NEO-112: add E7M1 prototype backlog and decomposition cross-links
parent
be1dae3872
commit
140d857398
|
|
@ -46,14 +46,18 @@ Provide a quest state machine and reward routing that ties gathering, crafting,
|
|||
|
||||
## Implementation Slices (Backlog-Ready)
|
||||
|
||||
<a id="epic-7-slice-1"></a>
|
||||
|
||||
### Slice 1 - Quest core and persistence
|
||||
|
||||
- Scope: E7.M1 supporting branching steps and failure/reset rules for prototype chain.
|
||||
- Dependencies: E3.M2, E5.M1
|
||||
- Dependencies: E3.M2, E5.M1 (gather/craft/encounter hooks on main)
|
||||
- Acceptance criteria:
|
||||
- 3-5 onboarding quests + one chain requiring gather/craft/combat complete without duped rewards.
|
||||
- Telemetry hooks: `quest_start`, `quest_step_complete`, `quest_complete`, funnel times.
|
||||
|
||||
**Linear backlog:** [E7M1-prototype-backlog.md](../../plans/E7M1-prototype-backlog.md) — [NEO-112](https://linear.app/neon-sprawl/issue/NEO-112) → [NEO-123](https://linear.app/neon-sprawl/issue/NEO-123); client capstone **E7M1-12** [NEO-123](https://linear.app/neon-sprawl/issue/NEO-123). Verify in **Godot**, not Bruno-only.
|
||||
|
||||
### Slice 2 - Reward and unlock routing
|
||||
|
||||
- Scope: E7.M2 delivering XP, items, blueprint unlocks, and flags for world gates.
|
||||
|
|
@ -85,7 +89,9 @@ Provide a quest state machine and reward routing that ties gathering, crafting,
|
|||
- Risk: Rewards break parity or economy.
|
||||
- Mitigation: Lint bundles against E6.M4 and E3.M5 policies.
|
||||
|
||||
<a id="epic-7-definition-of-done"></a>
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- Prototype quest counts and integrated chain meet master plan minimums.
|
||||
- Prototype quest counts and integrated chain meet master plan minimums **in the Godot client** (Slice 1 capstone [NEO-123](../../manual-qa/NEO-123.md)), not Bruno-only.
|
||||
- Pre-production adds faction + contracts with validation.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
| **Module ID** | E7.M1 |
|
||||
| **Epic** | [Epic 7 — Quest / Faction](../epics/epic_07_quest_faction.md) |
|
||||
| **Stage target** | Prototype |
|
||||
| **Status** | Planned (see [dependency register](module_dependency_register.md)) |
|
||||
| **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) → **E7M1-12** [NEO-123](https://linear.app/neon-sprawl/issue/NEO-123) (decomposed; implementation not started) |
|
||||
| **Linear** | Label **`E7.M1`** · [E7M1-prototype-backlog.md](../../plans/E7M1-prototype-backlog.md) |
|
||||
|
||||
## Purpose
|
||||
|
||||
|
|
@ -45,6 +46,40 @@ Data-driven quest lifecycle: start, step progression, branching, failure/reset,
|
|||
|
||||
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).
|
||||
|
||||
**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.
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -108,6 +108,8 @@ Gameplay **content and curves** default to **boot load** with optional **dev-onl
|
|||
| Module ID | Module Name | Depends On | Contract Needed | Phase Required | Status |
|
||||
|---|---|---|---|---|---|
|
||||
| E7.M1 | QuestStateMachine | E3.M2, E5.M1 | QuestDef, QuestStepState, QuestStateTransition | Prototype | Planned |
|
||||
|
||||
**E7.M1 note:** Epic 7 **Slice 1** backlog in Linear ([Epic 7 — Questing, Narrative, and Faction Reputation](https://linear.app/neon-sprawl/project/epic-7-questing-narrative-and-faction-reputation-a9416783ceee)): [NEO-112](https://linear.app/neon-sprawl/issue/NEO-112) → [NEO-123](https://linear.app/neon-sprawl/issue/NEO-123); label **`E7.M1`**. See [E7M1-prototype-backlog.md](../../plans/E7M1-prototype-backlog.md), [E7_M1_QuestStateMachine.md](E7_M1_QuestStateMachine.md). Upstream: E3.M1 gather **Ready**, E3.M2 craft **Ready**, E5.M3 encounter **Ready**. Client capstone **E7M1-12** [NEO-123](https://linear.app/neon-sprawl/issue/NEO-123). Register row stays **Planned** until **NEO-112** lands.
|
||||
| E7.M2 | RewardAndUnlockRouter | E2.M2, E3.M3, E7.M1 | QuestRewardBundle, UnlockGrant, RewardDeliveryEvent | Prototype | Planned |
|
||||
| E7.M3 | FactionReputationLedger | E7.M1 | FactionStanding, ReputationDelta, FactionGateRule | Pre-production | Planned |
|
||||
| E7.M4 | ContractMissionGenerator | E4.M1, E5.M3, E7.M3 | ContractTemplate, ContractSeed, ContractOutcome | Pre-production | Planned |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,392 @@
|
|||
# E7.M1 — Prototype story backlog (QuestStateMachine)
|
||||
|
||||
Working backlog for **Epic 7 — Slice 1** ([quest core and persistence](../decomposition/epics/epic_07_quest_faction.md#slice-1---quest-core-and-persistence)). Decomposition and contracts: [E7.M1 — QuestStateMachine](../decomposition/modules/E7_M1_QuestStateMachine.md).
|
||||
|
||||
**Full-stack policy:** Epics deliver **playable game features**. Every **player-visible** story has a **`client`** Linear issue created in **this same decomposition pass** — not an undocumented follow-up. Reference: [E5M3 (paired server+client)](../plans/E5M3-prototype-backlog.md).
|
||||
|
||||
**Labels (Linear):** every issue **`E7.M1`**; add **`server`** or **`client`** + **`Story`** as listed.
|
||||
|
||||
**Precursor (do not re-scope):** [E5.M3](../decomposition/modules/E5_M3_EncounterAndRewardTables.md) encounter complete grants **`contract_handoff_token`** + records **`EncounterCompleteEvent`** ([NEO-107](https://linear.app/neon-sprawl/issue/NEO-107)) — prototype quest credit stand-in until [E7.M2](../decomposition/modules/E7_M2_RewardAndUnlockRouter.md) **`QuestRewardBundle`** router lands. **NEO-43** [`MissionRewardSkillXpGrant`](../../server/NeonSprawl.Server/Game/Skills/MissionRewardSkillXpGrant.cs) is the future skill-XP apply helper for E7.M2; E7.M1 tracks quest state only (no duplicate item grants on quest complete in Slice 1).
|
||||
|
||||
**Upstream (must be landed):** [E3.M1](../decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md) gather on interact ([NEO-63](https://linear.app/neon-sprawl/issue/NEO-63)); [E3.M2](../decomposition/modules/E3_M2_RefinementAndRecipeExecution.md) craft POST ([NEO-70](https://linear.app/neon-sprawl/issue/NEO-70)); [E5.M3](../decomposition/modules/E5_M3_EncounterAndRewardTables.md) encounter wiring + progress GET ([NEO-106](https://linear.app/neon-sprawl/issue/NEO-106), [NEO-108](https://linear.app/neon-sprawl/issue/NEO-108)). [E3S5](../plans/E3S5-client-prototype-backlog.md) client economy HUD ([NEO-72](https://linear.app/neon-sprawl/issue/NEO-72)–[NEO-75](https://linear.app/neon-sprawl/issue/NEO-75)).
|
||||
|
||||
**Prototype quest spine (frozen in E7M1-01):** **three** solo onboarding quests + **one** multi-step chain quest (vision minimum 3–5 onboarding + one integrated chain). **Solo only** — no party credit ([quest_scope_and_party.md](../decomposition/modules/quest_scope_and_party.md)).
|
||||
|
||||
**Linear issues (created):** attach `docs/plans/NEO-*-implementation-plan.md` on the story branch when work starts.
|
||||
|
||||
| Slug | Layer | Linear |
|
||||
|------|-------|--------|
|
||||
| E7M1-01 | server | [NEO-112](https://linear.app/neon-sprawl/issue/NEO-112) |
|
||||
| E7M1-02 | server | [NEO-113](https://linear.app/neon-sprawl/issue/NEO-113) |
|
||||
| E7M1-03 | server | [NEO-114](https://linear.app/neon-sprawl/issue/NEO-114) |
|
||||
| E7M1-04 | server | [NEO-115](https://linear.app/neon-sprawl/issue/NEO-115) |
|
||||
| E7M1-05 | server | [NEO-116](https://linear.app/neon-sprawl/issue/NEO-116) |
|
||||
| E7M1-06 | server | [NEO-117](https://linear.app/neon-sprawl/issue/NEO-117) |
|
||||
| E7M1-07 | server | [NEO-118](https://linear.app/neon-sprawl/issue/NEO-118) |
|
||||
| E7M1-08 | server | [NEO-119](https://linear.app/neon-sprawl/issue/NEO-119) |
|
||||
| E7M1-09 | server | [NEO-120](https://linear.app/neon-sprawl/issue/NEO-120) |
|
||||
| E7M1-10 | server | [NEO-121](https://linear.app/neon-sprawl/issue/NEO-121) |
|
||||
| E7M1-11 | client | [NEO-122](https://linear.app/neon-sprawl/issue/NEO-122) |
|
||||
| E7M1-12 | client | [NEO-123](https://linear.app/neon-sprawl/issue/NEO-123) |
|
||||
|
||||
**Dependency graph in Linear:** E7M1-02 blocked by E7M1-01. E7M1-03 blocked by E7M1-02. E7M1-04 blocked by E7M1-03. E7M1-05 blocked by E7M1-03. E7M1-06 blocked by E7M1-05. E7M1-07 blocked by E7M1-06. E7M1-08 blocked by E7M1-07. E7M1-09 blocked by E7M1-06 (may parallel E7M1-08). E7M1-10 blocked by E7M1-07. E7M1-11 blocked by E7M1-08 and E7M1-09. E7M1-12 blocked by E7M1-11.
|
||||
|
||||
**Board order:** estimates **1–12** matching slug order (E7M1-01 = 1 … E7M1-12 = 12). On the Epic 7 project board, sort by **Estimate** (ascending).
|
||||
|
||||
---
|
||||
|
||||
## Story order (recommended)
|
||||
|
||||
| Order | Slug | Layer | Depends on |
|
||||
|-------|------|-------|------------|
|
||||
| 1 | **E7M1-01** | server | E3.M1/E3.M2/E5.M3 content ids frozen |
|
||||
| 2 | **E7M1-02** | server | E7M1-01 |
|
||||
| 3 | **E7M1-03** | server | E7M1-02 |
|
||||
| 4 | **E7M1-04** | server | E7M1-03 |
|
||||
| 5 | **E7M1-05** | server | E7M1-03 |
|
||||
| 6 | **E7M1-06** | server | E7M1-05 |
|
||||
| 7 | **E7M1-07** | server | E7M1-06 |
|
||||
| 8 | **E7M1-08** | server | E7M1-07 |
|
||||
| 9 | **E7M1-09** | server | E7M1-06 |
|
||||
| 10 | **E7M1-10** | server | E7M1-07 |
|
||||
| 11 | **E7M1-11** | client | E7M1-08, E7M1-09 |
|
||||
| 12 | **E7M1-12** | client | E7M1-11 |
|
||||
|
||||
**Downstream (separate modules):** [E7.M2](../decomposition/modules/E7_M2_RewardAndUnlockRouter.md) idempotent **`QuestRewardBundle`** apply + consume **`EncounterCompleteEvent`**; [E7.M3](../decomposition/modules/E7_M3_FactionReputationLedger.md) faction ledger (pre-production); [E8.M1](../decomposition/modules/E8_M1_PartyAndMatchAssembly.md) party-credit quests.
|
||||
|
||||
---
|
||||
|
||||
## Kickoff decisions (decomposition defaults)
|
||||
|
||||
| Topic | Decision | Rationale |
|
||||
|-------|----------|-----------|
|
||||
| Quest count | **3** onboarding + **1** multi-step chain (4 total) | Vision prototype minimum; readable manual QA |
|
||||
| Party mode | **Solo only** | [quest_scope_and_party.md](../decomposition/modules/quest_scope_and_party.md); E8.M1 not landed |
|
||||
| Accept flow | **`POST …/quests/{questId}/accept`** | Explicit start; boot does not auto-grant all quests |
|
||||
| Objective advance | **Server hooks** on gather/craft/encounter success | Client displays GET snapshot only ([client_server_authority.md](../decomposition/modules/client_server_authority.md)) |
|
||||
| Objective kinds (v1) | **`gather_item`**, **`craft_recipe`**, **`encounter_complete`**, **`inventory_has_item`** | Covers gather→craft→combat chain without custom scripting VM |
|
||||
| Chain quest | **4 sequential steps** in one `QuestDef` | Single HUD row with step index; epic “integrated chain” |
|
||||
| Prerequisites | **`prerequisiteQuestIds`** enforced on accept | Onboarding order: gather → refine → combat → chain |
|
||||
| Rewards (Slice 1) | **State-only completion**; no duplicate item/XP grants | Loot stays on gather/craft/encounter paths; E7.M2 owns bundles |
|
||||
| Token handoff | Chain final step **`inventory_has_item`** **`contract_handoff_token`** | Uses E5.M3 encounter loot; no consume mutation in Slice 1 |
|
||||
| Idempotency | **Once per player per quest id** complete | Slice 1 AC: no duped quest completion |
|
||||
| Store | **In-memory** **`IPlayerQuestStateStore`** (+ optional Postgres migration) | Matches encounter prototype stores |
|
||||
| HTTP read | **`GET /game/players/{id}/quest-progress`** | Client HUD without local objective math |
|
||||
| HUD fidelity | Prototype Labels / debug panels (not final art) | NEO-110 / NEO-122 precedent |
|
||||
|
||||
---
|
||||
|
||||
### E7M1-01 — Prototype QuestDef catalog + schemas + CI
|
||||
|
||||
**Goal:** Lock content shape and CI validation for **four** frozen quests before server load.
|
||||
|
||||
**In scope**
|
||||
|
||||
- `content/schemas/quest-def.schema.json`, `content/schemas/quest-step-def.schema.json`, `content/schemas/quest-objective-def.schema.json`.
|
||||
- `content/quests/prototype_quests.json` — stable quest ids and step/objective graph (see module doc freeze table).
|
||||
- `scripts/validate_content.py`: schema validation, duplicate ids, exact four-quest allowlist, cross-ref **`itemId`** / **`recipeId`** / **`encounterId`** to frozen catalogs, **`prerequisiteQuestIds`** acyclic + known ids, objective kind enum.
|
||||
- Designer note in [E7_M1](../decomposition/modules/E7_M1_QuestStateMachine.md) + `content/README.md`.
|
||||
|
||||
**Out of scope**
|
||||
|
||||
- Server loader, runtime engine, HTTP, Godot.
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] PR gate validates quest JSON against schema.
|
||||
- [ ] Exactly four prototype quest ids; duplicate `id` fails CI.
|
||||
- [ ] Every objective reference resolves to a frozen catalog id.
|
||||
- [ ] Stable id list documented in module doc freeze box.
|
||||
|
||||
**Client counterpart:** none (infrastructure-only).
|
||||
|
||||
---
|
||||
|
||||
### E7M1-02 — Server quest catalog load (fail-fast)
|
||||
|
||||
**Goal:** Disk → host: startup load of `content/quests/*.json` with CI-parity validation.
|
||||
|
||||
**In scope**
|
||||
|
||||
- Loader + catalog types under `server/NeonSprawl.Server/Game/Quests/` (path finalized in plan).
|
||||
- Fail-fast on malformed files, duplicate ids, allowlist mismatch with CI, broken cross-refs (items, recipes, encounters).
|
||||
- Unit tests (AAA) for loader happy path and failure modes.
|
||||
- `server/README.md` section.
|
||||
|
||||
**Out of scope**
|
||||
|
||||
- Injectable registry interface (E7M1-03), HTTP projection, runtime state machine.
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] Host fails startup on invalid quest JSON (mirror CI rules).
|
||||
- [ ] Loader tests cover allowlist + cross-ref failures.
|
||||
|
||||
**Client counterpart:** none (infrastructure-only).
|
||||
|
||||
---
|
||||
|
||||
### E7M1-03 — Injectable quest definition registry + DI
|
||||
|
||||
**Goal:** **`IQuestDefinitionRegistry`** with **`TryGet`**, startup registration from E7M1-02 catalog.
|
||||
|
||||
**In scope**
|
||||
|
||||
- Interface + in-memory implementation; **`AddQuestDefinitionRegistry`** DI extension.
|
||||
- Unit tests: lookup known ids, unknown id returns false.
|
||||
- Wire in host startup alongside other content registries.
|
||||
|
||||
**Out of scope**
|
||||
|
||||
- HTTP, player quest state.
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] Registry resolves all four frozen quest ids at runtime.
|
||||
- [ ] Unknown quest id fails closed for downstream operations.
|
||||
|
||||
**Client counterpart:** none (infrastructure-only).
|
||||
|
||||
---
|
||||
|
||||
### E7M1-04 — GET /game/world/quest-definitions
|
||||
|
||||
**Goal:** Versioned read-only projection of frozen quest defs for client display names and step summaries.
|
||||
|
||||
**In scope**
|
||||
|
||||
- `QuestDefinitionsWorldApi` + DTOs in `Game/Quests/`.
|
||||
- Nested steps/objectives summary (ids, kinds, display copy — no server secrets).
|
||||
- Bruno folder `bruno/neon-sprawl-server/quest-definitions/`.
|
||||
- Integration tests (AAA).
|
||||
|
||||
**Out of scope**
|
||||
|
||||
- Per-player progress (E7M1-08).
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] GET returns all four prototype quests with stable JSON v1 envelope.
|
||||
- [ ] Bruno request documents example response shape.
|
||||
|
||||
**Client counterpart:** consumed by [NEO-122](https://linear.app/neon-sprawl/issue/NEO-122) for display names (optional cache).
|
||||
|
||||
---
|
||||
|
||||
### E7M1-05 — Player quest state store + QuestStepState persistence
|
||||
|
||||
**Goal:** Durable per-player quest rows: status (`not_started` / `active` / `completed`), current step index, per-step objective counters.
|
||||
|
||||
**In scope**
|
||||
|
||||
- **`IPlayerQuestStateStore`** + in-memory implementation (registered in quest DI extension).
|
||||
- Optional Postgres migration **`V00X`** when DB configured (mirror encounter/inventory pattern).
|
||||
- **`QuestStepState`** / **`PlayerQuestProgressRow`** types aligned with module contracts.
|
||||
- Unit tests: accept transitions, idempotent complete mark.
|
||||
|
||||
**Out of scope**
|
||||
|
||||
- Objective evaluation (E7M1-06), HTTP.
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] Store supports read/update per `(playerId, questId)`.
|
||||
- [ ] Completed quest cannot regress to active without explicit reset API (none in prototype).
|
||||
|
||||
**Client counterpart:** none (infrastructure-only).
|
||||
|
||||
---
|
||||
|
||||
### E7M1-06 — QuestStateOperations (accept, step advance, complete)
|
||||
|
||||
**Goal:** Server-authoritative quest lifecycle without objective wiring yet.
|
||||
|
||||
**In scope**
|
||||
|
||||
- **`QuestStateOperations.TryAccept`**, **`TryAdvanceStep`**, **`TryMarkComplete`** with structured **`reasonCode`** denials (`unknown_quest`, `prerequisite_incomplete`, `already_completed`, `already_active`).
|
||||
- Prerequisite enforcement from **`prerequisiteQuestIds`**.
|
||||
- Idempotent complete: second complete returns success without state change.
|
||||
- Unit tests (AAA) for accept order, prerequisite gate, idempotent complete.
|
||||
|
||||
**Out of scope**
|
||||
|
||||
- Gather/craft/encounter hooks (E7M1-07); HTTP (E7M1-08/09).
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] Accept fails when prerequisite quest not **completed**.
|
||||
- [ ] Complete is idempotent per player+quest.
|
||||
- [ ] Reason codes documented in `server/README.md`.
|
||||
|
||||
**Client counterpart:** [NEO-120](https://linear.app/neon-sprawl/issue/NEO-120) exposes accept POST to Godot.
|
||||
|
||||
---
|
||||
|
||||
### E7M1-07 — Quest objective wiring (gather, craft, encounter)
|
||||
|
||||
**Goal:** Advance active quest steps when server-side gather, craft, and encounter events succeed.
|
||||
|
||||
**In scope**
|
||||
|
||||
- **`QuestObjectiveWiring`** (or equivalent) invoked from:
|
||||
- **`GatherOperations.TryGather`** success path — **`gather_item`** objectives.
|
||||
- **`CraftOperations.TryCraft`** success path — **`craft_recipe`** objectives.
|
||||
- **`EncounterCompletionOperations.TryCompleteAndGrant`** success path — **`encounter_complete`** objectives.
|
||||
- Inventory snapshot read for **`inventory_has_item`** (post-grant or on polling hook from accept).
|
||||
- Counter accumulation for quantity objectives (e.g. gather 3 scrap).
|
||||
- Auto **`TryAdvanceStep`** / **`TryMarkComplete`** when step objectives satisfied.
|
||||
- Integration tests: accept quest → simulate gather/craft/encounter → progress row advances.
|
||||
|
||||
**Out of scope**
|
||||
|
||||
- Client-side objective tracking; item consume on turn-in; E7.M2 reward bundles.
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] Active **`prototype_quest_gather_intro`** advances when **`scrap_metal_bulk`** gather succeeds.
|
||||
- [ ] Active **`prototype_quest_refine_intro`** advances on **`refine_scrap_standard`** craft success.
|
||||
- [ ] Active **`prototype_quest_combat_intro`** advances when **`prototype_combat_pocket`** completes.
|
||||
- [ ] Chain quest steps advance in order across mixed objective kinds.
|
||||
|
||||
**Client counterpart:** progress visible via [NEO-122](https://linear.app/neon-sprawl/issue/NEO-122) GET HUD after mutations.
|
||||
|
||||
---
|
||||
|
||||
### E7M1-08 — GET /game/players/{id}/quest-progress
|
||||
|
||||
**Goal:** Per-player quest progress snapshot for client HUD.
|
||||
|
||||
**In scope**
|
||||
|
||||
- **`QuestProgressApi`** + DTOs: all known quests with status, current step index, objective progress counters, completion timestamp when applicable.
|
||||
- Known-player gate (mirror encounter-progress / skill-progression patterns).
|
||||
- Bruno `bruno/neon-sprawl-server/quest-progress/`.
|
||||
- Integration tests (AAA): accept → partial progress → complete rows.
|
||||
|
||||
**Out of scope**
|
||||
|
||||
- Quest definition catalog (E7M1-04).
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] GET returns stable v1 envelope for **`dev-local-1`** player.
|
||||
- [ ] Completed quests show **`completed`** with step count at terminal step.
|
||||
|
||||
**Client counterpart:** [NEO-122](https://linear.app/neon-sprawl/issue/NEO-122) — **`quest_progress_client.gd`** + HUD labels.
|
||||
|
||||
---
|
||||
|
||||
### E7M1-09 — POST /game/players/{id}/quests/{questId}/accept
|
||||
|
||||
**Goal:** Player-initiated quest accept from Godot (prototype “quest giver” is HUD button or key binding).
|
||||
|
||||
**In scope**
|
||||
|
||||
- **`QuestAcceptApi`**: POST accept; JSON body optional v1 `{}`; response includes updated progress row or deny payload.
|
||||
- Wire **`QuestStateOperations.TryAccept`**.
|
||||
- Bruno + integration tests: happy accept, prerequisite deny, duplicate accept.
|
||||
|
||||
**Out of scope**
|
||||
|
||||
- Abandon/reset POST (defer unless capstone QA requires).
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] Successful accept transitions row **`not_started` → `active`**.
|
||||
- [ ] Deny returns structured **`reasonCode`** without mutation.
|
||||
|
||||
**Client counterpart:** [NEO-122](https://linear.app/neon-sprawl/issue/NEO-122) — accept binding + feedback label.
|
||||
|
||||
---
|
||||
|
||||
### E7M1-10 — Quest telemetry hook sites (comment-only)
|
||||
|
||||
**Goal:** Document and place comment-only hook sites for future E9.M1 catalog events **`quest_start`**, **`quest_step_complete`**, **`quest_complete`**.
|
||||
|
||||
**In scope**
|
||||
|
||||
- Hook sites in **`QuestStateOperations`** / **`QuestObjectiveWiring`** at accept, step advance, and complete.
|
||||
- Reserved deny hook **`quest_accept_denied`** (optional comment).
|
||||
- `server/README.md` subsection; module doc note.
|
||||
|
||||
**Out of scope**
|
||||
|
||||
- E9.M1 ingest pipeline; runtime telemetry emit.
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] Hook sites exist at accept, step complete, quest complete paths.
|
||||
- [ ] Epic 7 Slice 1 telemetry vocabulary documented.
|
||||
|
||||
**Client counterpart:** none (infrastructure-only).
|
||||
|
||||
---
|
||||
|
||||
### E7M1-11 — Client quest progress + accept HUD (Godot)
|
||||
|
||||
**Goal:** Godot **`GET …/quest-progress`** client + readable quest panel; accept via **`POST …/accept`**.
|
||||
|
||||
**In scope**
|
||||
|
||||
- `quest_progress_client.gd`, optional `quest_definitions_client.gd` for display names.
|
||||
- HUD: **`QuestProgressLabel`** (active/completed summary), **`QuestAcceptFeedbackLabel`** (deny/success copy).
|
||||
- Boot hydrate + refresh after gather/craft/cast/encounter events (mirror **`encounter_progress_client.gd`** pattern).
|
||||
- Prototype accept bindings: e.g. keys **Q** / **Shift+Q** for next eligible quest accept (document in manual QA).
|
||||
- GdUnit: HTTP double, parse happy path + deny path.
|
||||
- `client/README.md` section.
|
||||
- `docs/manual-qa/NEO-122.md`.
|
||||
|
||||
**Out of scope**
|
||||
|
||||
- Quest journal art, map pins, NPC dialog; final quest picker UI.
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] Player sees quest status change after accept without Bruno.
|
||||
- [ ] Objective progress updates after gather/craft/encounter in Godot session.
|
||||
- [ ] Failed GET/accept surfaces visible HUD error (match interaction client pattern).
|
||||
|
||||
**Client counterpart:** this story **is** the client counterpart for E7M1-08/09.
|
||||
|
||||
---
|
||||
|
||||
### E7M1-12 — Playable onboarding quest chain capstone (Godot)
|
||||
|
||||
**Goal:** Prove Epic 7 Slice 1 acceptance **in Godot**: complete all four prototype quests (gather → refine → combat → operator chain) without Bruno; satisfies vision **quest loop** gate.
|
||||
|
||||
**In scope**
|
||||
|
||||
- **`docs/manual-qa/NEO-123.md`**: numbered single-session capstone — fresh server restart, accept onboarding quests in order, perform gather/craft/combat actions, verify chain quest **`prototype_quest_operator_chain`** completes when **`contract_handoff_token`** held.
|
||||
- **`client/README.md`**: **End-to-end onboarding quest loop** section — flow table; cross-links NEO-112–NEO-122.
|
||||
- Module alignment on completion: [E7_M1](../decomposition/modules/E7_M1_QuestStateMachine.md), [documentation_and_implementation_alignment.md](../decomposition/modules/documentation_and_implementation_alignment.md), [module_dependency_register.md](../decomposition/modules/module_dependency_register.md).
|
||||
|
||||
**Out of scope**
|
||||
|
||||
- E7.M2 reward bundles; faction reputation; quest VFX; Bruno-only verification as prototype-complete proof.
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] Human completes **`docs/manual-qa/NEO-123.md`** with server + client.
|
||||
- [ ] Epic 7 Slice 1 AC: 3 onboarding + 1 chain complete without duplicate completion on replay.
|
||||
- [ ] Re-read [epic_07 Definition of Done](../decomposition/epics/epic_07_quest_faction.md#definition-of-done) for prototype minimums.
|
||||
|
||||
**Client counterpart:** this story **is** the Slice 1 client capstone.
|
||||
|
||||
---
|
||||
|
||||
## Decomposition complete checklist
|
||||
|
||||
- [x] Every player-visible AC has a **`client`** Linear issue (NEO-122, NEO-123)
|
||||
- [x] No forbidden deferral language in backlog
|
||||
- [x] Capstone client story exists (E7M1-12 / NEO-123)
|
||||
- [x] Epic DoD updated for Godot verification
|
||||
- [x] [documentation_and_implementation_alignment.md](../decomposition/modules/documentation_and_implementation_alignment.md) E7.M1 row updated
|
||||
- [x] [module_dependency_register.md](../decomposition/modules/module_dependency_register.md) E7.M1 note updated
|
||||
|
||||
## Related docs
|
||||
|
||||
- [epic_07_quest_faction.md](../decomposition/epics/epic_07_quest_faction.md)
|
||||
- [quest_scope_and_party.md](../decomposition/modules/quest_scope_and_party.md)
|
||||
- [E5M3-prototype-backlog.md](E5M3-prototype-backlog.md) (encounter token precursor)
|
||||
- [E3S5-client-prototype-backlog.md](E3S5-client-prototype-backlog.md) (gather/craft client HUD)
|
||||
- [neon_sprawl_vision.plan.md — Prototype Scope](../../neon_sprawl_vision.plan.md)
|
||||
Loading…
Reference in New Issue