Ship 2C: replaces the single rotating NamedBetrayalBeat (cream block,
one-card-per-week pattern) with a horizontal-scroll dark section showing
all 5 constitutional refusals at once with the chain rendered inline.
src/shared/movement/queries.ts:
- getFeatureChain(featureId) — single-feature joiner across feature_wishes
→ wishes → users (display name) and feature_adrs → adrs (locked-by ADR
number, slug, effect)
- getFeatureChains(featureIds) — bulk variant; one query per join type;
used to render N cards without N round trips
- listRefusalsWithChains(productScope, limit) — composite query: refusal
Features ordered by importance (core first), each with its chain
- Reaction count: distinct "want_this" reactions across all linked wishes
src/marketing/components/refusal-cards-strip.tsx:
- Renders the listRefusalsWithChains result as a horizontal-scroll strip
inside a dark section. Each card has:
- Top: tiny scope label, giant NO. + title remainder (parsed from
"No " titles), serif oneLiner
- Middle: cited contrast in two columns (incumbent admission ←→ our
behavior). Currently shows a placeholder for "their way" until the
operator publishes the linked Comparison; ourBehaviorMd renders from
feature.refusedNote on day one.
- Bottom: chain narration — "Wished by · N voted yes · refused
by ADR 0014" — each name and ADR a link. When the chain is empty
(no wishes, no ADRs yet), falls back to "Constitutionally seeded ·
commitment 06" — honest forward-looking copy.
- Uses the primitive from Phase 2A
- Hides if no refusal Features exist
Ship 2D: adds an AI agent reasoning panel that cycles through recent AI
commits' Reasoning trailers with typewriter animation.
src/shared/movement/ai-build-queries.ts:
- getRecentAiBuildEntries(limit) — recent public AI commits with non-null
reasoningMd. Excerpts the first paragraph of reasoning (~600 chars)
for the typewriter; full reasoning is available on /build-log/.
src/marketing/components/ai-terminal.tsx (client):
- Stylized terminal window cycling through AI commit reasoning excerpts
- Typewriter animation at 16ms/char on the current excerpt; pauses 2.4s
between entries; loops infinitely
- Hover pauses the animation so the visitor can read
- Mac-style window chrome, AI badges in emerald, blinking cursor
- Respects prefers-reduced-motion (renders excerpts statically)
src/marketing/components/live-build-panel.tsx (server):
- Section wrapper with "Watch the AI build." headline + total AI commit
count chip + the AiTerminal + "Browse every commit" + "Daily wrap-ups"
links
- Hides if no AI commits with reasoning exist yet
Homepage layout (after this commit):
- Hero (cream, two-column, terminal on right)
- RecentShipsStrip (dark, horizontal scroll of featured commits)
- ProductsStrip (cream, horizontal scroll of 4 products)
- RefusalCardsStrip (dark, horizontal scroll of 5 NO. cards with chain) ← new
- LiveBuildPanel (cream, AI reasoning typewriter) ← new
- RealHumanWrapper (hidden if no patron)
- OfferWrapper (cream → dark inside, the offer)
- Inversion (cream, 0% / 90%)
- Proof (cream, YouTube/Substack/etc.)
- Commitments (dark, with gloss)
- PatronSection (cream, hidden if no reservations)
- SignCtaSection (cream)
- FounderSignature (cream)
- Subscribe (cream)
NamedBetrayalBeat removed from homepage (still exists as a component if
needed elsewhere). FeaturedRefusalSection wrapper removed.