NEO-123: Add capstone manual QA and onboarding quest loop docs.
Ship four-quest Godot session script (Shift+Q catalog accept order, idempotency steps), client README capstone section, and align NEO-122 component QA with catalog-order picker behavior.pull/162/head
parent
4cfec3ac7f
commit
ec71fba260
|
|
@ -239,6 +239,32 @@ Full checklist: [`docs/manual-qa/NEO-110.md`](../docs/manual-qa/NEO-110.md).
|
||||||
|
|
||||||
Full checklist: [`docs/manual-qa/NEO-122.md`](../docs/manual-qa/NEO-122.md).
|
Full checklist: [`docs/manual-qa/NEO-122.md`](../docs/manual-qa/NEO-122.md).
|
||||||
|
|
||||||
|
## End-to-end onboarding quest loop (NEO-123)
|
||||||
|
|
||||||
|
Epic 7 Slice 1 capstone — complete all four prototype quests (three onboarding intros + operator chain) **in Godot** without Bruno.
|
||||||
|
|
||||||
|
**Flow:** fresh server restart → **Q** gather intro → **Shift+Q** combat intro → **Shift+Q** refine intro → **Shift+Q** operator chain → four chain steps → Godot restart idempotency.
|
||||||
|
|
||||||
|
| Step | Input / trigger | HUD / server outcome |
|
||||||
|
|------|-----------------|----------------------|
|
||||||
|
| Boot | Godot **F5** + fresh server | Four quests **`not started`**; empty bag |
|
||||||
|
| Gather intro | **Q** + **R** at nodes (×3 scrap) | Salvage Run **`active`** → **`completed`** |
|
||||||
|
| Combat intro | **Shift+Q** + defeat ×3 NPCs | Clear the Pocket **`completed`**; encounter **`completed (3/3)`**; **`contract_handoff_token`** in bag |
|
||||||
|
| Refine intro | **Shift+Q** + craft **`refine_scrap_standard`** | Refine Stock **`completed`** |
|
||||||
|
| Operator chain | **Shift+Q** + chain objectives | Operator Chain **`active step 1…4`** → **`completed`** when token held |
|
||||||
|
| Idempotency | Stop Godot + **F5** (server still running) | All four quests still **`completed`** |
|
||||||
|
| Duplicate accept | **Q** / **Shift+Q** on finished quests | **`already_completed`** / **`no eligible quest`**; HUD unchanged |
|
||||||
|
|
||||||
|
**Accept order note:** **Shift+Q** uses quest-definitions **catalog order** (ordinal `id`). After gather intro completes, combat intro is offered before refine intro — see [`docs/manual-qa/NEO-123.md`](../docs/manual-qa/NEO-123.md).
|
||||||
|
|
||||||
|
**Cross-links:** [NEO-112](../docs/plans/NEO-112-implementation-plan.md) catalog · [NEO-118](../docs/plans/NEO-118-implementation-plan.md) objective wiring · [NEO-119](../docs/plans/NEO-119-implementation-plan.md) quest-progress GET · [NEO-120](../docs/plans/NEO-120-implementation-plan.md) accept POST · [NEO-122](../docs/manual-qa/NEO-122.md) HUD components · [NEO-75](../docs/manual-qa/NEO-75.md) economy craft · [NEO-111](../docs/manual-qa/NEO-111.md) combat token loot.
|
||||||
|
|
||||||
|
**Scripts:** `quest_progress_client.gd`, `quest_definitions_client.gd`, `quest_hud_controller.gd`, `encounter_progress_client.gd`, `inventory_client.gd`, `craft_client.gd`, `ability_cast_client.gd` — wired from `main.gd`.
|
||||||
|
|
||||||
|
**Preconditions:** **Server restart** before capstone run resets quest progress, inventory, encounter state, and resource nodes.
|
||||||
|
|
||||||
|
Full capstone checklist: [`docs/manual-qa/NEO-123.md`](../docs/manual-qa/NEO-123.md).
|
||||||
|
|
||||||
## End-to-end encounter clear loop (NEO-111)
|
## End-to-end encounter clear loop (NEO-111)
|
||||||
|
|
||||||
Epic 5 Slice 3 capstone — defeat all three prototype NPCs, receive loot + quest token **once**, verify inventory **in Godot** without Bruno.
|
Epic 5 Slice 3 capstone — defeat all three prototype NPCs, receive loot + quest token **once**, verify inventory **in Godot** without Bruno.
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
| **Q** accept gather | **`Intro: Salvage Run: active step 1`** | **`Quest accept: Intro: Salvage Run accepted`** |
|
| **Q** accept gather | **`Intro: Salvage Run: active step 1`** | **`Quest accept: Intro: Salvage Run accepted`** |
|
||||||
| Gather scrap (**R** on resource node ×3) | Gather objective counter increases (e.g. **`gather_intro_obj_scrap=3`**) | unchanged |
|
| Gather scrap (**R** on resource node ×3) | Gather objective counter increases (e.g. **`gather_intro_obj_scrap=3`**) | unchanged |
|
||||||
| Gather quest completes | **`Intro: Salvage Run: completed`** | unchanged |
|
| Gather quest completes | **`Intro: Salvage Run: completed`** | unchanged |
|
||||||
| **Shift+Q** accept refine (after gather complete) | **`Intro: Refine Stock: active step 1`** | **`Quest accept: Intro: Refine Stock accepted`** |
|
| **Shift+Q** after gather complete (catalog order) | **`Intro: Clear the Pocket: active`** — combat sorts before refine | **`Quest accept: Intro: Clear the Pocket accepted`** |
|
||||||
| Craft **`refine_scrap_standard`** (Economy HUD) | Refine quest completes when recipe succeeds | unchanged |
|
| Craft **`refine_scrap_standard`** (Economy HUD) | Refine quest completes when recipe succeeds | unchanged |
|
||||||
| Duplicate **Q** on gather | Gather row stays **`completed`** | **`Quest accept: denied — already_completed`** (or **`already_active`**) |
|
| Duplicate **Q** on gather | Gather row stays **`completed`** | **`Quest accept: denied — already_completed`** (or **`already_active`**) |
|
||||||
|
|
||||||
|
|
@ -33,9 +33,9 @@
|
||||||
3. Press **Q**. Verify gather intro becomes **`active step 1`** and accept feedback shows success.
|
3. Press **Q**. Verify gather intro becomes **`active step 1`** and accept feedback shows success.
|
||||||
4. Gather scrap until gather quest completes (resource node **R**). Verify counter updates on **`QuestProgressLabel`** after each successful gather (may lag one GET).
|
4. Gather scrap until gather quest completes (resource node **R**). Verify counter updates on **`QuestProgressLabel`** after each successful gather (may lag one GET).
|
||||||
5. Press **Shift+Q** before gather is complete — verify **`Quest accept: denied — prerequisite_incomplete`** for refine (or **`no eligible quest`** if refine is not yet eligible).
|
5. Press **Shift+Q** before gather is complete — verify **`Quest accept: denied — prerequisite_incomplete`** for refine (or **`no eligible quest`** if refine is not yet eligible).
|
||||||
6. After gather completes, press **Shift+Q**. Verify refine quest becomes **`active`**.
|
6. After gather completes, press **Shift+Q**. Verify **combat** intro becomes **`active`** (catalog order — combat before refine). Component refine/craft path: complete combat first, then repeat **Shift+Q** for refine; see [NEO-123 capstone](NEO-123.md) for full four-quest order.
|
||||||
7. Open **Economy HUD** recipe panel — **Refine Scrap (Standard)** is the **first** row (scroll starts at top). Craft when **≥5** scrap in bag.
|
7. Open **Economy HUD** recipe panel — **Refine Scrap (Standard)** is the **first** row (scroll starts at top). After combat intro is **`completed`** and refine intro is **`active`**, craft when **≥5** scrap in bag.
|
||||||
8. Craft **`refine_scrap_standard`** with Economy HUD open. Verify refine quest **`completed`** after successful craft.
|
8. Craft **`refine_scrap_standard`** with Economy HUD open. Verify refine quest **`completed`** after successful craft (requires refine intro **`active`** from step 6 follow-up **Shift+Q**).
|
||||||
9. Press **Q** again on already-completed gather. Verify deny feedback on **`QuestAcceptFeedbackLabel`** without Bruno.
|
9. Press **Q** again on already-completed gather. Verify deny feedback on **`QuestAcceptFeedbackLabel`** without Bruno.
|
||||||
10. Optional: stop server while Godot running, press **Q** — verify **`Quests: error — …`** or **`Quest accept: failed — …`** visible on HUD.
|
10. Optional: stop server while Godot running, press **Q** — verify **`Quests: error — …`** or **`Quest accept: failed — …`** visible on HUD.
|
||||||
11. Optional: block **`GET /game/world/quest-definitions`** only while progress GET succeeds — verify **`definitions error — …`** under **`QuestProgressLabel`** with raw quest ids as fallback.
|
11. Optional: block **`GET /game/world/quest-definitions`** only while progress GET succeeds — verify **`definitions error — …`** under **`QuestProgressLabel`** with raw quest ids as fallback.
|
||||||
|
|
@ -43,8 +43,8 @@
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- Combat intro (**`prototype_quest_combat_intro`**) has no prerequisites — **Shift+Q** may offer it before refine if gather is still active; server deny is authoritative when prerequisites block accept.
|
- **Shift+Q** uses quest-definitions **catalog order** (ordinal `id`): after gather intro completes, **combat** intro is offered before **refine** intro. Server deny is authoritative when prerequisites block accept.
|
||||||
- Full four-quest chain capstone: [NEO-123 manual QA](NEO-123.md).
|
- Full four-quest chain capstone (supersedes partial intro path here): [NEO-123 manual QA](NEO-123.md).
|
||||||
- Encounter progress HUD regression: [NEO-110 manual QA](NEO-110.md).
|
- Encounter progress HUD regression: [NEO-110 manual QA](NEO-110.md).
|
||||||
|
|
||||||
## Acceptance
|
## Acceptance
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
# NEO-123 — Manual QA checklist
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Key | NEO-123 |
|
||||||
|
| Title | E7M1-12: Playable onboarding quest chain capstone (Godot) |
|
||||||
|
| Linear | https://linear.app/neon-sprawl/issue/NEO-123/e7m1-12-playable-onboarding-quest-chain-capstone-godot |
|
||||||
|
| Plan | `docs/plans/NEO-123-implementation-plan.md` |
|
||||||
|
| Branch | `NEO-123-playable-onboarding-quest-chain-capstone` |
|
||||||
|
|
||||||
|
## Preconditions
|
||||||
|
|
||||||
|
- **Fresh dev player:** stop any running server, then start a new instance so in-memory **`dev-local-1`** quest progress, inventory, encounter progress, NPC HP, and resource-node depletion reset.
|
||||||
|
- **No Bruno/curl** for this checklist — accept uses **Q** / **Shift+Q**; gameplay uses **R**, **Tab** + **1**, and Economy HUD **Craft** buttons only.
|
||||||
|
- NEO-112–NEO-122 quest spine and NEO-75/NEO-111 economy/combat capstones landed on `main`.
|
||||||
|
- **`Economy HUD`** toggle **on** for craft and inventory verification.
|
||||||
|
|
||||||
|
## Quest catalog (frozen)
|
||||||
|
|
||||||
|
| Quest id | Display name | Prerequisites | Objective |
|
||||||
|
|----------|--------------|---------------|-----------|
|
||||||
|
| `prototype_quest_gather_intro` | Intro: Salvage Run | none | gather **3** `scrap_metal_bulk` |
|
||||||
|
| `prototype_quest_combat_intro` | Intro: Clear the Pocket | none | `encounter_complete` **`prototype_combat_pocket`** |
|
||||||
|
| `prototype_quest_refine_intro` | Intro: Refine Stock | gather intro | craft **`refine_scrap_standard`** ×1 |
|
||||||
|
| `prototype_quest_operator_chain` | Operator Chain | all three intros | gather ×5 → refine ×1 → **`make_field_stim_mk0`** ×1 → hold **`contract_handoff_token`** ×1 |
|
||||||
|
|
||||||
|
## Accept key contract
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
|-----|--------|
|
||||||
|
| **Q** | Accept **`prototype_quest_gather_intro`** |
|
||||||
|
| **Shift+Q** | First catalog-order **`not_started`** quest with all **`prerequisiteQuestIds`** **`completed`** |
|
||||||
|
|
||||||
|
**Catalog order (ordinal `id`):** combat → gather → operator chain → refine. After gather intro completes, **Shift+Q** accepts **combat** (not refine). After combat completes, **Shift+Q** accepts **refine**. After all three intros complete, **Shift+Q** accepts **operator chain**.
|
||||||
|
|
||||||
|
## Resource node anchors (gather)
|
||||||
|
|
||||||
|
| Node id | Anchor | Yield per **R** |
|
||||||
|
|---------|--------|-----------------|
|
||||||
|
| `prototype_resource_node_alpha` | **(12, −6)** | +1 scrap |
|
||||||
|
| `prototype_subsurface_vein_beta` | **(18, −6)** | +2 scrap |
|
||||||
|
| `prototype_bio_mat_gamma` | **(12, 0)** | +3 scrap |
|
||||||
|
| `prototype_urban_bulk_delta` | **(18, 0)** | +5 scrap |
|
||||||
|
|
||||||
|
Nodes allow multiple gathers (`maxGathers` **10** each). Quest gather counters credit **scrap quantity granted**, not gather event count.
|
||||||
|
|
||||||
|
## Combat archetypes (defeat order flexible)
|
||||||
|
|
||||||
|
| Archetype | Instance id | Marker | Pulses to defeat |
|
||||||
|
|-----------|-------------|--------|------------------|
|
||||||
|
| Melee | `prototype_npc_melee` | orange west **`(-3, -3)`** | 4 |
|
||||||
|
| Ranged | `prototype_npc_ranged` | purple SE **`(3, 3)`** | 4 |
|
||||||
|
| Elite | `prototype_npc_elite` | gold origin **`(0, 0)`** | 8 |
|
||||||
|
|
||||||
|
Player casts **`prototype_pulse`** (**25** damage, ~**3 s** cooldown).
|
||||||
|
|
||||||
|
## Expected quest HUD progression
|
||||||
|
|
||||||
|
| Phase | `QuestProgressLabel` (high level) | `QuestAcceptFeedbackLabel` |
|
||||||
|
|-------|-----------------------------------|----------------------------|
|
||||||
|
| Boot | All four **`not started`** | **`Quest accept: — (Q gather / Shift+Q next)`** |
|
||||||
|
| Gather intro | Salvage Run **`active step 1`** → **`completed`** | **`accepted`** on **Q** |
|
||||||
|
| Combat intro | Clear the Pocket **`active`** → **`completed`** | **`accepted`** on **Shift+Q** |
|
||||||
|
| Refine intro | Refine Stock **`active`** → **`completed`** | **`accepted`** on **Shift+Q** |
|
||||||
|
| Operator chain | Operator Chain **`active step 1…4`** → **`completed`** | **`accepted`** on **Shift+Q** |
|
||||||
|
| Idempotency | All four still **`completed`** | **Q** deny / **Shift+Q** no eligible |
|
||||||
|
|
||||||
|
## Material math (suggested path)
|
||||||
|
|
||||||
|
| Phase | Actions | Bag after (approx.) |
|
||||||
|
|-------|---------|---------------------|
|
||||||
|
| Gather intro | **Q**; **R** at **gamma** once (+3 scrap) | 3 scrap |
|
||||||
|
| Combat intro | **Shift+Q**; defeat ×3 NPCs | 13 scrap, 1 token (+10 scrap loot) |
|
||||||
|
| Refine intro | **Shift+Q**; craft **`refine_scrap_standard`** | 8 scrap, 1 plate, 1 token |
|
||||||
|
| Chain step 1 | **Shift+Q**; **R** at **delta** once (+5 scrap) | 13 scrap; counter **5/5** |
|
||||||
|
| Chain step 2 | Craft **`refine_scrap_standard`** | 8 scrap, 2 plates, 1 token |
|
||||||
|
| Chain step 3 | Craft **`make_field_stim_mk0`** | 7 scrap, 0 plates, 1 stim, 1 token |
|
||||||
|
| Chain step 4 | Token already held from combat loot | Operator Chain **`completed`** |
|
||||||
|
|
||||||
|
Adjust gathers/crafts if bag counts differ; counters and craft denies are authoritative.
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
### Boot
|
||||||
|
|
||||||
|
1. Start server: `cd server/NeonSprawl.Server && dotnet run`.
|
||||||
|
2. Run Godot main scene (**F5**). Confirm **`QuestProgressLabel`** lists four **`not started`** quests and **`QuestAcceptFeedbackLabel`** shows the idle hint (in **`HudRootScroll`**). **`Economy HUD`** on; economy panel pinned bottom-left.
|
||||||
|
|
||||||
|
### Intro: Salvage Run (gather)
|
||||||
|
|
||||||
|
3. Press **Q**. Verify **`Intro: Salvage Run: active step 1`** and accept success feedback.
|
||||||
|
4. Walk to **gamma** **(12, 0)**; press **R** once. Verify counter **`chain_obj_gather`** is **not** present yet; gather intro counter increases (e.g. **`gather_intro_obj_scrap=3`**).
|
||||||
|
5. Verify **`Intro: Salvage Run: completed`**.
|
||||||
|
|
||||||
|
### Intro: Clear the Pocket (combat)
|
||||||
|
|
||||||
|
6. Press **Shift+Q**. Verify **`Intro: Clear the Pocket: active`** (combat intro — catalog order picks combat before refine).
|
||||||
|
7. Defeat all three prototype NPCs (**Tab** + **1**, any order). Verify **`EncounterProgressLabel`** **`completed (3/3)`** and **`EncounterCompleteLabel`** lists **`scrap_metal_bulk ×10`** + **`contract_handoff_token ×1`**.
|
||||||
|
8. Verify **`Intro: Clear the Pocket: completed`** and **`InventoryLabel`** shows **`contract_handoff_token`** (**1**).
|
||||||
|
|
||||||
|
### Intro: Refine Stock (craft)
|
||||||
|
|
||||||
|
9. Press **Shift+Q**. Verify **`Intro: Refine Stock: active step 1`**.
|
||||||
|
10. In Economy HUD, **Craft** **`refine_scrap_standard`** when **≥5** scrap in bag. Verify **`Intro: Refine Stock: completed`**.
|
||||||
|
|
||||||
|
### Operator Chain (four steps)
|
||||||
|
|
||||||
|
11. Press **Shift+Q**. Verify **`Operator Chain: active step 1`**.
|
||||||
|
12. **Chain step 1 — gather ×5:** press **R** at resource nodes until step advances (suggested: **delta** once for +5 scrap). Verify **`active step 2`** on **`QuestProgressLabel`**.
|
||||||
|
13. **Chain step 2 — refine:** craft **`refine_scrap_standard`**. Verify **`active step 3`**.
|
||||||
|
14. **Chain step 3 — stim:** craft **`make_field_stim_mk0`** (needs **2** plates + **1** scrap). Verify **`active step 4`**.
|
||||||
|
15. **Chain step 4 — token:** verify **`Operator Chain: completed`** without extra actions (token from step 8).
|
||||||
|
|
||||||
|
### Capstone snapshot
|
||||||
|
|
||||||
|
16. **Record** final **`QuestProgressLabel`**: all four quests **`completed`**.
|
||||||
|
|
||||||
|
### Idempotency (no duplicate quest completion)
|
||||||
|
|
||||||
|
17. **Godot restart:** stop Godot (**Shift+F5**); **F5** again **without** stopping the server. Verify all four quests still **`completed`**.
|
||||||
|
18. Press **Q** on gather intro. Verify **`Quest accept: denied — already_completed`** (or **`already_active`**).
|
||||||
|
19. Press **Shift+Q**. Verify **`Quest accept: no eligible quest`** (or equivalent deny). Quest HUD **unchanged** from step 16.
|
||||||
|
|
||||||
|
### Regression
|
||||||
|
|
||||||
|
20. Component quest HUD: [NEO-122 manual QA](NEO-122.md).
|
||||||
|
21. Encounter loot + token: [NEO-111 manual QA](NEO-111.md).
|
||||||
|
22. Economy craft panel: [NEO-75 manual QA](NEO-75.md).
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- **Shift+Q catalog order** is intentional for Slice 1 — combat intro before refine intro after gather completes. Full capstone supersedes [NEO-122](NEO-122.md) partial intro path.
|
||||||
|
- Combat defeat order is flexible; only **0/3 → completed (3/3)** is asserted.
|
||||||
|
- Chain terminal step is **`inventory_has_item`** — no token consume in Slice 1.
|
||||||
|
- **`POST /game/__dev/combat-targets-fixture`** is **out of scope** — clears encounter progress unsuitable for idempotency ([server README — dev combat-target fixture](../../server/README.md#dev-combat-target-fixture-brunomanual-qa)).
|
||||||
|
- Epic 7 Slice 1 AC: 3 onboarding + 1 chain complete without duped completion ([epic_07 Definition of Done](../decomposition/epics/epic_07_quest_faction.md#epic-7-definition-of-done)).
|
||||||
|
|
||||||
|
## Acceptance
|
||||||
|
|
||||||
|
- [ ] Steps 1–19 completable in one session without Bruno/curl.
|
||||||
|
- [ ] All four prototype quests reach **`completed`**; operator chain finishes when **`contract_handoff_token`** held.
|
||||||
|
- [ ] Godot restart + duplicate **Q**/**Shift+Q** leave quest statuses unchanged (no duplicate completion).
|
||||||
|
- [ ] Epic 7 Slice 1 AC satisfied in Godot.
|
||||||
|
|
@ -372,6 +372,8 @@ Working backlog for **Epic 7 — Slice 1** ([quest core and persistence](../deco
|
||||||
- [ ] Epic 7 Slice 1 AC: 3 onboarding + 1 chain complete without duplicate completion on replay.
|
- [ ] 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.
|
- [ ] Re-read [epic_07 Definition of Done](../decomposition/epics/epic_07_quest_faction.md#definition-of-done) for prototype minimums.
|
||||||
|
|
||||||
|
**Landed (docs — NEO-123):** [`docs/manual-qa/NEO-123.md`](../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). Human capstone QA + module **Ready** alignment pending.
|
||||||
|
|
||||||
**Client counterpart:** this story **is** the Slice 1 client capstone.
|
**Client counterpart:** this story **is** the Slice 1 client capstone.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,14 @@
|
||||||
- [ ] Epic 7 Slice 1 AC: 3 onboarding + 1 chain complete without duplicate completion on replay (idempotency steps pass).
|
- [ ] Epic 7 Slice 1 AC: 3 onboarding + 1 chain complete without duplicate completion on replay (idempotency steps pass).
|
||||||
- [ ] Re-read [epic_07 Definition of Done](../decomposition/epics/epic_07_quest_faction.md#epic-7-definition-of-done) for prototype minimums.
|
- [ ] Re-read [epic_07 Definition of Done](../decomposition/epics/epic_07_quest_faction.md#epic-7-definition-of-done) for prototype minimums.
|
||||||
|
|
||||||
|
## Implementation reconciliation (shipped — docs)
|
||||||
|
|
||||||
|
- **`docs/manual-qa/NEO-123.md`** — single-session four-quest capstone with Shift+Q catalog accept order, material math, idempotency steps.
|
||||||
|
- **`client/README.md`** — **End-to-end onboarding quest loop (NEO-123)** section with flow table and cross-links.
|
||||||
|
- **`docs/manual-qa/NEO-122.md`** — catalog-order note + capstone cross-link; expected HUD table aligned with Shift+Q picker.
|
||||||
|
- **No integration code changes** — docs-primary scope pending human capstone QA on `main`.
|
||||||
|
- **Module alignment** (E7.M1 **Ready**, register row, backlog checkboxes): update after human QA passes steps 1–19.
|
||||||
|
|
||||||
## Technical approach
|
## Technical approach
|
||||||
|
|
||||||
### 1. Capstone manual QA script (`docs/manual-qa/NEO-123.md`)
|
### 1. Capstone manual QA script (`docs/manual-qa/NEO-123.md`)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue