v4.30 — Editorial Community Curation
Communities discovery gets a human hand: an admin can now place a community into a named rail without a deploy, and
is_featured— a badge nobody could ever set — finally has a write path.
Summary
Discovery on the Communities tab was entirely algorithmic — community_suggestions, trending_communities, recommended_communities — and nobody, including Josh, could place a community anywhere without shipping code. v4.30 adds an admin-gated editorial slot system: three named rails (active_now, just_started, most_members) with ordinal position within each, an admin screen at /communities/curation to assign them, and the consumer rails that render them on the Communities tab, behind PostHog flag editorial-discovery (registered, deliberately not promoted). It also closes a live, unrelated defect it found along the way: CommunityCardV2.vue had been rendering an is_featured "Featured" badge with no mutation, admin UI, or service anywhere in the codebase able to set it — Phase 2's screen is that flag's first-ever write path.
The work is a salvage, not a greenfield build. Phase 79 of the abandoned gsd/v1.18-pre-launch-readiness branch built almost exactly this and never shipped — the branch was abandoned as a whole, but this slice was only partially superseded when master took the algorithmic half. What was preserved — a migration, a validated model constant, a complete interaction, a mutation, an admin view, two Vue components, a composable, and six spec files — was a strong starting point but not a drop-in: six distinct ways the preserved code had drifted out of sync with master were found and designed around across kickoff and all three phases, the highest-severity one being a preserved diff that would have silently deleted master's live recommended_communities resolver as part of unrelated, out-of-scope work.
The milestone shipped clean on every phase, but not without two of its own planning gaps (not preserved-code drift) surfacing mid-flight: Phase 2 was originally scoped without a backend write path for is_featured even though keeping that flag (Josh's kickoff call) made a write path load-bearing for Phase 2's own acceptance criteria, and Phase 1's admin resolver filtered out exactly the sub-threshold rows Phase 2's own warning criterion needed to see. Both were caught and closed before shipping. So was the milestone's own closing sequencing: an initial dispatch would have written the shipped-narrative before the integration branch was promoted to master — the exact stranded-branch failure this milestone's own source material suffered — caught by the close ritual's own gate before anything was written.
Goal
Give Objectuve a human hand on the Communities discovery surface. Today discovery is entirely algorithmic —
community_suggestions,trending_communities,recommended_communities— and nobody, including Josh, can place a community anywhere without a deploy. This milestone ships an admin-gated editorial slot system (three named rails, ordinal position within each), an admin screen to assign slots, and the consumer rails that render them, behind a flag.
Scope — What Shipped
- Data model.
communitiesgainededitorial_slot,editorial_position,editorial_updated_at(nullable, indexed, additive migration — no backfill, reverses cleanly).Community::EDITORIAL_SLOTSfixes the three valid slot names;editorial_slotvalidates against it with nil permitted. - Admin write path.
Admin::SetCommunityEditorialSlot— admin-gated, wraps the write inAdmin::Loggedfor a full audit trail, evicts the prior occupant of an assigned slot+position inside a transaction, and clears all three columns onslot: nil.Admin::SetCommunityFeaturedmirrors the same shape foris_featured, kept deliberately independent (Option A) rather than folded into the slot mutation. - Admin curation screen.
CommunityCurationView.vueat/communities/curation, reachable from the admin sidebar and role-gated tosuper_admin/admin. Per-row staged edit → save with unsaved/saving/saved/error states, an inline warning on sub-threshold rows holding a slot, eviction feedback naming both communities, and theis_featuredtoggle. - Consumer discovery rails.
EditorialCarousel.vue(three editorial rails) andFoundingMemberOpportunitiesSection.vue(an algorithmic "founding spots open" rail, 0–4 members) render on the Communities tab behindeditorial-discovery. Flag off rendersCommunities.vuebyte-identical to before this milestone, asserted in a test — that assertion is the rollback guarantee. curatable_communitiesadmin query, widened mid-milestone to include any community already holding a slot even below the 5-member discoverability floor, closing an orphan hole where a slotted community that dropped below the floor would otherwise become invisible and unclearable at the same time.- Docs, across the admin guide, feature inventory, communities deep-dive, feature-flags registry, and CHANGELOG — every claim traceable to a named source file.
- What did not ship: a "See all →" destination for either rail (both preserved components emit the event; no target route exists — deliberately deferred to a follow-up rather than shipping a dead control).
Phases
| Phase | Name | Status | Plans | Highlights |
|---|---|---|---|---|
| 1 | Editorial data model, admin write path, read queries | Shipped | 2 | Migration, model, SetCommunityEditorialSlot, editorialCommunities/formingCommunities/curatableCommunities resolvers; existing recommendation specs passed unmodified, proving the port stayed additive (PR #2130, a19caae8b) |
| 2 | Admin curation screen | Shipped | 2 | CommunityCurationView.vue + sidebar entry + Admin::SetCommunityFeatured (scope expanded mid-milestone, Josh's Option A) + orphan-slot resolver fix (PR #2159, 5811bbaa0) |
| 3 | Consumer editorial discovery surface | Shipped | 2 | Four rails on the Communities tab behind editorial-discovery, flag-off byte-identical guarantee, useFeatureFlag-based composable, docs (PR #2143, 6d38eddb0) — executed ahead of Phase 2 while Phase 2 was held on a scope decision |
Key Decisions
is_featuredstays orthogonal toeditorial_slot, not consolidated. Josh's kickoff call:is_featuredis a per-card badge,editorial_slotis rail placement — different concepts, no migration to merge them. Phase 2's screen becomesis_featured's first write path via its own mutation,Admin::SetCommunityFeatured, rather than folding it intoSetCommunityEditorialSlot.- "Founding spots open" is in scope, algorithmic, not editorial.
FoundingMemberOpportunitiesSectioncomputes from member count alone (0–4, newest first, excluding the caller's own communities) — no admin assignment needed. Included because the source issue named it explicitly; also the cleanest thing to cut if the milestone had needed trimming. - "See all →" omitted in v1. Both preserved components emit a
see-allevent with no destination — the shelved branch never built the target route. Shipping a dead control was rejected; a real "all editorial communities" page is a follow-up issue, not this milestone. - The preserved branch's
community_queries.rbdiff was ported additively, not wholesale. The shelved branch had removedrecommended_communitiesas part of an unrelated, out-of-scope ally-gating rework. Porting the diff as-is would have silently deleted a livemastersurface; Phase 1 ported onlyeditorial_communities/forming_communitiesand Roy independently verifiedrecommended_communities/community_suggestions/trending_communitiesstayed byte-identical to base. - Milestone close held on master containment, not just phase completion. The integration branch sat unpromoted for roughly two hours after all three phases shipped. A close dispatch that would have written the shipped-narrative first was caught and corrected before any doc landed — the promotion (a separate, hand-created issue, per this repo's own documented stranded-branch pattern) ran to completion first.
Requirements Coverage
14 / 14 requirements satisfied — no standalone REQUIREMENTS.md; the milestone's own ROADMAP requirements table is the traceability surface, independently re-verified against live master source in the MILESTONE-AUDIT.md.
| Category | Count | Status |
|---|---|---|
| DATA-1–3 | 3 | All satisfied |
| ADMIN-1–7 | 7 | All satisfied |
| DISCOVER-1–3 | 3 | All satisfied |
| DOCS-1 | 1 | Satisfied (closed a mid-flight docs-inversion window before promotion — see Tech Debt) |
Outcomes
- An admin can place a community into a named discovery rail — or clear one — from
/communities/curation, without a deploy. is_featuredfinally has a write path; the badgeCommunityCardV2.vuehad rendered for an unknown span of time is no longer a dead flag.- The Communities tab renders four new rails when
editorial-discoveryis enabled for a user, and is byte-identical to before this milestone when it isn't — flipping the flag off in PostHog is a full, instant rollback with no deploy. - A community that drops below the 5-member discoverability floor after being slotted stays visible and clearable in the admin list rather than becoming an invisible, unclearable orphan.
master's existing algorithmic recommendation surface (recommended_communities,community_suggestions,trending_communities) is provably untouched.
Tech Debt
- (Process, cross-milestone pattern) A phase's own docs sub-task, deferred to run after the phase's code merges, is the task most likely to be silently dropped by a stage-rollup signal. This milestone's Phase 2 docs task (OBJ-2239) landed after Phase 2's code merged; in the window between, the shipped docs briefly asserted the curation screen didn't exist. Caught and closed before promotion — no live drift on
master— but this is the second time this repo has seen this exact shape. No mechanical guard exists yet. - (Evidence gap, disclosed at review time) No light+dark screenshot evidence exists for PR #2159 (Phase 2).
admin_dashboard/had no PR-time evidence-capture path when the PR opened; the infra fix landed onmasterafterward, too late for this branch. Reviewer substituted source/token-level UI-SPEC verification instead. Recorded as a disclosed gap, not a clean pass. - (Scope, deliberate) "See all →" has no destination route for either editorial rail — correctly scoped out at kickoff. A future "all editorial communities" page is a follow-up issue.
Related Artifacts
- Roadmap: v4.30-editorial-community-curation-ROADMAP.md
- Milestone Audit: v4.30-editorial-community-curation-MILESTONE-AUDIT.md
- Source issue: OBJ-2166 — salvage of Phase 79 from
gsd/v1.18-pre-launch-readiness - Spec input: tag
shelved/v1.18-pre-launch-readiness@eb36ce168 - Coordination anchor: OBJ-2188
- Phase issues: OBJ-2189 (Phase 1), OBJ-2190 (Phase 2), OBJ-2191 (Phase 3)
- Docs task: OBJ-2239 (Task 2-4)
- Promotion issue: OBJ-2268
- Merge PR: #2170 — master promotion
Related Commits
a19caae8b— Phase 1: editorial data model, admin write path, read queries (PR #2130)6d38eddb0— Phase 3: consumer editorial discovery surface (PR #2143)5811bbaa0— Phase 2: admin curation screen +is_featuredwrite path (PR #2159)28b35f7de— Merge v4.30 editorial community curation to master (PR #2170)
Last updated: 2026-08-07