# E7.M1 — QuestStateMachine ## Summary | Field | Value | |--------|--------| | **Module ID** | E7.M1 | | **Epic** | [Epic 7 — Quest / Faction](../epics/epic_07_quest_faction.md) | | **Stage target** | Prototype | | **Status** | Planned — Slice 1 backlog [E7M1-prototype-backlog.md](../../plans/E7M1-prototype-backlog.md): **E7M1-01** [NEO-112](https://linear.app/neon-sprawl/issue/NEO-112) catalog **landed** (schemas + CI); **E7M1-02** [NEO-113](https://linear.app/neon-sprawl/issue/NEO-113) server load **landed**; **E7M1-03** [NEO-114](https://linear.app/neon-sprawl/issue/NEO-114) registry **landed**; **E7M1-04** [NEO-115](https://linear.app/neon-sprawl/issue/NEO-115) HTTP read **landed**; **E7M1-05** [NEO-116](https://linear.app/neon-sprawl/issue/NEO-116) player quest state store **landed**; **E7M1-06** [NEO-117](https://linear.app/neon-sprawl/issue/NEO-117) **`QuestStateOperations`** **landed**; objective wiring from **E7M1-07** [NEO-118](https://linear.app/neon-sprawl/issue/NEO-118) → capstone **E7M1-12** [NEO-123](https://linear.app/neon-sprawl/issue/NEO-123) | | **Linear** | Label **`E7.M1`** · [E7M1-prototype-backlog.md](../../plans/E7M1-prototype-backlog.md) | ## Purpose Data-driven quest lifecycle: start, step progression, branching, failure/reset, and completion with durable persistence. Integrates crafting and combat outcomes so guided content ties together gather–craft–combat loops without duplicate rewards. **Scope / party:** [Per-character state by default](quest_scope_and_party.md#persistence-per-character-by-default); optional [party credit and turn-in rules](quest_scope_and_party.md#quest-modes-content-driven) via `QuestDef` and [E8.M1](E8_M1_PartyAndMatchAssembly.md). ## Responsibilities - Load and interpret `QuestDef`; track `QuestStepState` **per character**; synchronize party-credit advances per [quest_scope_and_party.md](quest_scope_and_party.md). - Apply `QuestStateTransition` rules for advance, abandon, fail, and complete. - Invoke or subscribe to [E3.M2](E3_M2_RefinementAndRecipeExecution.md) and [E5.M1](E5_M1_CombatRulesEngine.md) (or their events) for step completion predicates. ## Key contracts | Contract | Role | |----------|------| | `QuestDef` | Steps, prerequisites, objectives, and branching metadata. | | `QuestStepState` | Current step progress and internal flags. | | `QuestStateTransition` | Valid transitions and side effects (before E7.M2 reward routing). | ## Module dependencies - **E3.M2** — RefinementAndRecipeExecution: craft completion, item hand-ins, refine steps. - **E5.M1** — CombatRulesEngine: defeat objectives, encounter-linked steps. ## Dependents (by design) - **E7.M2** — [RewardAndUnlockRouter](E7_M2_RewardAndUnlockRouter.md): idempotent delivery after completion. - **E7.M3** — [FactionReputationLedger](E7_M3_FactionReputationLedger.md): reputation-gated content (pre-production). - **E5.M3** — [EncounterAndRewardTables](E5_M3_EncounterAndRewardTables.md): encounter completion and quest credit. - **E6.M4** — [RewardParityEnforcer](E6_M4_RewardParityEnforcer.md): quest/PvP reward alignment. ## Related implementation slices See Epic 7 **Slice 1 — Quest core and persistence**: 3–5 onboarding quests plus one chain across gather/craft/combat; telemetry `quest_start`, `quest_step_complete`, `quest_complete`, funnel times. ## Linear backlog (decomposed) Full story tables, kickoff defaults, and **`blockedBy` graph:** [E7M1-prototype-backlog.md](../../plans/E7M1-prototype-backlog.md). | Slug | Linear | |------|--------| | E7M1-01 | [NEO-112](https://linear.app/neon-sprawl/issue/NEO-112) | | E7M1-02 | [NEO-113](https://linear.app/neon-sprawl/issue/NEO-113) | | E7M1-03 | [NEO-114](https://linear.app/neon-sprawl/issue/NEO-114) | | E7M1-04 | [NEO-115](https://linear.app/neon-sprawl/issue/NEO-115) | | E7M1-05 | [NEO-116](https://linear.app/neon-sprawl/issue/NEO-116) | | E7M1-06 | [NEO-117](https://linear.app/neon-sprawl/issue/NEO-117) | | E7M1-07 | [NEO-118](https://linear.app/neon-sprawl/issue/NEO-118) | | E7M1-08 | [NEO-119](https://linear.app/neon-sprawl/issue/NEO-119) | | E7M1-09 | [NEO-120](https://linear.app/neon-sprawl/issue/NEO-120) | | E7M1-10 | [NEO-121](https://linear.app/neon-sprawl/issue/NEO-121) | | E7M1-11 | [NEO-122](https://linear.app/neon-sprawl/issue/NEO-122) | | E7M1-12 | [NEO-123](https://linear.app/neon-sprawl/issue/NEO-123) | ## Prototype Slice 1 freeze (E7M1-01) The **first shipped quest spine** is **frozen** for prototype tuning until a deliberate migration issue expands the roster. | `QuestDef.id` | `displayName` | `prerequisiteQuestIds` | Steps (summary) | |---------------|---------------|------------------------|-----------------| | **`prototype_quest_gather_intro`** | Intro: Salvage Run | *(none)* | 1× **`gather_item`**: **`scrap_metal_bulk` ×3** | | **`prototype_quest_refine_intro`** | Intro: Refine Stock | **`prototype_quest_gather_intro`** | 1× **`craft_recipe`**: **`refine_scrap_standard`** ×1 | | **`prototype_quest_combat_intro`** | Intro: Clear the Pocket | *(none)* | 1× **`encounter_complete`**: **`prototype_combat_pocket`** | | **`prototype_quest_operator_chain`** | Operator Chain | **`prototype_quest_gather_intro`**, **`prototype_quest_refine_intro`**, **`prototype_quest_combat_intro`** | 4 steps: gather **`scrap_metal_bulk` ×5** → craft **`refine_scrap_standard`** → craft **`make_field_stim_mk0`** → **`inventory_has_item`** **`contract_handoff_token` ×1** | **CI enforcement (NEO-112):** `scripts/validate_content.py` requires **exactly** these four quest ids; objective cross-refs to frozen item/recipe/encounter catalogs; acyclic **`prerequisiteQuestIds`**; chain quest terminal step uses **`contract_handoff_token`** from [E5.M3 encounter loot](E5_M3_EncounterAndRewardTables.md#prototype-slice-3-freeze-e5m3-01). **Server load (NEO-113):** Host fail-fast load of `content/quests/*_quests.json` with the same gates — [server README — Quest catalog](../../../server/README.md#quest-catalog-contentquests-neo-113). **HTTP read model (NEO-115):** **`GET /game/world/quest-definitions`** — `QuestDefinitionsWorldApi` + DTOs in `Game/Quests/` ([NEO-115](../../plans/NEO-115-implementation-plan.md)); [server README — Quest definitions (NEO-115)](../../../server/README.md#quest-definitions-neo-115); Bruno `bruno/neon-sprawl-server/quest-definitions/`. **Player quest state store (NEO-116):** **`IPlayerQuestStateStore`** — in-memory + Postgres (`V008__player_quest_progress.sql`) per-player rows keyed by `(playerId, questId)`; implicit `not_started` when missing ([NEO-116](../../plans/NEO-116-implementation-plan.md)); [server README — Quest progress store (NEO-116)](../../../server/README.md#quest-progress-store-neo-116). **Quest state operations (NEO-117):** **`QuestStateOperations`** — accept, step advance, complete with **`QuestStateReasonCodes`**; prerequisite gate on accept; idempotent complete at operations layer ([NEO-117](../../plans/NEO-117-implementation-plan.md)); [server README — Quest state operations (NEO-117)](../../../server/README.md#quest-state-operations-neo-117). HTTP read/accept deferred to E7M1-08/09; objective wiring in E7M1-07. **Reward policy (Slice 1):** Quest completion updates **`QuestStepState` only** — no duplicate item/XP grants. Gather/craft/encounter paths keep existing payouts; [E7.M2](E7_M2_RewardAndUnlockRouter.md) adds **`QuestRewardBundle`** apply in Slice 2. ## Risks and telemetry - Scripting weight: keep `QuestDef` data-first; templates in decomposition/tooling path per epic. - Double-claim: design for idempotency before E7.M2; lint bundles vs E6.M4 / E3.M5. ## Source anchors - Master plan: [`neon_sprawl_vision.plan.md`](../../../neon_sprawl_vision.plan.md) — Core Epic Map, Epic 7. - [Module dependency register](module_dependency_register.md)