ADR-026: Reactive campaign arcs — decision-driven narrative and scenario selection¶
Status: Accepted (implemented Apr 2026; what this ADR calls "reactive arcs" was renamed to "Campaigns" per ADR-035)
Date: 2026-04-15
Context: Current campaign arcs are structurally linear: chapters have pre-authored preambles, scenarios are selected by category/difficulty filters and info-gain scoring, and the only branching mechanism is a single pre-defined fork point per arc. The narrative history (narrative_history) feeds into preamble generation, but preambles are pre-cached on first generation and reused across all playthroughs of the same arc. Players' specific decisions don't meaningfully alter what comes next — the story mentions what happened but the world doesn't change because of it.
Comparison with Pax Historia (an AI-driven grand strategy game with 35K DAU) identified the core engagement gap: in Pax, every decision visibly reshapes what comes next. Players report the game as addictive specifically because the AI world reacts to their specific choices with memory and personality. Sync's campaign arcs currently lack this quality — narrative framing is atmospheric but not reactive.
The challenge is adding reactivity without compromising Sync's primary purpose: behavioral measurement. The profile engine, DTA prediction system, and judgment layer signals depend on scenarios being fair measurement instruments, not narrative set pieces designed to continue a story. Players who optimize for "what makes the best story?" rather than "what would I actually do?" produce contaminated signal.
At a glance
What it decides: A "reactive" arc type generates preambles and consequences live from the player's actual decisions, with scenario selection softly biased by prior choices — while the measurement instrument (scenarios, options, DTA, sync score) stays completely untouched. Static arcs are unaffected.
- Consequence is its own beat after results, a 2–3 block screen shows what the player's specific choice caused; kept separate from the next preamble so the reactivity is visible, not folded into "slightly better preambles."
- Reactivity lives in the framing layer only preambles, consequences, and a 0.15 thematic-adjacency selection weight — never sync score, DTA, or the 12 signals (ADR-024), preserving clean behavioral data.
- Selection is influenced, not forced thematic adjacency only breaks ties; info-gain scheduling still wins when calibration needs a specific scenario.
- Final chapter ends in a coda a 4–6 block epilogue replaces the consequence, weaving the full arc of decisions together.
- Watch: prompt quality is the highest-risk element and the reason for a single-arc pilot (~$0.30 extra per reactive campaign vs $0 for static); renamed to "Campaigns" per ADR-035.
flowchart LR
A["Live preamble (world after prior consequence)"] --> B["Info-gain scenario selection"]
B --> C["Decision + results (DTA, sync score, signals)"]
C --> D["Consequence screen: what your choice caused"]
D --> E["Thematic adjacency tags (soft weight)"]
E -->|"next chapter"| A
D -->|"final chapter"| F["Coda: full-arc epilogue"]
Reactive-arc loop: decision drives the consequence and the soft tags that bias next-chapter selection; the final chapter ends in a coda instead.
Decision¶
Introduce a new arc type — reactive arcs — where preambles and consequences are generated live based on the player's actual decisions, and scenario selection is influenced (but not determined) by prior choices. Static arcs continue working unchanged.
A reactive arc has two distinct narrative beats per chapter: - Consequence (after the decision): "Here's what your choice just caused." Immediate, specific to the option the player selected. 2-3 blocks. Shown as a new step after the results screen. - Preamble (before the next decision): "Here's the world you're walking into now." Atmospheric, forward-looking, references the prior consequence but doesn't repeat it. Sets up the next chapter's context.
These are separate because the consequence needs to be a distinct, noticeable experience — the moment where the game visibly reacts to the player's specific choice. Folding it into the preamble would make it invisible; the player would just experience "slightly better preambles" without recognizing the new mechanic.
How a reactive arc flows¶
Chapter 1:
1. Live-generated preamble (world-building, no pre-cache). The arc provides a narrative voice prompt and a seed premise, but no preamble_blocks or rigid chapter_intro.
2. Scenario selected by the existing info-gain scheduler, filtered by chapter category/difficulty constraints. Same as static arcs.
3. Player makes their decision. Sync score, DTA prediction, and all behavioral signals fire normally.
4. Consequence screen. After results, the player sees a new screen with 2-3 narrative blocks showing what happened because of their specific choice. Rendered with the same typewriter effect as preambles. The consequence is stored in narrative_history with the chosen option label.
Chapter 2+:
1. Live-generated preamble that builds on the accumulating narrative_history. The preamble knows about the prior consequence but doesn't restate it — it shows the world after the consequence has settled. The player is walking into a changed environment, not re-reading what changed.
2. Decision-influenced scenario selection. The scenario selector receives thematic adjacency tags derived from the prior chapter's outcome. This biases (not forces) selection toward scenarios that feel like natural follow-ups.
3. Scenario, decision, results — same as Chapter 1.
4. Consequence screen — same as Chapter 1, but now building on accumulated narrative history. NPCs and settings from prior consequences may recur.
Chapter 5 (final): Same flow for the scenario itself. After results, instead of a consequence, a coda is generated — a longer (4-6 block) narrative epilogue that weaves together the full arc of decisions across all 5 chapters. This replaces the current campaign completion screen's journey summary with something narrative: a scene that shows where the world landed because of the specific path this player carved through it.
What stays the same for profiling¶
- Sync score calculation is unchanged — no stakes multiplier, no arc-type weighting
- The DTA still predicts and learns from every decision
- All 12 behavioral signals (ADR-024) still fire: reaction buttons, decision strength, timing, self-awareness, persuadability, etc.
- Scenarios are still real scenarios from the library, selected by info-gain scoring — the measurement instrument is not compromised
Schema changes¶
-- New column on campaign_arcs
ALTER TABLE campaign_arcs ADD COLUMN arc_type text NOT NULL DEFAULT 'static'
CHECK (arc_type IN ('static', 'reactive'));
COMMENT ON COLUMN campaign_arcs.arc_type IS
'static = pre-authored preambles and fixed chapter intros. reactive = live-generated preambles and consequences based on player decisions.';
The narrative_history JSONB array on campaigns already stores per-chapter entries. For reactive arcs, each entry gains:
- chosen_option: the specific option label the player selected
- consequence_blocks: the NarrativeBlock[] generated for the consequence screen
- The existing outcome_summary field carries a richer text summary including the choice
No new tables or columns beyond arc_type. The narrative_history JSONB structure is flexible enough.
Consequence generation¶
New endpoint: POST /api/campaigns/[id]/consequence
Called after the round completes. Inputs:
- The scenario just played (title, description, options)
- The player's specific chosen option (label + description)
- The arc's narrative voice prompt
- The campaign's narrative_history (all prior chapters)
- The current phase
New function in campaign-narrator.ts: generateConsequence(). The prompt enforces:
- Show, don't tell. A specific scene, not "your decision led to positive outcomes."
- Neutral tone. No "you made the right/wrong call." The consequence is what happened, not a judgment. All options should lead to complex, interesting outcomes.
- Specificity. Name what changed. A person affected, a policy enacted, a door closed. The player should be able to point to the thing their choice caused.
- Continuity. Reference NPCs and settings from prior preambles/consequences. The world must feel persistent — same people, changed circumstances.
- Brevity. 2-3 blocks only. This is a beat, not a scene. The preamble does the scene-setting.
Output: 2-3 NarrativeBlock[] stored in narrative_history as consequence_blocks.
Preamble route changes¶
The existing preamble route (/api/campaigns/[id]/preamble) checks for pre-cached preamble_blocks first. For reactive arcs:
- Skip the chapter-level cache (chapter.preamble_blocks) — every playthrough generates fresh
- Still use campaign-level narrative_history cache for the current chapter's preamble (so reloading the page doesn't regenerate)
- Always generate with full narrative_history context, including consequence blocks and chosen options from prior chapters
- The preamble prompt is enhanced: for Chapter 2+, it knows about the prior consequence but is instructed NOT to restate it — instead, show the world after the consequence has settled
Preamble prompt changes for reactive arcs¶
The existing preamble prompt (buildPreamblePrompt in campaign-narrator.ts) already handles Chapter 2+ with prior narrative context. For reactive arcs, the prompt gains additional instructions:
- Don't restate the consequence. The player already saw it. Open with the world after — changed, but settled. "The press conference footage is still circulating" not "After you chose to disclose..."
- Continuity across chapters. NPCs introduced in prior preambles and consequences should recur. The world must feel persistent.
- Forward momentum. The preamble's job is to set up the next decision, not dwell on the last one. 1-2 blocks of consequence aftermath, then transition to the new chapter's context.
Coda generation (Chapter 5 epilogue)¶
New function in campaign-narrator.ts: generateCoda(). Called after the final chapter's round completes (replaces the consequence for Chapter 5). Inputs:
- Full narrative_history (all 5 chapters' outcomes, chosen options, and consequence blocks)
- The arc's narrative voice prompt
- Theme
Output: 4-6 NarrativeBlock[] rendered on the campaign completion screen with the same typewriter effect as preambles. The coda is a scene — not a summary — that shows where the world landed. It should reference specific decisions from across the arc, showing their cumulative effect. Characters from the full arc may appear. The tone matches the arc's narrative voice.
Decision-influenced scenario selection¶
The scenario selector currently scores by: category novelty (0.30), trigger novelty (0.25), freshness (0.25), difficulty (0.20). For reactive arcs, add a fifth factor:
- Thematic adjacency (0.15): After consequence generation, the API also returns 2-3 suggested scenario tags/categories that would feel like natural follow-ups. These become soft-weight preferences in the scoring function. The other four factors are re-weighted proportionally (0.26, 0.22, 0.22, 0.15).
This is a suggestion, not a constraint. If the info-gain scheduler says "this player needs more ethical-dilemma scenarios for calibration," that still wins. The thematic adjacency just breaks ties in a narratively coherent direction.
Solo UX: the consequence screen¶
After the existing results screen (AI prediction → DTA reasoning → sync score → What Your Twin Learned), a "Continue" button transitions to:
Consequence screen:
- Full-screen narrative display, same visual treatment as preambles (dark background, typewriter effect)
- 2-3 blocks showing what the player's choice caused
- Step indicator: two stretched bars at the top (matching multiplayer's existing flex-1 h-2 rounded-full pattern) — "Results" and "What Happened"
- "Continue" → back to campaign page
For none-of-above decisions: generate the consequence based on the player's none_closest_option_id.
Multiplayer UX (future — not in pilot)¶
When reactive arcs extend to multiplayer, each player sees the consequence for their specific option on the results screen. Consequences are public — all players can see what happened for each person's choice.
Test mode¶
For evaluating the reactive arc without contaminating player profiles:
- Query parameter:
?testMode=trueon the solo game flow - When active:
- Skips DTA prediction (no inference cost)
- Skips sync score update (no profile contamination)
- Skips writing to
scenario_play_log(no recency pollution) - Still generates live preambles, consequences, and coda (the things being tested)
- Still shows the full UI flow for evaluation
- Campaign can be deleted after testing — no artifacts remain
Cost estimate¶
| Generation | Cost per call | Calls per chapter | Per 5-chapter arc |
|---|---|---|---|
| Live preamble | ~$0.02-0.03 | 1 | ~$0.12 |
| Consequence | ~$0.02-0.03 | 1 | ~$0.12 |
| Thematic tag suggestion | ~$0.005 | 1 (bundled with consequence) | ~$0.02 |
| Coda (final chapter only) | ~$0.03-0.04 | 1 total | ~$0.04 |
| Total incremental | ~$0.30 |
Static arcs: $0 incremental (pre-cached preambles, no consequences, no coda).
Rationale¶
- Reactivity is the engagement lever. Pax Historia's stickiness comes from the world responding to your specific choices. Adding this to Sync's campaigns makes the solo experience — the hardest to make engaging and the best source of clean behavioral data — significantly more compelling.
- Consequence as a distinct step, not folded into preambles. During discussion, we identified that folding consequences into the next chapter's preamble would make the new mechanic invisible — it would feel like "slightly better preambles" rather than a distinct reactive experience. The consequence needs to be a noticeable new beat: the moment where the game visibly responds to the player's specific choice. The preamble then builds on it without restating it.
- Measurement integrity is preserved. Scenarios are still selected by the info-gain scheduler. The reactive elements (preambles, consequences) are framing, not measurement. The player still sees real scenarios with real options; the DTA still predicts; the sync score still reflects prediction accuracy. The framing just makes the experience feel alive.
- The prompt quality concern is real and addressed by piloting. Both the consequence prompt and the reactive preamble prompt need to produce excellent, neutral narrative regardless of which option was chosen or which scenario was played. This is a prompt engineering challenge, not an architectural one. Building one reactive arc first lets us iterate on prompt quality before scaling.
- "Would you change your mind" is deferred. The signal value for DTA training is marginal — the DTA learns from what you choose, not how you feel about it afterward. It's a potential judgment layer signal (persuadability, self-awareness) but not critical for the pilot. Can be layered on later as an optional prompt on the consequence screen.
Alternatives Considered¶
- Preamble-only reactivity (no separate consequence step): Cleaner flow, fewer API calls, but makes the new mechanic invisible. The player experiences better preambles but can't point to the moment where the game reacted to them. Rejected because the pilot's purpose is to evaluate whether visible reactivity is engaging — can't evaluate what you can't see.
- Separate consequence step + "would you change your mind" prompt: Adds a reflection mechanic on top of the consequence. More signal, but adds UI complexity and the signal value for DTA training is marginal. Deferred — can be layered on the consequence screen later if the reactive arc itself proves engaging.
- Pre-authored consequences (4 per scenario): Lower latency, no API cost, but loses the reactivity that makes this worth doing. Pre-authored consequences can't reference prior chapters, NPCs, or the evolving world.
- Full dynamic scenario generation (not just selection): Generate entirely new scenarios on the fly based on the story. Maximum reactivity, but destroys measurement integrity — AI-generated scenarios haven't been validated, difficulty-calibrated, or checked for leading language. The scenarios must come from the vetted library.
- Every arc becomes reactive: Premature. The prompt engineering needs to be proven on one arc before scaling. Static arcs are reliable and low-cost. Reactive arcs are an opt-in experience.
Discussion¶
The core tension is between narrative engagement and behavioral measurement. Sync's value comes from the profile engine — the DTA, sync score, and judgment layer signals. Anything that makes players think "what makes the best story?" instead of "what would I actually do?" degrades that value.
The design resolves this by keeping the measurement instrument (scenarios, options, DTA prediction) completely untouched and adding reactivity only to the framing layer (preambles, consequences, scenario selection weighting). The player's decision is still their decision; the world just responds to it more visibly.
The consequence-as-separate-step decision went through two iterations. Initially, we proposed folding consequences into the next chapter's preamble ("the preamble IS the consequence"). On reflection, this was rejected: if the reactive mechanic is invisible to the player, there's nothing to evaluate in the pilot. The consequence needs to be a distinct beat — a moment where the player clearly sees "the game just responded to what I chose." The preamble then builds on that foundation without restating it. Two jobs, two moments, no redundancy.
The prompt quality concern is the highest-risk element. Both the consequence prompt (must produce compelling, neutral, specific narrative for any option of any scenario) and the reactive preamble prompt (must build on consequence history without restating it) need careful engineering. This is why the proposal starts with a single pilot arc — the prompts need iteration before this pattern can scale.
The "would you change your mind" mechanic was considered and deferred. For DTA prediction training, the signal is marginal — the DTA learns from choices, not retrospective feelings about choices. It has potential value as a judgment layer signal (persuadability, self-awareness) but adds complexity to a pilot that should focus on validating whether reactive narrative works at all. The consequence screen provides a natural hook to add this later.
Candidate themes for the pilot arc: Boardroom (strongest for profiling, most grounded), Frontier (more narrative range), or Rebuild/Post-apocalyptic (high stakes, strong consequence visibility). The pilot will use one theme; if successful, reactive arcs can be created for others.
Consequences¶
- One new arc type (
reactive) coexists with existingstaticarcs - New consequence generation endpoint and narrator function
- The preamble route gains arc-type-aware caching behavior (skip chapter cache for reactive)
- The preamble prompt gains instructions to build on consequences without restating them
- The scenario selector gains a soft thematic-adjacency factor (0.15 weight) for reactive arcs
- Solo flow gains a consequence screen after results (step indicator: "Results" → "What Happened")
- A new
generateCoda()function produces narrative epilogues for completed reactive campaigns - Test mode (
?testMode=true) enables evaluation without profile contamination - Prompt engineering becomes a critical ongoing concern — consequence and preamble prompts need to be robust across all scenario types, option choices, and narrative phases
- Cost per reactive campaign is ~$0.30 higher than static
- Static arcs are completely unaffected — no changes to existing campaigns
Key files:
- src/lib/ai/campaign-narrator.ts — new generateConsequence() and generateCoda() functions, enhanced preamble prompt for reactive arcs, thematic tag extraction
- src/app/api/campaigns/[id]/preamble/route.ts — arc-type-aware cache bypass, richer narrative_history entries
- src/app/api/campaigns/[id]/consequence/route.ts — new endpoint (to be created)
- src/lib/game/campaign-scenario-selector.ts — add thematic adjacency scoring factor
- src/app/solo/page.tsx — consequence screen after results, test mode flag (skip DTA, sync score, play log), step indicator
- src/app/(app)/campaigns/[id]/page.tsx — coda display on completion screen
Pilot scope: - One reactive arc, solo only, one theme (Boardroom, Frontier, or Rebuild) - 5 chapters with seed premise and narrative voice — no pre-authored preambles or chapter intros - Consequence screen after each round with live-generated narrative - Coda epilogue after the final chapter - Test mode for speed-running without profile impact - Iterate on consequence + preamble prompt quality until output is consistently compelling and neutral - Evaluate with the team before broader rollout or multiplayer support