Skip to content

ADR-040: Curated scenario packs

Status: Proposed Date: 2026-05-06 Context: Cici's twin redesign mocks include "Pack: Conflict & repair" — a curated 12-round bundle of thematically-related scenarios. No scenario_packs table or product flow exists today. This ADR scopes the feature: schema, curation source, the Stories/Campaigns/Packs distinction, progression rules, and discovery surface — so we can ship coherently rather than bolt it on.

At a glance

What it decides: introduce scenario packs — curated, themed bundles of N scenarios with no narrative through-line — as a third content primitive alongside Stories and Campaigns. Proposed, not yet built.

  • Core mechanism — themed bundle, any-order play. Completion earns a badge + small XP, but unlocks nothing; players go at their own pace.
  • Curation — AI nominates, human picks/orders. Hand-only doesn't scale; AI-only produces incoherent packs.
  • The three-way distinction is load-bearing. Story = narrative arc; Campaign = multi-session container; Pack = focused practice, no story.
  • Rejected — gating/linear progression. Conflicts with identity-vs-process ("play to be seen, not to perform"); gating breeds resentment.
  • The killer surface waits on B.4. Recommending packs by the user's weakest sync dimension is gated on the 5-dimensions ADR; until then, rank by recency.

Decision

Introduce scenario packs as a third content primitive, distinct from both Stories (narrative-arc-driven, e.g. The Brink) and Campaigns (multi-session containers). A pack is a thematic bundle of N scenarios with a curated order but no narrative through-line. Players work through a pack at their own pace; completion is recognized but doesn't gate anything.

Schema:

scenario_packs:
  id, name, description, theme, cover_image_url,
  ordered_scenario_ids (uuid[]),
  curator_id, status ('draft' | 'published'),
  recommended_for_dimension TEXT NULL,  -- ties into B.4 once shipped
  created_at, updated_at

scenario_pack_progress:
  user_id, pack_id, scenarios_completed (int),
  started_at, completed_at, last_played_at
  PRIMARY KEY (user_id, pack_id)

Curation source: AI-suggested, human-curated. The team (or a designated curator) picks/orders; the AI surfaces candidates. Hand-only doesn't scale; AI-only produces incoherent packs.

Progression: Any-order within the pack. Completion = badge + small XP bonus. Does not unlock anything else (resist the temptation; gating breeds resentment).

Discovery: Hub card surfaces 1–3 packs (ranked by relevance to the user's weakest sync dimension once B.4 ships; ranked by newness until then). Plus a /packs listing route.

Rationale

  • The thematic-bundle gap is real. Stories tell a single connected narrative. Campaigns are containers for multi-session play. Neither answers "give me 12 scenarios about conflict" — which is a valid user intent (skill-building in a domain, or just "I want to play but don't want a full campaign").
  • Hand-curated for the first 5–10, then AI-augmented. Sets the bar for what good packs look like before scaling.
  • No gating. Sync's identity-vs-process philosophy (per project_identity_vs_process) means we don't want users grinding packs to "level up" — that conflicts with the "play to be noticed, not to perform" frame. Completion as recognition only.
  • Recommended-by-weakest-dimension is the killer surface — once B.4 ships. "Train your weakest dimension at X/100 → Pack: Calibration drills" is the loop that makes Sync (Play) screen's recommendation engine real.

Alternatives Considered

  • Skip packs entirely; let users browse all scenarios. Rejected. Browsing 895 scenarios is paralysis. Curation is the value.
  • Make packs identical to short Stories. Rejected. Stories are narrative-driven (Dunia.gg-style preambles, character continuity, choice consequences across chapters). Packs deliberately don't have a narrative through-line — that's their value. Conflating them muddies both.
  • Dynamic packs generated on-the-fly per user. Rejected for v1. Personalized recommendation is the output of B.4 dimensions, not a separate pack mechanism. Static curated packs surface in personalized order; we don't need to invent dynamic packs.
  • Linear/gated progression within a pack. Rejected. Adds friction without clear benefit; users may want to skip a scenario that doesn't resonate, and forcing order makes packs feel like homework.
  • Completion unlocks new content. Rejected. Gating breeds resentment, and it conflicts with the "play to be seen, not to perform" framing.

Discussion

The clean line between Stories, Campaigns, and Packs is the load-bearing decision in this ADR. Without it, the team UX gets muddled and copywriters won't know what to call things.

  • Story = narrative arc (chapters, character continuity, decision consequences across chapters). Players experience a journey.
  • Campaign = container for multi-session play, possibly running a Story across multiple sittings. Players experience continuity over time.
  • Pack = thematic bundle, no narrative. Players experience focused practice in a theme.

A Story can live inside a Campaign. A Pack can't (Pack is its own container). All three live alongside one-off scenarios.

flowchart TB
    Campaign["Campaign<br/>(multi-session container)"]
    Story["Story<br/>(narrative arc)"]
    Pack["Pack<br/>(themed bundle, no story)"]
    OneOff["One-off scenario"]
    Campaign --> Story
    Story --> Scenarios["Scenarios (connected)"]
    Pack --> PackScenarios["Scenarios (curated order, no arc)"]

A Story can nest inside a Campaign; a Pack is its own container. All three coexist with one-off scenarios.

The curation-source decision (AI-suggested, human-curated) was the second key call. Hand-curated only doesn't scale past ~10 packs; AI-curated only produces incoherent bundles ("Conflict & repair" should not include scenarios about resource allocation just because they share keywords). The mix — AI nominates, human picks/orders — is how good music playlists get made and is the right pattern here too.

The decision not to gate completion was deliberate. The temptation is to use packs as the progression substrate (Pack 1 → Pack 2 → Pack 3). That conflicts with project_identity_vs_process — Sync measures how you decide, not what level you've reached. Packs are practice surfaces, not progression rails.

Open question deferred: when B.4 ships and packs become recommendable by weakest dimension, do we add a "Recovery" pack mechanic (per Cici's design — surfaces when you've drifted)? That's a follow-up; this ADR keeps recommendation passive (Hub surfaces relevant packs) rather than reactive (the system tells you to do a recovery pack).

Consequences

  • Two new tables: scenario_packs, scenario_pack_progress. Forward-compatible — existing scenarios continue to work outside packs.
  • Curation tooling needed: a small admin surface for the team to draft/publish packs and reorder scenarios. Not a full CMS — admin SQL editor + a draft preview view is enough for v1.
  • Hub surface becomes denser: pack cards alongside team cards alongside the existing entries. Cici's design will need to handle this in the Hub layout (probably already does — the design includes the pack mock).
  • Discovery route at /packs: lists all published packs filtered by theme. Mirrors the Stories/Campaigns browsers.
  • Recommended-by-dimension is gated on B.4. Until ADR for 5 sync dimensions lands, surfaces rank packs by recency. After B.4 lands, the recommendation pass also reads recommended_for_dimension and ranks accordingly.
  • Watch: completion rate. If <30% of started packs get finished, packs are too long (12 scenarios may be too much; consider 6–8). If >70% complete with no return visits, packs are too easy/disposable.

Key files (proposed): - migrations/0XX_scenario_packs.sql — schema - src/app/(app)/packs/page.tsx + [id]/page.tsx — discovery + detail routes - src/lib/packs/recommend.ts — pack ranking logic (thin until B.4) - src/app/api/packs/[id]/start/route.ts, complete/route.ts — progress writes - src/components/packs/PackCard.tsx — Hub surface