chore: Decompose E7.M2 prototype backlog (NEO-124–NEO-132).

Epic 7 Slice 2 reward router: nine server+client stories, Linear
issues, module docs, and kickoff defaults for completion bundles.
pull/163/head
VinPropane 2026-06-07 15:11:43 -04:00
parent 31609917a5
commit 85ead01a0b
6 changed files with 336 additions and 3 deletions

View File

@ -66,6 +66,8 @@ Provide a quest state machine and reward routing that ties gathering, crafting,
- Idempotent reward delivery; replays cannot double-claim.
- Telemetry hooks: `reward_delivery`, `unlock_granted`.
**Linear backlog:** [E7M2-prototype-backlog.md](../../plans/E7M2-prototype-backlog.md) — [NEO-124](https://linear.app/neon-sprawl/issue/NEO-124) → [NEO-132](https://linear.app/neon-sprawl/issue/NEO-132); client capstone **E7M2-09** [NEO-132](https://linear.app/neon-sprawl/issue/NEO-132). Verify quest completion rewards in **Godot**, not Bruno-only. Encounter loot ([E5.M3](../modules/E5_M3_EncounterAndRewardTables.md)) unchanged in Slice 2.
### Slice 3 - Faction ledger (pre-production)
- Scope: E7.M3 gating at least one faction line and mission set.
@ -94,4 +96,5 @@ Provide a quest state machine and reward routing that ties gathering, crafting,
## Definition of Done
- 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.
- Slice 2 quest **completion** rewards (items + skill XP) visible in Godot with idempotent delivery (capstone [NEO-132](../../manual-qa/NEO-132.md)), not Bruno-only.
- Pre-production adds faction + contracts with validation.

View File

@ -7,7 +7,7 @@
| **Module ID** | E7.M2 |
| **Epic** | [Epic 7 — Quest / Faction](../epics/epic_07_quest_faction.md) |
| **Stage target** | Prototype |
| **Status** | Planned (see [dependency register](module_dependency_register.md)). **NEO-43 prep:** server `MissionRewardSkillXpGrant` for scripted skill XP from bundles (`mission_reward`); full router + `QuestRewardBundle` apply still TBD. |
| **Status** | Planned — Slice 2 backlog [E7M2-prototype-backlog.md](../../plans/E7M2-prototype-backlog.md): **E7M2-01** [NEO-124](https://linear.app/neon-sprawl/issue/NEO-124) → **E7M2-09** [NEO-132](https://linear.app/neon-sprawl/issue/NEO-132). **NEO-43 prep landed:** `MissionRewardSkillXpGrant` for bundle skill XP (`mission_reward`). Upstream: E7.M1 **Ready**, E2.M2 grant stack, E3.M3 inventory. |
## Purpose
@ -38,7 +38,20 @@ Route quest and encounter outputs to XP, items, unlocks, and flags with **idempo
## Related implementation slices
Epic 7 **Slice 2**`reward_delivery`, `unlock_granted`; no double-claim on replay.
Epic 7 **Slice 2**`reward_delivery`, `unlock_granted`; no double-claim on replay. Backlog: [E7M2-prototype-backlog.md](../../plans/E7M2-prototype-backlog.md).
## Prototype Slice 2 freeze (E7M2-01)
**`completionRewardBundle`** on each frozen [E7.M1 quest id](E7_M1_QuestStateMachine.md#prototype-slice-1-freeze-e7m1-01). Grant kinds v1: **`item_grants`** + **`skill_xp_grants`** only (unlock/flag rows deferred).
| Quest id | Item grants | Skill XP (`mission_reward`) |
|----------|-------------|-------------------------------|
| `prototype_quest_gather_intro` | — | `salvage` **25** |
| `prototype_quest_refine_intro` | — | `refine` **25** |
| `prototype_quest_combat_intro` | — | `salvage` **25** |
| `prototype_quest_operator_chain` | `survey_drone_kit` ×1 | `salvage` **50** |
**Idempotency:** `{playerId}:quest_complete:{questId}`. **Encounter loot:** [E5.M3](E5_M3_EncounterAndRewardTables.md) direct grants unchanged in Slice 2.
## Source anchors

File diff suppressed because one or more lines are too long

View File

@ -111,6 +111,8 @@ Gameplay **content and curves** default to **boot load** with optional **dev-onl
**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) **landed**; 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**. **E7M1-12 / NEO-123** client capstone landed — [`NEO-123` manual QA](../../manual-qa/NEO-123.md), [client README — End-to-end onboarding quest loop (NEO-123)](../../../client/README.md#end-to-end-onboarding-quest-loop-neo-123), plan [NEO-123](../../plans/NEO-123-implementation-plan.md). Epic 7 Slice 1 client capstone complete.
| E7.M2 | RewardAndUnlockRouter | E2.M2, E3.M3, E7.M1 | QuestRewardBundle, UnlockGrant, RewardDeliveryEvent | Prototype | Planned |
**E7.M2 note:** Epic 7 **Slice 2** 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-124](https://linear.app/neon-sprawl/issue/NEO-124) → [NEO-132](https://linear.app/neon-sprawl/issue/NEO-132); label **`E7.M2`**. See [E7M2-prototype-backlog.md](../../plans/E7M2-prototype-backlog.md), [E7_M2_RewardAndUnlockRouter.md](E7_M2_RewardAndUnlockRouter.md). Upstream: E7.M1 **Ready**, E2.M2 grant stack ([NEO-43](https://linear.app/neon-sprawl/issue/NEO-43)), E3.M3 inventory **Ready**. Client capstone **E7M2-09** [NEO-132](https://linear.app/neon-sprawl/issue/NEO-132). Register row stays **Planned** until capstone lands.
| 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 |

View File

@ -52,7 +52,7 @@ Working backlog for **Epic 7 — Slice 1** ([quest core and persistence](../deco
| 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.
**Downstream (separate modules):** [E7.M2](../decomposition/modules/E7_M2_RewardAndUnlockRouter.md) Slice 2 backlog [E7M2-prototype-backlog.md](E7M2-prototype-backlog.md) ([NEO-124](https://linear.app/neon-sprawl/issue/NEO-124)[NEO-132](https://linear.app/neon-sprawl/issue/NEO-132)); [E7.M3](../decomposition/modules/E7_M3_FactionReputationLedger.md) faction ledger (pre-production); [E8.M1](../decomposition/modules/E8_M1_PartyAndMatchAssembly.md) party-credit quests.
---

View File

@ -0,0 +1,314 @@
# E7.M2 — Prototype story backlog (RewardAndUnlockRouter)
Working backlog for **Epic 7 — Slice 2** ([reward and unlock routing](../decomposition/epics/epic_07_quest_faction.md#slice-2---reward-and-unlock-routing)). Decomposition and contracts: [E7.M2 — RewardAndUnlockRouter](../decomposition/modules/E7_M2_RewardAndUnlockRouter.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: [E7M1 (paired server+client)](../plans/E7M1-prototype-backlog.md), [E5M3 (encounter loot capstone)](../plans/E5M3-prototype-backlog.md).
**Labels (Linear):** every issue **`E7.M2`**; add **`server`** or **`client`** + **`Story`** as listed.
**Precursor (do not re-scope):** [E7.M1](../decomposition/modules/E7_M1_QuestStateMachine.md) Slice 1 **Ready** — quest state + objectives only; no duplicate completion grants on replay ([NEO-123](https://linear.app/neon-sprawl/issue/NEO-123)). [E5.M3](../decomposition/modules/E5_M3_EncounterAndRewardTables.md) encounter loot stays on **`EncounterCompletionOperations`** + **`rewardGrantSummary`** on encounter-progress GET — **not** migrated through E7.M2 in Slice 2. **`EncounterCompleteEvent`** ([NEO-107](https://linear.app/neon-sprawl/issue/NEO-107)) remains a future consumer hook. **NEO-43** [`MissionRewardSkillXpGrant`](../../server/NeonSprawl.Server/Game/Skills/MissionRewardSkillXpGrant.cs) is the skill-XP apply path for bundle rows with **`sourceKind: mission_reward`**.
**Upstream (must be landed):** [E7.M1](E7_M1_QuestStateMachine.md) **Ready** ([NEO-112](https://linear.app/neon-sprawl/issue/NEO-112)[NEO-123](https://linear.app/neon-sprawl/issue/NEO-123)); [E2.M2](E2_M2_XpAwardAndLevelEngine.md) grant stack ([NEO-38](https://linear.app/neon-sprawl/issue/NEO-38), [NEO-43](https://linear.app/neon-sprawl/issue/NEO-43)); [E3.M3](E3_M3_ItemizationAndInventorySchema.md) inventory ([NEO-54](https://linear.app/neon-sprawl/issue/NEO-54)[NEO-55](https://linear.app/neon-sprawl/issue/NEO-55)). [NEO-122](https://linear.app/neon-sprawl/issue/NEO-122) quest HUD for client reward surfacing.
**Prototype reward spine (frozen in E7M2-01):** **`completionRewardBundle`** on each of the **four** frozen [E7.M1 quests](E7_M1_QuestStateMachine.md#prototype-slice-1-freeze-e7m1-01) — **quest completion only** (not per-step). Grant kinds v1: **`item_grants`** + **`skill_xp_grants`** only. **Solo only** — per-character idempotent keys ([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 |
|------|-------|--------|
| E7M2-01 | server | [NEO-124](https://linear.app/neon-sprawl/issue/NEO-124) |
| E7M2-02 | server | [NEO-125](https://linear.app/neon-sprawl/issue/NEO-125) |
| E7M2-03 | server | [NEO-126](https://linear.app/neon-sprawl/issue/NEO-126) |
| E7M2-04 | server | [NEO-127](https://linear.app/neon-sprawl/issue/NEO-127) |
| E7M2-05 | server | [NEO-128](https://linear.app/neon-sprawl/issue/NEO-128) |
| E7M2-06 | server | [NEO-129](https://linear.app/neon-sprawl/issue/NEO-129) |
| E7M2-07 | server | [NEO-130](https://linear.app/neon-sprawl/issue/NEO-130) |
| E7M2-08 | client | [NEO-131](https://linear.app/neon-sprawl/issue/NEO-131) |
| E7M2-09 | client | [NEO-132](https://linear.app/neon-sprawl/issue/NEO-132) |
**Dependency graph in Linear:** E7M2-02 blocked by E7M2-01. E7M2-03 blocked by E7M2-01. E7M2-04 blocked by E7M2-02 and E7M2-03. E7M2-05 blocked by E7M2-04. E7M2-06 blocked by E7M2-05. E7M2-07 blocked by E7M2-05 (may parallel E7M2-06). E7M2-08 blocked by E7M2-06. E7M2-09 blocked by E7M2-08.
**Board order:** estimates **19** matching slug order (E7M2-01 = 1 … E7M2-09 = 9). On the Epic 7 project board, sort by **Estimate** (ascending).
---
## Story order (recommended)
| Order | Slug | Layer | Depends on |
|-------|------|-------|------------|
| 1 | **E7M2-01** | server | E7.M1 quest catalog frozen |
| 2 | **E7M2-02** | server | E7M2-01 |
| 3 | **E7M2-03** | server | E7M2-01 |
| 4 | **E7M2-04** | server | E7M2-02, E7M2-03 |
| 5 | **E7M2-05** | server | E7M2-04 |
| 6 | **E7M2-06** | server | E7M2-05 |
| 7 | **E7M2-07** | server | E7M2-05 |
| 8 | **E7M2-08** | client | E7M2-06 |
| 9 | **E7M2-09** | client | E7M2-08 |
**Downstream (separate modules):** [E6.M4](../decomposition/modules/E6_M4_RewardParityEnforcer.md) lint against bundles; [E7.M3](../decomposition/modules/E7_M3_FactionReputationLedger.md) reputation grants (pre-production); E5.M3 **`EncounterCompleteEvent`** full router consumer (optional follow-on).
---
## Kickoff decisions (decomposition defaults)
| Topic | Decision | Rationale |
|-------|----------|-----------|
| Reward trigger | **Quest completion only** (not per-step) | Slice 2 AC is idempotent **completion** delivery; step bundles add scope without prototype need |
| Grant kinds (v1) | **`item_grants`** + **`skill_xp_grants`** (`mission_reward`) | [NEO-43](NEO-43-implementation-plan.md) prep; unlock/flag grants deferred |
| Unlock / world gates | **Deferred** to pre-production | Epic mentions unlocks; no prototype gate content yet — comment-only **`unlock_granted`** hook |
| Encounter loot | **Unchanged** — E5.M3 direct grants | Avoid breaking [NEO-111](https://linear.app/neon-sprawl/issue/NEO-111) / [NEO-123](https://linear.app/neon-sprawl/issue/NEO-123); `EncounterCompleteEvent` consumer is follow-on |
| Bundle attachment | **`completionRewardBundle`** on each frozen **four** quests | Readable capstone; CI enforces shape on all E7.M1 ids |
| Idempotency key | **`{playerId}:quest_complete:{questId}`** | [quest_scope_and_party.md](../decomposition/modules/quest_scope_and_party.md); once per character per quest |
| Delivery store | **In-memory** **`IRewardDeliveryStore`** (+ optional Postgres migration) | Matches encounter/quest prototype stores |
| Fail-closed | **Quest complete rolls back** if bundle apply fails after mark (inventory full deny) | Mirror [NEO-105](NEO-105-implementation-plan.md) encounter completion compensating rollback |
| HTTP read | **Extend** **`GET …/quest-progress`** with **`completionRewardSummary`** per completed quest | Mirror encounter **`rewardGrantSummary`** ([NEO-108](NEO-108-implementation-plan.md)); no new top-level route in Slice 2 |
| Party mode | **Solo only** | E8.M1 not landed |
| HUD fidelity | Prototype labels / debug panels | NEO-122 / NEO-110 precedent |
### Prototype completion bundles (E7M2-01 freeze — tunable display only)
| Quest id | Item grants | Skill XP grants |
|----------|-------------|-----------------|
| `prototype_quest_gather_intro` | — | **`salvage`** **25** (`mission_reward`) |
| `prototype_quest_refine_intro` | — | **`refine`** **25** (`mission_reward`) |
| `prototype_quest_combat_intro` | — | **`salvage`** **25** (`mission_reward`) |
| `prototype_quest_operator_chain` | **`survey_drone_kit` ×1** | **`salvage`** **50** (`mission_reward`) |
Combat intro bundle is **skill XP only** — encounter loot already granted **`contract_handoff_token`** via E5.M3 (no double item payout on same milestone).
---
### E7M2-01 — QuestRewardBundle schema + quest catalog extension + CI
**Goal:** Lock **`completionRewardBundle`** content shape and CI validation on the four frozen quests before server load.
**In scope**
- `content/schemas/quest-reward-bundle.schema.json`, `content/schemas/quest-skill-xp-grant.schema.json` (reuse or align with existing grant row patterns).
- Extend `content/schemas/quest-def.schema.json` with optional **`completionRewardBundle`**.
- Update `content/quests/prototype_quests.json` — bundles per freeze table above.
- `scripts/validate_content.py`: bundle schema validation, item id cross-refs, skill id cross-refs, `mission_reward` allowlist alignment with `prototype_skills.json`.
- Designer note in [E7_M2](../decomposition/modules/E7_M2_RewardAndUnlockRouter.md) + `content/README.md`.
**Out of scope**
- Server loader, delivery store, router, HTTP, Godot.
**Acceptance criteria**
- [ ] PR gate validates quest JSON including optional completion bundles.
- [ ] All four prototype quests include a **`completionRewardBundle`** row matching freeze table.
- [ ] Invalid item/skill refs fail CI.
**Client counterpart:** none (infrastructure-only).
---
### E7M2-02 — Server quest catalog load: reward bundle validation
**Goal:** Fail-fast startup validation of **`completionRewardBundle`** with CI parity.
**In scope**
- Extend `server/NeonSprawl.Server/Game/Quests/` catalog loader / registry types.
- Cross-check bundle grants against item + skill registries at startup.
- Unit tests (AAA) for happy path and broken bundle refs.
- `server/README.md` section.
**Out of scope**
- Delivery apply, HTTP projection changes.
**Acceptance criteria**
- [ ] Host exits on invalid bundle refs at startup.
- [ ] `dotnet test` covers loader gates.
**Client counterpart:** none (infrastructure-only).
---
### E7M2-03 — Reward delivery store (`IRewardDeliveryStore`)
**Goal:** Durable idempotency record for **`RewardDeliveryEvent`** per player + quest completion.
**In scope**
- `IRewardDeliveryStore`, in-memory implementation, optional Postgres migration (NEO-29-style split).
- Idempotency key **`{playerId}:quest_complete:{questId}`**; store granted item + skill XP summary for audit/read projection.
- Unit tests: first delivery applies; replay returns existing event without double-apply.
- `server/README.md` store section.
**Out of scope**
- Router apply logic (E7M2-04), quest-state wiring (E7M2-05).
**Acceptance criteria**
- [ ] `TryRecord` idempotent on same key.
- [ ] Store readable summary for HTTP projection.
**Client counterpart:** none (infrastructure-only).
---
### E7M2-04 — `RewardRouterOperations` (apply `QuestRewardBundle`)
**Goal:** Server-internal apply for item + skill XP completion bundles with structured outcomes.
**In scope**
- `RewardRouterOperations.TryDeliverQuestCompletion` in `server/NeonSprawl.Server/Game/Quests/` (or `Game/Rewards/`).
- Item grants via **`PlayerInventoryOperations`**; skill XP via **`MissionRewardSkillXpGrant`**.
- Deny reason codes (inventory full, unknown item/skill, xp deny).
- Unit + integration tests (AAA): happy path, inventory deny, idempotent replay via store.
**Out of scope**
- Quest state transition hooks (E7M2-05), HTTP DTOs (E7M2-06).
**Acceptance criteria**
- [ ] Bundle rows apply atomically where possible; compensating rollback on partial failure before store record.
- [ ] Skill XP uses **`mission_reward`** source kind only.
**Client counterpart:** none (server engine).
---
### E7M2-05 — Wire router into `QuestStateOperations.TryMarkComplete`
**Goal:** First-time quest completion triggers bundle delivery exactly once.
**In scope**
- Call **`RewardRouterOperations`** from **`TryMarkComplete`** success path (after state commit or transactional equivalent per fail-closed decision).
- Skip delivery on idempotent complete replay (already `Completed` status).
- Integration tests: complete gather intro → inventory/skills reflect bundle; replay → no duplicate grants.
- Bruno smoke in `bruno/neon-sprawl-server/quest-progress/` (optional subfolder).
**Out of scope**
- Encounter completion path; step-complete bundles.
**Acceptance criteria**
- [ ] Completing a quest via objective wiring delivers bundle once.
- [ ] Idempotent complete does not double-grant items or XP.
**Client counterpart:** [NEO-131](https://linear.app/neon-sprawl/issue/NEO-131) — HUD surfacing (blocked by E7M2-06).
---
### E7M2-06 — Extend `GET …/quest-progress` with `completionRewardSummary`
**Goal:** Client-readable grant summary on completed quest rows (mirror encounter progress).
**In scope**
- Extend `QuestProgressApi` DTOs + OpenAPI-stable JSON: per completed quest optional **`completionRewardSummary`** (item lines + skill XP lines).
- Populate from **`IRewardDeliveryStore`** / delivery event snapshot.
- Integration tests + Bruno assertions on gather intro complete path.
- `server/README.md` quest-progress section update.
**Out of scope**
- Godot HUD (E7M2-08).
**Acceptance criteria**
- [ ] Completed quest rows include summary when delivery recorded.
- [ ] `not_started` / `active` rows omit summary.
**Client counterpart:** [NEO-131](https://linear.app/neon-sprawl/issue/NEO-131).
---
### E7M2-07 — Reward telemetry hook sites (comment-only)
**Goal:** Anchor future E9.M1 catalog events without ingest.
**In scope**
- Comment-only **`reward_delivery`** in **`RewardRouterOperations`** (first-time success).
- Comment-only **`unlock_granted`** stub (no runtime unlock apply in Slice 2).
- `server/README.md` hook list.
**Out of scope**
- E9.M1 ingest, unlock engine.
**Acceptance criteria**
- [ ] Hook sites documented in README; no behavior change beyond comments.
**Client counterpart:** none (infrastructure-only).
---
### E7M2-08 — Client quest completion reward HUD (Godot)
**Goal:** Player sees quest completion rewards in Godot without Bruno.
**In scope**
- Extend **`quest_progress_client.gd`** parse for **`completionRewardSummary`**.
- **`QuestRewardDeliveryLabel`** (or extend **`QuestProgressLabel`** / **`quest_hud_controller.gd`**) — compact grant lines when quest transitions to **`completed`**.
- Refresh on quest-progress GET after objective events (reuse NEO-122 triggers).
- GdUnit parse tests; `client/README.md` section.
- `docs/manual-qa/NEO-131.md` component checklist.
**Out of scope**
- Final quest journal UI; reward VFX.
**Acceptance criteria**
- [ ] Completing a quest shows readable reward copy on HUD.
- [ ] Failed GET surfaces visible error (NEO-122 pattern).
**Server counterpart:** [NEO-129](https://linear.app/neon-sprawl/issue/NEO-129).
---
### E7M2-09 — Playable quest reward delivery capstone (Godot)
**Goal:** Prove Epic 7 Slice 2 acceptance **in Godot**: quest completion grants items + skill XP **once**; idempotent on replay.
**In scope**
- **`docs/manual-qa/NEO-132.md`**: single-session capstone — extend [NEO-123](NEO-123.md) flow or shorter reward-focused path; verify **`completionRewardSummary`** + inventory/skills; Godot restart + duplicate complete attempt unchanged.
- **`client/README.md`**: **End-to-end quest reward loop** section; cross-links NEO-124NEO-131.
- Module alignment on completion: [E7_M2](../decomposition/modules/E7_M2_RewardAndUnlockRouter.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**
- Encounter loot migration; faction reputation; Bruno-only proof.
**Acceptance criteria**
- [ ] Human completes **`docs/manual-qa/NEO-132.md`** with server + client.
- [ ] Epic 7 Slice 2 AC: idempotent reward delivery; replays cannot double-claim.
- [ ] Re-read [epic_07 Slice 2 AC](../decomposition/epics/epic_07_quest_faction.md#slice-2---reward-and-unlock-routing).
**Client counterpart:** this story **is** the Slice 2 client capstone.
---
## Decomposition complete checklist
- [x] Every player-visible AC has a **`client`** Linear issue (NEO-131, NEO-132)
- [x] No forbidden deferral language in backlog
- [x] Capstone client story exists (E7M2-09 / NEO-132)
- [x] Epic DoD updated for Godot verification (see epic_07 update)
- [x] [documentation_and_implementation_alignment.md](../decomposition/modules/documentation_and_implementation_alignment.md) E7.M2 row updated (decomposition pass)
- [x] [module_dependency_register.md](../decomposition/modules/module_dependency_register.md) E7.M2 note updated
## Related docs
- [epic_07_quest_faction.md](../decomposition/epics/epic_07_quest_faction.md)
- [E7M1-prototype-backlog.md](E7M1-prototype-backlog.md)
- [NEO-43 implementation plan](NEO-43-implementation-plan.md)
- [quest_scope_and_party.md](../decomposition/modules/quest_scope_and_party.md)
- [neon_sprawl_vision.plan.md — Prototype Scope](../../neon_sprawl_vision.plan.md)