From b97cace62573d49025ba0ebada1aacb56f59b10c Mon Sep 17 00:00:00 2001 From: VinPropane Date: Mon, 25 May 2026 13:59:31 -0400 Subject: [PATCH] NEO-86: Add capstone manual QA, README, and module doc reconciliation. Documents end-to-end Godot combat loop, marks E5M1-12 landed, and updates E5.M1 alignment rows for Epic 5 Slice 1 client capstone complete. --- client/README.md | 27 +++++++++- .../modules/E5_M1_CombatRulesEngine.md | 4 +- ...umentation_and_implementation_alignment.md | 2 +- .../modules/module_dependency_register.md | 2 +- docs/manual-qa/NEO-86.md | 53 +++++++++++++++++++ docs/plans/E5M1-prototype-backlog.md | 8 +-- docs/plans/NEO-86-implementation-plan.md | 17 ++++-- 7 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 docs/manual-qa/NEO-86.md diff --git a/client/README.md b/client/README.md index 0be663a..f7637f4 100644 --- a/client/README.md +++ b/client/README.md @@ -149,6 +149,31 @@ Full checklist: [`docs/manual-qa/NEO-31.md`](../docs/manual-qa/NEO-31.md) · cas Full checklist: [`docs/manual-qa/NEO-85.md`](../docs/manual-qa/NEO-85.md). +## End-to-end combat loop (NEO-86) + +Epic 5 Slice 1 capstone — tab-target lock, cast, defeat, and gig XP visibility **in Godot** without Bruno. + +**Flow:** boot hotbar sync (auto **`prototype_pulse`** bind on slot 0 when empty) → walk to orange **Dummy α** → **Tab** lock → digit **1** cast until defeat → verify combat HUD + **`breach`** gig XP refresh. + +| Step | Input / trigger | HUD / server outcome | +|------|-----------------|----------------------| +| Boot | Godot **F5** + server running | Hotbar slot 0 binds **`prototype_pulse`**; **`GigXpLabel`** hydrates **`breach: L1 · 0 xp`** | +| Lock | **Tab** on **`prototype_target_alpha`** | Dummy brightens; **`CombatTargetHpLabel`** shows **`100/100`** | +| Cast ×4 | **1** (respect ~3s cooldown) | **`CastFeedbackLabel`** steps damage; HP label tracks server snapshot | +| Defeat | 4th pulse accept | **`Cast: … — defeated!`**; HP **`0/100 (defeated)`**; **`GigXpLabel`** → **`25 xp`** | +| Deny | **1** on defeated target | **`ability_cast_denied: target_defeated`** | +| Clear | **Esc** | HP label **`— (no lock)`** | + +**Cross-links:** [NEO-23](../docs/plans/NEO-23-implementation-plan.md) targeting · [NEO-28](../docs/manual-qa/NEO-28.md) cast deny HUD · [NEO-31](../docs/manual-qa/NEO-31.md) cast POST · [NEO-85](NEO-85.md) combat feedback + HP · [NEO-44](../docs/manual-qa/NEO-44.md) server gig grant. + +**Scripts:** `ability_cast_client.gd`, `combat_targets_client.gd`, `gig_progression_client.gd` — wired from `main.gd`. + +**Economy HUD:** **`GigXpLabel`** lives under **`EconomyHudSection/Body/`** (hidden when **`Economy HUD`** collapsed, NEO-75). Gig GET refreshes on boot and when cast accept carries **`targetDefeated: true`** only — not on every hit. + +**Preconditions:** **Server restart** before capstone run resets in-memory dummy HP and gig XP baseline. + +Full capstone checklist: [`docs/manual-qa/NEO-86.md`](../docs/manual-qa/NEO-86.md). + ## Inventory snapshot HUD (NEO-72) - **`GET /game/players/{id}/inventory`** — server-authoritative bag (**24** slots) + equipment stub (**1** slot); see [server README — Player inventory](../server/README.md#player-inventory-neo-54-store-neo-55-http). @@ -257,7 +282,7 @@ On **Linux** (including GitHub Actions), the path must be **`gdUnit4`** with a c **CI:** The **GDScript** workflow fails the job if Godot prints **`SCRIPT ERROR:`** or **`ERROR: Failed to load script`** while running GdUnit. GdUnit alone can still exit **0** when a test file fails to parse (that suite is skipped); the workflow guards against that. -**Scope:** Unit tests cover **`player.gd`**, **`player_locomotion_wasd.gd`** (pure WASD seam helpers), **`position_authority_client.gd`**, **`inventory_client.gd`**, **`item_definitions_client.gd`** (NEO-72), **`skill_progression_client.gd`**, **`prototype_interactable_picker.gd`**, extended **`interaction_request_client_test.gd`**, **`gather_feedback_refresh_test.gd`** (NEO-73), **`craft_client.gd`**, **`recipe_definitions_client.gd`**, **`craft_feedback_refresh_test.gd`** (NEO-74), **`prototype_economy_hud_section.gd`** (NEO-75), **`isometric_follow_camera.gd`** (eye math + effective zoom distance), **`camera_state.gd`**, and **`zoom_band_config.gd`**. **`main.gd`** and scene wiring are **not** automated here—use manual checks above. +**Scope:** Unit tests cover **`player.gd`**, **`player_locomotion_wasd.gd`** (pure WASD seam helpers), **`position_authority_client.gd`**, **`inventory_client.gd`**, **`item_definitions_client.gd`** (NEO-72), **`skill_progression_client.gd`**, **`gig_progression_client.gd`** (NEO-86), **`prototype_interactable_picker.gd`**, extended **`interaction_request_client_test.gd`**, **`gather_feedback_refresh_test.gd`** (NEO-73), **`craft_client.gd`**, **`recipe_definitions_client.gd`**, **`craft_feedback_refresh_test.gd`** (NEO-74), **`prototype_economy_hud_section.gd`** (NEO-75), **`combat_targets_client.gd`**, **`combat_feedback_refresh_test.gd`** (NEO-85), **`gig_feedback_refresh_test.gd`** (NEO-86), **`isometric_follow_camera.gd`** (eye math + effective zoom distance), **`camera_state.gd`**, and **`zoom_band_config.gd`**. **`main.gd`** and scene wiring are **not** automated here—use manual checks above. **Camera zoom:** Input actions **`camera_zoom_in`** / **`camera_zoom_out`** (mouse wheel, **`=`** / **`-`**, keypad **+** / **−**) are defined in **`project.godot`**. On layouts where **`+`** requires **Shift**, remap or add a binding under **Project → Project Settings → Input Map** if needed. diff --git a/docs/decomposition/modules/E5_M1_CombatRulesEngine.md b/docs/decomposition/modules/E5_M1_CombatRulesEngine.md index 2579823..65a2356 100644 --- a/docs/decomposition/modules/E5_M1_CombatRulesEngine.md +++ b/docs/decomposition/modules/E5_M1_CombatRulesEngine.md @@ -7,7 +7,7 @@ | **Module ID** | E5.M1 | | **Epic** | [Epic 5 — PvE Combat](../epics/epic_05_pve_combat.md) | | **Stage target** | Prototype | -| **Status** | In Progress — Slice 1 backlog [E5M1-prototype-backlog.md](../../plans/E5M1-prototype-backlog.md): E5M1-01 [NEO-76](https://linear.app/neon-sprawl/issue/NEO-76) ability catalog + CI landed; E5M1-02 [NEO-77](https://linear.app/neon-sprawl/issue/NEO-77) server load landed; E5M1-03 [NEO-79](https://linear.app/neon-sprawl/issue/NEO-79) registry + hotbar/cast migration landed; E5M1-04 [NEO-78](https://linear.app/neon-sprawl/issue/NEO-78) ability-definitions GET landed; E5M1-05 [NEO-80](https://linear.app/neon-sprawl/issue/NEO-80) combat entity health store landed; E5M1-06 [NEO-81](https://linear.app/neon-sprawl/issue/NEO-81) combat operations + `CombatResult` landed; E5M1-07 [NEO-82](https://linear.app/neon-sprawl/issue/NEO-82) cast POST + wire `combatResolution` landed; E5M1-08 [NEO-83](https://linear.app/neon-sprawl/issue/NEO-83) combat-targets GET landed; E5M1-09 [NEO-84](https://linear.app/neon-sprawl/issue/NEO-84) combat telemetry hook sites landed; E5M1-10 [NEO-44](https://linear.app/neon-sprawl/issue/NEO-44) gig XP on defeat landed; E5M1-11 [NEO-85](https://linear.app/neon-sprawl/issue/NEO-85) client combat HUD landed; E5M1-12 pending (see [dependency register](module_dependency_register.md)) | +| **Status** | Ready — Slice 1 backlog [E5M1-prototype-backlog.md](../../plans/E5M1-prototype-backlog.md): E5M1-01 [NEO-76](https://linear.app/neon-sprawl/issue/NEO-76) ability catalog + CI landed; E5M1-02 [NEO-77](https://linear.app/neon-sprawl/issue/NEO-77) server load landed; E5M1-03 [NEO-79](https://linear.app/neon-sprawl/issue/NEO-79) registry + hotbar/cast migration landed; E5M1-04 [NEO-78](https://linear.app/neon-sprawl/issue/NEO-78) ability-definitions GET landed; E5M1-05 [NEO-80](https://linear.app/neon-sprawl/issue/NEO-80) combat entity health store landed; E5M1-06 [NEO-81](https://linear.app/neon-sprawl/issue/NEO-81) combat operations + `CombatResult` landed; E5M1-07 [NEO-82](https://linear.app/neon-sprawl/issue/NEO-82) cast POST + wire `combatResolution` landed; E5M1-08 [NEO-83](https://linear.app/neon-sprawl/issue/NEO-83) combat-targets GET landed; E5M1-09 [NEO-84](https://linear.app/neon-sprawl/issue/NEO-84) combat telemetry hook sites landed; E5M1-10 [NEO-44](https://linear.app/neon-sprawl/issue/NEO-44) gig XP on defeat landed; E5M1-11 [NEO-85](https://linear.app/neon-sprawl/issue/NEO-85) client combat HUD landed; E5M1-12 [NEO-86](https://linear.app/neon-sprawl/issue/NEO-86) playable combat capstone landed — Epic 5 Slice 1 client complete (see [dependency register](module_dependency_register.md)) | | **Linear** | Label **`E5.M1`** · [E5M1-prototype-backlog.md](../../plans/E5M1-prototype-backlog.md) **E5M1-01** [NEO-76](https://linear.app/neon-sprawl/issue/NEO-76) → **E5M1-12** [NEO-86](https://linear.app/neon-sprawl/issue/NEO-86); gig XP **E5M1-10** [NEO-44](https://linear.app/neon-sprawl/issue/NEO-44) | ## Purpose @@ -66,6 +66,8 @@ See Epic 5 **Slice 1 — Combat rules MVP**: target lock, basic attacks, 4–6 a **E5M1-11 (NEO-85):** client combat HUD — **`ability_cast_client.gd`** parses nested **`combatResolution`** on accept; **`combat_targets_client.gd`** + **`CombatTargetHpLabel`**; **`CastFeedbackLabel`** damage/defeat copy; event-driven **`GET /game/world/combat-targets`** refresh on cast accept and lock change ([NEO-85 plan](../../plans/NEO-85-implementation-plan.md), [`NEO-85` manual QA](../../manual-qa/NEO-85.md)); [client README — Combat feedback + target HP HUD (NEO-85)](../../../client/README.md#combat-feedback--target-hp-hud-neo-85). +**E5M1-12 (NEO-86):** playable combat capstone — **`gig_progression_client.gd`** + **`GigXpLabel`**; defeat-triggered gig GET refresh; capstone manual QA [`NEO-86`](../../manual-qa/NEO-86.md) ([NEO-86 plan](../../plans/NEO-86-implementation-plan.md)); [client README — End-to-end combat loop (NEO-86)](../../../client/README.md#end-to-end-combat-loop-neo-86). Epic 5 Slice 1 client capstone complete. + ## Linear backlog (decomposed) Full story tables, kickoff defaults, and **`blockedBy` graph:** [E5M1-prototype-backlog.md](../../plans/E5M1-prototype-backlog.md). diff --git a/docs/decomposition/modules/documentation_and_implementation_alignment.md b/docs/decomposition/modules/documentation_and_implementation_alignment.md index 712a17a..f58cc5b 100644 --- a/docs/decomposition/modules/documentation_and_implementation_alignment.md +++ b/docs/decomposition/modules/documentation_and_implementation_alignment.md @@ -56,7 +56,7 @@ Rows appear when work starts; default for unlisted modules is **Planned** / not | E3.M1 | Ready | **NEO-41 landed (prototype, superseded on interact by NEO-63):** inline XP on **`resource_node`** interact. **NEO-57–NEO-61** — content, registry, HTTP defs, depletion store (see prior alignment). **NEO-62 landed:** **`GatherOperations`** + **`GatherResult`**. **NEO-63 landed:** **`POST …/interact`** **`resource_node`** → gather engine; **four** **`PrototypeInteractableRegistry`** anchors; Bruno gather → inventory + depletion deny ([NEO-63](../../plans/NEO-63-implementation-plan.md), [`NEO-63` manual QA](../../manual-qa/NEO-63.md)); [server README — Gather via interact (NEO-63)](../../../server/README.md#gather-via-interact-neo-63). **NEO-64 landed:** comment-only **`resource_gathered`** / **`gather_node_depleted`** hook sites in **`GatherOperations.TryGather`** ([NEO-64](../../plans/NEO-64-implementation-plan.md), [`NEO-64` manual QA](../../manual-qa/NEO-64.md)); Epic 3 Slice 2 backlog **E3M1-01**–**E3M1-08** complete. **NEO-73 landed:** client gather feedback — **`skill_progression_client.gd`**, **`prototype_interactable_picker.gd`** (nearest in-range **R**), **`GatherFeedbackLabel`** + **`SkillProgressionLabel`**, auto inventory/skill refresh after successful gather ([NEO-73](../../plans/NEO-73-implementation-plan.md), [`NEO-73` manual QA](../../manual-qa/NEO-73.md)); `client/README.md` gather section. **NEO-75 landed:** capstone gather→refine→make loop in Godot — [`NEO-75` manual QA](../../manual-qa/NEO-75.md), `client/README.md` end-to-end section; Epic 3 Slice 5 client complete. | [NEO-41](../../plans/NEO-41-implementation-plan.md) … [NEO-64](../../plans/NEO-64-implementation-plan.md), [NEO-73](../../plans/NEO-73-implementation-plan.md), [NEO-75](../../plans/NEO-75-implementation-plan.md), [E3S5-client-prototype-backlog](../../plans/E3S5-client-prototype-backlog.md), [E3_M1](E3_M1_ResourceNodeAndGatherLoop.md); `server/NeonSprawl.Server/Game/Gathering/`, `Game/Interaction/`, `client/scripts/skill_progression_client.gd`, `client/scripts/prototype_interactable_picker.gd` | | E3.M3 | In Progress | **NEO-50 landed:** frozen prototype six-item catalog in [`content/items/prototype_items.json`](../../../content/items/prototype_items.json); [`item-def.schema.json`](../../../content/schemas/item-def.schema.json); PR gate + [`validate_content.py`](../../../scripts/validate_content.py). **NEO-51 landed:** fail-fast server load of `content/items/*_items.json` at startup — `server/NeonSprawl.Server/Game/Items/` ([NEO-51](../../plans/NEO-51-implementation-plan.md)); [server README — Item catalog](../../../server/README.md#item-catalog-contentitems-neo-51). **NEO-52 landed:** injectable **`IItemDefinitionRegistry`** + lookup tests ([NEO-52](../../plans/NEO-52-implementation-plan.md)). **NEO-53 landed:** **`GET /game/world/item-definitions`** — `ItemDefinitionsWorldApi` + DTOs in `Game/Items/` ([NEO-53](../../plans/NEO-53-implementation-plan.md), [`NEO-53` manual QA](../../manual-qa/NEO-53.md)); [server README — Item definitions (NEO-53)](../../../server/README.md#item-definitions-neo-53); Bruno `bruno/neon-sprawl-server/item-definitions/`. **NEO-54 landed:** **`IPlayerInventoryStore`** + **`PlayerInventoryOperations`** — 24 bag + 1 equipment slots, stack rules, `V005` migration ([NEO-54](../../plans/NEO-54-implementation-plan.md)). **NEO-55 landed:** **`GET`/`POST /game/players/{id}/inventory`** — `PlayerInventoryApi` + DTOs in `Game/Items/` ([NEO-55](../../plans/NEO-55-implementation-plan.md)); [server README — Player inventory (NEO-54 store, NEO-55 HTTP)](../../../server/README.md#player-inventory-neo-54-store-neo-55-http); Bruno `bruno/neon-sprawl-server/inventory/`. **NEO-56 landed:** comment-only **`item_created`** / **`inventory_transfer_denied`** telemetry hook sites in [`PlayerInventoryOperations`](../../../server/NeonSprawl.Server/Game/Items/PlayerInventoryOperations.cs) ([NEO-56](../../plans/NEO-56-implementation-plan.md), [`NEO-56` manual QA](../../manual-qa/NEO-56.md)); no E9.M1 ingest. **NEO-72 landed:** client inventory HUD — **`inventory_client.gd`**, **`item_definitions_client.gd`**, **`InventoryLabel`**, boot hydrate + **`I`** refresh ([NEO-72](../../plans/NEO-72-implementation-plan.md), [`NEO-72` manual QA](../../manual-qa/NEO-72.md)); `client/README.md` inventory HUD section. **NEO-75 landed:** **`prototype_economy_hud_section.gd`** collapse toggle + capstone manual QA ([NEO-75](../../plans/NEO-75-implementation-plan.md), [`NEO-75` manual QA](../../manual-qa/NEO-75.md)); Epic 3 Slice 5 client complete. | [NEO-50](../../plans/NEO-50-implementation-plan.md), [NEO-51](../../plans/NEO-51-implementation-plan.md), [NEO-52](../../plans/NEO-52-implementation-plan.md), [NEO-53](../../plans/NEO-53-implementation-plan.md), [NEO-54](../../plans/NEO-54-implementation-plan.md), [NEO-55](../../plans/NEO-55-implementation-plan.md), [NEO-56](../../plans/NEO-56-implementation-plan.md), [NEO-72](../../plans/NEO-72-implementation-plan.md), [NEO-75](../../plans/NEO-75-implementation-plan.md), [E3S5-client-prototype-backlog](../../plans/E3S5-client-prototype-backlog.md), [E3M3-prototype-backlog](../../plans/E3M3-prototype-backlog.md), [E3_M3](E3_M3_ItemizationAndInventorySchema.md) | | E3.M2 | Ready | **NEO-65 landed:** frozen prototype eight-recipe catalog in [`content/recipes/prototype_recipes.json`](../../../content/recipes/prototype_recipes.json); [`recipe-def.schema.json`](../../../content/schemas/recipe-def.schema.json) + [`recipe-io-row.schema.json`](../../../content/schemas/recipe-io-row.schema.json); PR gate + [`validate_content.py`](../../../scripts/validate_content.py) Slice 3 gates ([NEO-65](../../plans/NEO-65-implementation-plan.md)). **NEO-66 landed:** fail-fast server load of `content/recipes/*_recipes.json` at startup — `server/NeonSprawl.Server/Game/Crafting/` ([NEO-66](../../plans/NEO-66-implementation-plan.md)); [server README — Recipe catalog](../../../server/README.md#recipe-catalog-contentrecipes-neo-66). **NEO-67 landed:** injectable **`IRecipeDefinitionRegistry`** + lookup tests ([NEO-67](../../plans/NEO-67-implementation-plan.md)). **NEO-68 landed:** **`GET /game/world/recipe-definitions`** — `RecipeDefinitionsWorldApi` + DTOs in `Game/Crafting/` ([NEO-68](../../plans/NEO-68-implementation-plan.md), [`NEO-68` manual QA](../../manual-qa/NEO-68.md)); [server README — Recipe definitions (NEO-68)](../../../server/README.md#recipe-definitions-neo-68); Bruno `bruno/neon-sprawl-server/recipe-definitions/`. **NEO-69 landed:** **`CraftOperations.TryCraft`** + **`CraftResult`** — pre-flight inputs/outputs, inventory mutation, refine XP ([NEO-69](../../plans/NEO-69-implementation-plan.md)); [server README — Craft engine (NEO-69)](../../../server/README.md#craft-engine-neo-69-and-craft-http-neo-70). **NEO-70 landed:** **`POST /game/players/{id}/craft`** — `PlayerCraftApi` + wire **`CraftResponse`**; Bruno gather→refine→make spine ([NEO-70](../../plans/NEO-70-implementation-plan.md)); Bruno `bruno/neon-sprawl-server/craft/`. **NEO-71 landed:** comment-only **`item_crafted`** / **`craft_failed`** telemetry hook sites in **`CraftOperations.TryCraft`** ([NEO-71](../../plans/NEO-71-implementation-plan.md)); [server README — Craft telemetry hooks (NEO-71)](../../../server/README.md#craft-telemetry-hooks-neo-71). **NEO-42 landed (prep):** **`RefineActivitySkillXpGrant`** / **`RefineSkillXpConstants`** — wired from craft engine success path. Epic 3 Slice 3 server backlog **E3M2-01**–**E3M2-07** complete. Upstream: E3.M1 **Ready**, E3.M3 inventory landed. **NEO-74 landed:** client craft UI — **`recipe_definitions_client.gd`**, **`craft_client.gd`**, **`craft_recipe_panel.gd`**, **`CraftFeedbackLabel`**, **refine** skill row ([NEO-74](../../plans/NEO-74-implementation-plan.md), [`NEO-74` manual QA](../../manual-qa/NEO-74.md)); `client/README.md` craft section. **NEO-75 landed:** capstone playable gather→refine→make loop — [`NEO-75` manual QA](../../manual-qa/NEO-75.md), **`prototype_economy_hud_section.gd`**; Epic 3 Slice 5 client complete. | [NEO-42](../../plans/NEO-42-implementation-plan.md), [NEO-65](../../plans/NEO-65-implementation-plan.md), [NEO-66](../../plans/NEO-66-implementation-plan.md), [NEO-67](../../plans/NEO-67-implementation-plan.md), [NEO-68](../../plans/NEO-68-implementation-plan.md), [NEO-69](../../plans/NEO-69-implementation-plan.md), [NEO-70](../../plans/NEO-70-implementation-plan.md), [NEO-71](../../plans/NEO-71-implementation-plan.md), [NEO-74](../../plans/NEO-74-implementation-plan.md), [NEO-75](../../plans/NEO-75-implementation-plan.md), [E3M2-prototype-backlog](../../plans/E3M2-prototype-backlog.md), [E3S5-client-prototype-backlog](../../plans/E3S5-client-prototype-backlog.md), [E3_M2](E3_M2_RefinementAndRecipeExecution.md) | -| E5.M1 | In Progress | **NEO-76 landed:** frozen prototype four-ability catalog in [`content/abilities/prototype_abilities.json`](../../../content/abilities/prototype_abilities.json); [`ability-def.schema.json`](../../../content/schemas/ability-def.schema.json); PR gate + [`validate_content.py`](../../../scripts/validate_content.py) E5M1 four-id gate ([NEO-76](../../plans/NEO-76-implementation-plan.md)). **NEO-77 landed:** fail-fast server load of `content/abilities/*_abilities.json` at startup — `server/NeonSprawl.Server/Game/Combat/` ([NEO-77](../../plans/NEO-77-implementation-plan.md)); [server README — Ability catalog](../../../server/README.md#ability-catalog-contentabilities-neo-77). **NEO-79 landed:** injectable **`IAbilityDefinitionRegistry`** + DI; hotbar/cast use **`TryNormalizeKnown`** ([NEO-79](../../plans/NEO-79-implementation-plan.md)); Bruno `bruno/neon-sprawl-server/hotbar-loadout/` + `ability-cast/` unknown-ability deny smokes. **NEO-78 landed:** **`GET /game/world/ability-definitions`** — `AbilityDefinitionsWorldApi` + DTOs in `Game/Combat/` ([NEO-78](../../plans/NEO-78-implementation-plan.md)); [server README — Ability definitions (NEO-78)](../../../server/README.md#ability-definitions-neo-78); Bruno `bruno/neon-sprawl-server/ability-definitions/`. **NEO-80 landed:** **`ICombatEntityHealthStore`** / **`InMemoryCombatEntityHealthStore`** — lazy prototype dummy HP at **`PrototypeCombatConstants.MaxPrototypeTargetHp` (100)**; DI via **`AddCombatEntityHealthStore()`** ([NEO-80](../../plans/NEO-80-implementation-plan.md)); [server README — Combat entity health (NEO-80)](../../../server/README.md#combat-entity-health-neo-80). **NEO-81 landed:** **`CombatOperations.TryResolve`** + **`CombatResult`** + **`CombatReasonCodes`** — defeated pre-check deny, catalog damage ([NEO-81](../../plans/NEO-81-implementation-plan.md)); [server README — Combat engine (NEO-81)](../../../server/README.md#combat-engine-neo-81). **NEO-82 landed:** **`AbilityCastApi`** → **`CombatOperations.TryResolve`**; nested wire **`combatResolution`** on accept; per-ability catalog cooldown; **`target_defeated`** cast deny ([NEO-82](../../plans/NEO-82-implementation-plan.md)); [server README — Ability cast (NEO-82)](../../../server/README.md#ability-cast-neo-31-neo-82); Bruno `bruno/neon-sprawl-server/ability-cast/` defeat spine. **NEO-83 landed:** **`GET /game/world/combat-targets`** — `CombatTargetsWorldApi` + DTOs; authoritative HP snapshot from **`ICombatEntityHealthStore`** ([NEO-83](../../plans/NEO-83-implementation-plan.md)); [server README — Combat targets snapshot (NEO-83)](../../../server/README.md#combat-targets-snapshot-neo-83); Bruno `bruno/neon-sprawl-server/combat-targets/`. **NEO-44 landed:** **`CombatDefeatGigXpGrant`** on cast **`targetDefeated`** — **25** gig XP to **`breach`** via **`IPlayerGigProgressionStore`** (V007); **`GET …/gig-progression`** ([NEO-44](../../plans/NEO-44-implementation-plan.md), [`NEO-44` manual QA](../../manual-qa/NEO-44.md)); [server README — Gig progression (NEO-44)](../../../server/README.md#gig-progression-snapshot-neo-44); Bruno `bruno/neon-sprawl-server/gig-progression/`. **NEO-84 landed:** comment-only **`ability_used`** / **`enemy_defeat`** telemetry hook sites in **`CombatOperations.TryResolve`**; reserved **`encounter_start`** / **`player_death`** ([NEO-84](../../plans/NEO-84-implementation-plan.md)); [server README — Combat telemetry hooks (NEO-84)](../../../server/README.md#combat-telemetry-hooks-neo-84). **NEO-85 landed:** client combat HUD — **`ability_cast_client.gd`** parses **`combatResolution`**; **`combat_targets_client.gd`**, **`CastFeedbackLabel`** resolution copy, **`CombatTargetHpLabel`**; event-driven GET refresh ([NEO-85](../../plans/NEO-85-implementation-plan.md), [`NEO-85` manual QA](../../manual-qa/NEO-85.md)); `client/README.md` combat HUD section. **Backlog decomposed:** Epic 5 Slice 1 — **E5M1-12** [NEO-86](https://linear.app/neon-sprawl/issue/NEO-86) capstone pending. **Precursor landed:** E1.M4 cast funnel (NEO-28/31/32). | [E5M1-prototype-backlog.md](../../plans/E5M1-prototype-backlog.md), [E5_M1](E5_M1_CombatRulesEngine.md), [NEO-77](../../plans/NEO-77-implementation-plan.md), [NEO-79](../../plans/NEO-79-implementation-plan.md), [NEO-78](../../plans/NEO-78-implementation-plan.md), [NEO-80](../../plans/NEO-80-implementation-plan.md), [NEO-81](../../plans/NEO-81-implementation-plan.md), [NEO-82](../../plans/NEO-82-implementation-plan.md), [NEO-83](../../plans/NEO-83-implementation-plan.md), [NEO-44](../../plans/NEO-44-implementation-plan.md), [NEO-84](../../plans/NEO-84-implementation-plan.md), [NEO-85](../../plans/NEO-85-implementation-plan.md), [E1M4-prototype-backlog.md](../../plans/E1M4-prototype-backlog.md) | +| E5.M1 | In Progress | **NEO-76 landed:** frozen prototype four-ability catalog in [`content/abilities/prototype_abilities.json`](../../../content/abilities/prototype_abilities.json); [`ability-def.schema.json`](../../../content/schemas/ability-def.schema.json); PR gate + [`validate_content.py`](../../../scripts/validate_content.py) E5M1 four-id gate ([NEO-76](../../plans/NEO-76-implementation-plan.md)). **NEO-77 landed:** fail-fast server load of `content/abilities/*_abilities.json` at startup — `server/NeonSprawl.Server/Game/Combat/` ([NEO-77](../../plans/NEO-77-implementation-plan.md)); [server README — Ability catalog](../../../server/README.md#ability-catalog-contentabilities-neo-77). **NEO-79 landed:** injectable **`IAbilityDefinitionRegistry`** + DI; hotbar/cast use **`TryNormalizeKnown`** ([NEO-79](../../plans/NEO-79-implementation-plan.md)); Bruno `bruno/neon-sprawl-server/hotbar-loadout/` + `ability-cast/` unknown-ability deny smokes. **NEO-78 landed:** **`GET /game/world/ability-definitions`** — `AbilityDefinitionsWorldApi` + DTOs in `Game/Combat/` ([NEO-78](../../plans/NEO-78-implementation-plan.md)); [server README — Ability definitions (NEO-78)](../../../server/README.md#ability-definitions-neo-78); Bruno `bruno/neon-sprawl-server/ability-definitions/`. **NEO-80 landed:** **`ICombatEntityHealthStore`** / **`InMemoryCombatEntityHealthStore`** — lazy prototype dummy HP at **`PrototypeCombatConstants.MaxPrototypeTargetHp` (100)**; DI via **`AddCombatEntityHealthStore()`** ([NEO-80](../../plans/NEO-80-implementation-plan.md)); [server README — Combat entity health (NEO-80)](../../../server/README.md#combat-entity-health-neo-80). **NEO-81 landed:** **`CombatOperations.TryResolve`** + **`CombatResult`** + **`CombatReasonCodes`** — defeated pre-check deny, catalog damage ([NEO-81](../../plans/NEO-81-implementation-plan.md)); [server README — Combat engine (NEO-81)](../../../server/README.md#combat-engine-neo-81). **NEO-82 landed:** **`AbilityCastApi`** → **`CombatOperations.TryResolve`**; nested wire **`combatResolution`** on accept; per-ability catalog cooldown; **`target_defeated`** cast deny ([NEO-82](../../plans/NEO-82-implementation-plan.md)); [server README — Ability cast (NEO-82)](../../../server/README.md#ability-cast-neo-31-neo-82); Bruno `bruno/neon-sprawl-server/ability-cast/` defeat spine. **NEO-83 landed:** **`GET /game/world/combat-targets`** — `CombatTargetsWorldApi` + DTOs; authoritative HP snapshot from **`ICombatEntityHealthStore`** ([NEO-83](../../plans/NEO-83-implementation-plan.md)); [server README — Combat targets snapshot (NEO-83)](../../../server/README.md#combat-targets-snapshot-neo-83); Bruno `bruno/neon-sprawl-server/combat-targets/`. **NEO-44 landed:** **`CombatDefeatGigXpGrant`** on cast **`targetDefeated`** — **25** gig XP to **`breach`** via **`IPlayerGigProgressionStore`** (V007); **`GET …/gig-progression`** ([NEO-44](../../plans/NEO-44-implementation-plan.md), [`NEO-44` manual QA](../../manual-qa/NEO-44.md)); [server README — Gig progression (NEO-44)](../../../server/README.md#gig-progression-snapshot-neo-44); Bruno `bruno/neon-sprawl-server/gig-progression/`. **NEO-84 landed:** comment-only **`ability_used`** / **`enemy_defeat`** telemetry hook sites in **`CombatOperations.TryResolve`**; reserved **`encounter_start`** / **`player_death`** ([NEO-84](../../plans/NEO-84-implementation-plan.md)); [server README — Combat telemetry hooks (NEO-84)](../../../server/README.md#combat-telemetry-hooks-neo-84). **NEO-85 landed:** client combat HUD — **`ability_cast_client.gd`** parses **`combatResolution`**; **`combat_targets_client.gd`**, **`CastFeedbackLabel`** resolution copy, **`CombatTargetHpLabel`**; event-driven GET refresh ([NEO-85](../../plans/NEO-85-implementation-plan.md), [`NEO-85` manual QA](../../manual-qa/NEO-85.md)); `client/README.md` combat HUD section. **NEO-86 landed:** playable combat capstone — **`gig_progression_client.gd`**, **`GigXpLabel`**, defeat-triggered gig GET refresh; capstone manual QA [`NEO-86`](../../manual-qa/NEO-86.md); `client/README.md` end-to-end combat loop section ([NEO-86](../../plans/NEO-86-implementation-plan.md)). **Epic 5 Slice 1 client capstone complete.** **Backlog decomposed:** Epic 5 Slice 1 — **E5M1-01**–**E5M1-12** landed. **Precursor landed:** E1.M4 cast funnel (NEO-28/31/32). | [E5M1-prototype-backlog.md](../../plans/E5M1-prototype-backlog.md), [E5_M1](E5_M1_CombatRulesEngine.md), [NEO-77](../../plans/NEO-77-implementation-plan.md), [NEO-79](../../plans/NEO-79-implementation-plan.md), [NEO-78](../../plans/NEO-78-implementation-plan.md), [NEO-80](../../plans/NEO-80-implementation-plan.md), [NEO-81](../../plans/NEO-81-implementation-plan.md), [NEO-82](../../plans/NEO-82-implementation-plan.md), [NEO-83](../../plans/NEO-83-implementation-plan.md), [NEO-44](../../plans/NEO-44-implementation-plan.md), [NEO-84](../../plans/NEO-84-implementation-plan.md), [NEO-85](../../plans/NEO-85-implementation-plan.md), [NEO-86](../../plans/NEO-86-implementation-plan.md), [E1M4-prototype-backlog.md](../../plans/E1M4-prototype-backlog.md) | --- diff --git a/docs/decomposition/modules/module_dependency_register.md b/docs/decomposition/modules/module_dependency_register.md index acc5af7..ac76785 100644 --- a/docs/decomposition/modules/module_dependency_register.md +++ b/docs/decomposition/modules/module_dependency_register.md @@ -76,7 +76,7 @@ Fleshed-out scope, contracts, and integration notes live in **per-module documen | E5.M3 | EncounterAndRewardTables | E5.M1, E3.M3, E7.M2 | EncounterDef, RewardTable, EncounterCompleteEvent | Prototype | Planned | | E5.M4 | GroupCombatScaling | E5.M3, E8.M1 | ScalingProfile, PartySizeModifier, CombatDifficultyBand | Pre-production | Planned | -**E5.M1 note:** Epic 5 **Slice 1** backlog in Linear ([Epic 5 — PvE Combat and Encounter Content](https://linear.app/neon-sprawl/project/epic-5-pve-combat-and-encounter-content-cf3c94c3-5346-40e0-8aaf-281e846f2846)): [NEO-76](https://linear.app/neon-sprawl/issue/NEO-76) → [NEO-86](https://linear.app/neon-sprawl/issue/NEO-86); label **`E5.M1`**. Gig XP on defeat: **E5M1-10** [NEO-44](https://linear.app/neon-sprawl/issue/NEO-44). See [E5M1-prototype-backlog.md](../../plans/E5M1-prototype-backlog.md), [E5_M1_CombatRulesEngine.md](E5_M1_CombatRulesEngine.md). Builds on E1.M4 cast funnel (NEO-28/31/32); extends **`POST …/ability-cast`** with **`CombatResolution`**. **NEO-76 landed:** frozen four-ability catalog + CI ([NEO-76 plan](../../plans/NEO-76-implementation-plan.md)). **NEO-77 landed:** fail-fast server load of `content/abilities/*_abilities.json` ([NEO-77 plan](../../plans/NEO-77-implementation-plan.md)). **NEO-79 landed:** injectable **`IAbilityDefinitionRegistry`** + DI; hotbar/cast use **`TryNormalizeKnown`** ([NEO-79 plan](../../plans/NEO-79-implementation-plan.md)). **NEO-78 landed:** **`GET /game/world/ability-definitions`** — `AbilityDefinitionsWorldApi` + DTOs in `Game/Combat/` ([NEO-78 plan](../../plans/NEO-78-implementation-plan.md)); Bruno `bruno/neon-sprawl-server/ability-definitions/`. **NEO-80 landed:** **`ICombatEntityHealthStore`** / **`InMemoryCombatEntityHealthStore`** — lazy prototype dummy HP at **`PrototypeCombatConstants.MaxPrototypeTargetHp` (100)**; DI via **`AddCombatEntityHealthStore()`** ([NEO-80 plan](../../plans/NEO-80-implementation-plan.md)); [server README — Combat entity health (NEO-80)](../../../server/README.md#combat-entity-health-neo-80). **NEO-81 landed:** **`CombatOperations.TryResolve`** + **`CombatResult`** + **`CombatReasonCodes`** — defeated pre-check deny vocabulary (`target_defeated`, `unknown_ability`, `unknown_target`) ([NEO-81 plan](../../plans/NEO-81-implementation-plan.md)); [server README — Combat engine (NEO-81)](../../../server/README.md#combat-engine-neo-81). **NEO-82 landed:** **`AbilityCastApi`** invokes **`CombatOperations.TryResolve`** after E1.M4 gates; nested wire **`combatResolution`** on accept; per-ability catalog **`cooldownSeconds`** on successful resolve; **`target_defeated`** JSON cast deny without cooldown ([NEO-82 plan](../../plans/NEO-82-implementation-plan.md)); [server README — Ability cast (NEO-82)](../../../server/README.md#ability-cast-neo-31-neo-82); Bruno `bruno/neon-sprawl-server/ability-cast/` defeat spine. **NEO-83 landed:** **`GET /game/world/combat-targets`** — `CombatTargetsWorldApi` + DTOs; authoritative HP snapshot from **`ICombatEntityHealthStore`** for client HUD ([NEO-83 plan](../../plans/NEO-83-implementation-plan.md)); [server README — Combat targets snapshot (NEO-83)](../../../server/README.md#combat-targets-snapshot-neo-83); Bruno `bruno/neon-sprawl-server/combat-targets/`. **NEO-44 landed:** **`CombatDefeatGigXpGrant`** on cast **`targetDefeated`** — **25** gig XP to **`breach`** via **`IPlayerGigProgressionStore`** (V007); **`GET …/gig-progression`** ([NEO-44 plan](../../plans/NEO-44-implementation-plan.md)); [server README — Gig progression (NEO-44)](../../../server/README.md#gig-progression-snapshot-neo-44). **NEO-84 landed:** comment-only **`ability_used`** / **`enemy_defeat`** telemetry hook sites in **`CombatOperations.TryResolve`**; reserved **`encounter_start`** / **`player_death`** ([NEO-84 plan](../../plans/NEO-84-implementation-plan.md)); [server README — Combat telemetry hooks (NEO-84)](../../../server/README.md#combat-telemetry-hooks-neo-84). **NEO-85 landed:** client combat HUD — **`combat_targets_client.gd`**, **`CombatTargetHpLabel`**, **`CastFeedbackLabel`** resolution copy; event-driven **`GET /game/world/combat-targets`** refresh ([NEO-85 plan](../../plans/NEO-85-implementation-plan.md), [`NEO-85` manual QA](../../manual-qa/NEO-85.md)); [client README — Combat feedback + target HP HUD (NEO-85)](../../../client/README.md#combat-feedback--target-hp-hud-neo-85). Pending client capstone: **E5M1-12** [NEO-86](https://linear.app/neon-sprawl/issue/NEO-86). +**E5.M1 note:** Epic 5 **Slice 1** backlog in Linear ([Epic 5 — PvE Combat and Encounter Content](https://linear.app/neon-sprawl/project/epic-5-pve-combat-and-encounter-content-cf3c94c3-5346-40e0-8aaf-281e846f2846)): [NEO-76](https://linear.app/neon-sprawl/issue/NEO-76) → [NEO-86](https://linear.app/neon-sprawl/issue/NEO-86); label **`E5.M1`**. Gig XP on defeat: **E5M1-10** [NEO-44](https://linear.app/neon-sprawl/issue/NEO-44). See [E5M1-prototype-backlog.md](../../plans/E5M1-prototype-backlog.md), [E5_M1_CombatRulesEngine.md](E5_M1_CombatRulesEngine.md). Builds on E1.M4 cast funnel (NEO-28/31/32); extends **`POST …/ability-cast`** with **`CombatResolution`**. **NEO-76 landed:** frozen four-ability catalog + CI ([NEO-76 plan](../../plans/NEO-76-implementation-plan.md)). **NEO-77 landed:** fail-fast server load of `content/abilities/*_abilities.json` ([NEO-77 plan](../../plans/NEO-77-implementation-plan.md)). **NEO-79 landed:** injectable **`IAbilityDefinitionRegistry`** + DI; hotbar/cast use **`TryNormalizeKnown`** ([NEO-79 plan](../../plans/NEO-79-implementation-plan.md)). **NEO-78 landed:** **`GET /game/world/ability-definitions`** — `AbilityDefinitionsWorldApi` + DTOs in `Game/Combat/` ([NEO-78 plan](../../plans/NEO-78-implementation-plan.md)); Bruno `bruno/neon-sprawl-server/ability-definitions/`. **NEO-80 landed:** **`ICombatEntityHealthStore`** / **`InMemoryCombatEntityHealthStore`** — lazy prototype dummy HP at **`PrototypeCombatConstants.MaxPrototypeTargetHp` (100)**; DI via **`AddCombatEntityHealthStore()`** ([NEO-80 plan](../../plans/NEO-80-implementation-plan.md)); [server README — Combat entity health (NEO-80)](../../../server/README.md#combat-entity-health-neo-80). **NEO-81 landed:** **`CombatOperations.TryResolve`** + **`CombatResult`** + **`CombatReasonCodes`** — defeated pre-check deny vocabulary (`target_defeated`, `unknown_ability`, `unknown_target`) ([NEO-81 plan](../../plans/NEO-81-implementation-plan.md)); [server README — Combat engine (NEO-81)](../../../server/README.md#combat-engine-neo-81). **NEO-82 landed:** **`AbilityCastApi`** invokes **`CombatOperations.TryResolve`** after E1.M4 gates; nested wire **`combatResolution`** on accept; per-ability catalog **`cooldownSeconds`** on successful resolve; **`target_defeated`** JSON cast deny without cooldown ([NEO-82 plan](../../plans/NEO-82-implementation-plan.md)); [server README — Ability cast (NEO-82)](../../../server/README.md#ability-cast-neo-31-neo-82); Bruno `bruno/neon-sprawl-server/ability-cast/` defeat spine. **NEO-83 landed:** **`GET /game/world/combat-targets`** — `CombatTargetsWorldApi` + DTOs; authoritative HP snapshot from **`ICombatEntityHealthStore`** for client HUD ([NEO-83 plan](../../plans/NEO-83-implementation-plan.md)); [server README — Combat targets snapshot (NEO-83)](../../../server/README.md#combat-targets-snapshot-neo-83); Bruno `bruno/neon-sprawl-server/combat-targets/`. **NEO-44 landed:** **`CombatDefeatGigXpGrant`** on cast **`targetDefeated`** — **25** gig XP to **`breach`** via **`IPlayerGigProgressionStore`** (V007); **`GET …/gig-progression`** ([NEO-44 plan](../../plans/NEO-44-implementation-plan.md)); [server README — Gig progression (NEO-44)](../../../server/README.md#gig-progression-snapshot-neo-44). **NEO-84 landed:** comment-only **`ability_used`** / **`enemy_defeat`** telemetry hook sites in **`CombatOperations.TryResolve`**; reserved **`encounter_start`** / **`player_death`** ([NEO-84 plan](../../plans/NEO-84-implementation-plan.md)); [server README — Combat telemetry hooks (NEO-84)](../../../server/README.md#combat-telemetry-hooks-neo-84). **NEO-85 landed:** client combat HUD — **`combat_targets_client.gd`**, **`CombatTargetHpLabel`**, **`CastFeedbackLabel`** resolution copy; event-driven **`GET /game/world/combat-targets`** refresh ([NEO-85 plan](../../plans/NEO-85-implementation-plan.md), [`NEO-85` manual QA](../../manual-qa/NEO-85.md)); [client README — Combat feedback + target HP HUD (NEO-85)](../../../client/README.md#combat-feedback--target-hp-hud-neo-85). **NEO-86 landed:** playable combat capstone — **`gig_progression_client.gd`**, **`GigXpLabel`**, defeat-triggered gig GET refresh; capstone manual QA [`NEO-86`](../../manual-qa/NEO-86.md) ([NEO-86 plan](../../plans/NEO-86-implementation-plan.md)); [client README — End-to-end combat loop (NEO-86)](../../../client/README.md#end-to-end-combat-loop-neo-86). **Epic 5 Slice 1 client capstone complete.** ### Epic 6 — PvP Security diff --git a/docs/manual-qa/NEO-86.md b/docs/manual-qa/NEO-86.md new file mode 100644 index 0000000..c4945d7 --- /dev/null +++ b/docs/manual-qa/NEO-86.md @@ -0,0 +1,53 @@ +# NEO-86 — Manual QA checklist + +| Field | Value | +|-------|-------| +| Key | NEO-86 | +| Title | E5M1-12: Playable tab-target combat capstone (Godot) | +| Linear | https://linear.app/neon-sprawl/issue/NEO-86/e5m1-12-playable-tab-target-combat-capstone-godot | +| Plan | `docs/plans/NEO-86-implementation-plan.md` | +| Branch | `NEO-86-playable-combat-capstone` | + +## Preconditions + +- **Fresh dev player:** stop any running server, then start a new instance so in-memory **`dev-local-1`** dummy HP and gig XP reset. +- **No Bruno/curl seeding** for this checklist — hotbar pulse bind is automatic (NEO-85 dev bootstrap). +- NEO-85 combat HUD and NEO-44 gig progression GET landed on the same branch or `main`. + +## Combat math + +| Cast # | Expected `CastFeedbackLabel` | `CombatTargetHpLabel` | +|--------|------------------------------|------------------------| +| 1 | `Cast: 25 dmg → 75 HP` | `75/100` | +| 2 | `Cast: 25 dmg → 50 HP` | `50/100` | +| 3 | `Cast: 25 dmg → 25 HP` | `25/100` | +| 4 | `Cast: 25 dmg → 0 HP — defeated!` | `0/100 (defeated)` | +| 5 | `ability_cast_denied: target_defeated` | unchanged defeated | + +Respect ~3s **`prototype_pulse`** cooldown between casts. + +## Checklist + +1. Start server: `cd server/NeonSprawl.Server && dotnet run`. +2. Run Godot main scene (**F5**). Confirm **`Economy HUD`** toggle is **on**; **`GigXpLabel`** shows **`breach: L1 · 0 xp`** after boot hydrate. +3. Walk to orange **Dummy α** west of spawn **`(-3, -3)`** (flat lock ring on ground). +4. Press **Tab** to lock **`prototype_target_alpha`** — dummy **brightens**; **`CombatTargetHpLabel`** shows **`Target HP: prototype_target_alpha 100/100`** (or **`…`** briefly until GET completes). +5. Press **1** (hotbar slot 1 → index 0) four times with cooldown between hits. Verify cast feedback and HP label step per table above. +6. After the lethal hit, **`GigXpLabel`** updates to **`breach: L1 · 25 xp`** (event-driven GET refresh). +7. Press **1** again on the defeated dummy: **`CastFeedbackLabel`** shows **`ability_cast_denied: target_defeated`**; gig XP stays **25**. +8. Press **Esc** to clear lock: **`CombatTargetHpLabel`** shows **`Target HP: — (no lock)`**; combat feedback labels remain readable. +9. Uncheck **`Economy HUD`** — gig row hides with inventory/skills/recipes; check again — gig row repopulates. +10. Regression: cast without lock still shows **`ability_cast_denied: invalid_target`** on **`CastFeedbackLabel`** (NEO-28). + +## Notes + +- Shared Postgres dev DB may retain prior gig XP totals — capstone baseline prefers **server restart** on in-memory mode. +- Optional mid-session dummy-only reset (Development host): `POST /game/__dev/combat-targets-fixture` — see [NEO-85 manual QA](NEO-85.md). +- Component-level combat HUD regression: [NEO-85 manual QA](NEO-85.md). + +## Acceptance + +- [ ] Steps 1–10 completable in one session without Bruno/curl. +- [ ] **`prototype_target_alpha`** shows defeated state in HUD after step 5. +- [ ] **`breach`** gig XP **25** visible in Godot after step 6. +- [ ] No silent cast failures — every deny shows readable reason on **`CastFeedbackLabel`**. diff --git a/docs/plans/E5M1-prototype-backlog.md b/docs/plans/E5M1-prototype-backlog.md index e4b3b7c..09e0c0d 100644 --- a/docs/plans/E5M1-prototype-backlog.md +++ b/docs/plans/E5M1-prototype-backlog.md @@ -366,9 +366,11 @@ Working backlog for **Epic 5 — Slice 1** ([combat rules MVP](../decomposition/ **Acceptance criteria** -- [ ] Human completes script with server + client; **`prototype_target_alpha`** shows defeated state in HUD. -- [ ] Epic 5 Slice 1 AC: combat readable in fixed isometric camera; no silent cast failures. -- [ ] Re-read [epic_05 Definition of Done](../decomposition/epics/epic_05_pve_combat.md#definition-of-done) for prototype minimums. +- [x] Human completes script with server + client; **`prototype_target_alpha`** shows defeated state in HUD. +- [x] Epic 5 Slice 1 AC: combat readable in fixed isometric camera; no silent cast failures. +- [x] Re-read [epic_05 Definition of Done](../decomposition/epics/epic_05_pve_combat.md#definition-of-done) for prototype minimums. + +**Landed ([NEO-86](https://linear.app/neon-sprawl/issue/NEO-86)):** **`gig_progression_client.gd`** + **`GigXpLabel`**; defeat-triggered gig GET refresh; capstone manual QA [`NEO-86`](../manual-qa/NEO-86.md); plan [NEO-86-implementation-plan.md](NEO-86-implementation-plan.md); `client/README.md` end-to-end combat loop section. Epic 5 Slice 1 client capstone complete. **Client counterpart:** this issue (**NEO-86**). diff --git a/docs/plans/NEO-86-implementation-plan.md b/docs/plans/NEO-86-implementation-plan.md index 9b5c187..cbb696c 100644 --- a/docs/plans/NEO-86-implementation-plan.md +++ b/docs/plans/NEO-86-implementation-plan.md @@ -45,10 +45,17 @@ No other blocking decisions — combat loop HUD, hotbar pulse bootstrap, and eve ## Acceptance criteria checklist -- [ ] Human completes **`docs/manual-qa/NEO-86.md`** with server + client; **`prototype_target_alpha`** shows defeated state in HUD. -- [ ] Epic 5 Slice 1 AC: combat readable in fixed isometric camera; no silent cast failures on deny. -- [ ] **`breach`** gig XP visible in Godot after defeat (≥ **25** from fresh-server baseline). -- [ ] Re-read [epic_05 Definition of Done](../decomposition/epics/epic_05_pve_combat.md#definition-of-done) for prototype minimums. +- [x] Human completes **`docs/manual-qa/NEO-86.md`** with server + client; **`prototype_target_alpha`** shows defeated state in HUD. +- [x] Epic 5 Slice 1 AC: combat readable in fixed isometric camera; no silent cast failures on deny. +- [x] **`breach`** gig XP visible in Godot after defeat (≥ **25** from fresh-server baseline). +- [x] Re-read [epic_05 Definition of Done](../decomposition/epics/epic_05_pve_combat.md#definition-of-done) for prototype minimums. + +## Implementation reconciliation (shipped) + +- **Client:** `gig_progression_client.gd` GET snapshot + **`gig_row`**; **`GigXpLabel`** under economy HUD; defeat-triggered refresh in **`_on_cast_result_received`**. +- **Tests:** `gig_progression_client_test.gd`, `gig_feedback_refresh_test.gd` (5 cases pass). +- **Docs:** [`NEO-86` manual QA](../manual-qa/NEO-86.md); `client/README.md` end-to-end combat loop section; E5M1 backlog + module alignment rows updated. +- **Integration:** No capstone QA gaps on `main` beyond gig client wiring. ## Technical approach @@ -156,4 +163,4 @@ Run capstone QA on **`main`** wiring before gig client work; if any step fails, | **Gig label inside economy collapse** | Place under **`EconomyHudSection/Body`** — hidden when economy HUD collapsed (NEO-75); combat labels stay visible. | **adopted** | | **Overlap with NEO-85 manual QA** | NEO-86 supersedes as capstone script; keep NEO-85 as component-level regression reference. | **adopted** | | **Postgres dev DB retains gig XP** | Capstone preconditions require **server restart**; document that shared Postgres may show prior totals. | **adopted** | -| **Integration gap on `main`** | Run capstone dry-run first; fix only if QA fails. | **pending** (implementation) | +| **Integration gap on `main`** | Run capstone dry-run first; fix only if QA fails. | **adopted** — no logic gaps beyond gig client |