diff --git a/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-4-report.md b/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-4-report.md deleted file mode 100644 index 923642b..0000000 --- a/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-4-report.md +++ /dev/null @@ -1,50 +0,0 @@ -# Task 4: Health and demo-character API report - -## RED - -- Re-read every Markdown document below `docs/` and inspected `combat-screen.png`, `hunting-screen.png`, and `world-travel-screen.png` before implementation. -- Added focused health and character-service tests, then ran: - - ```powershell - npm test --workspace=@ashen-realms/api -- health.controller.spec.ts characters.service.spec.ts --runInBand - ``` - -- Observed the expected RED result: both suites failed because `HealthController` and `CharactersService` did not exist. - -## GREEN - -- Replaced the scaffold root controller/service with `HealthModule` and `CharactersModule`. -- `GET /api/health` returns `{ status: 'ok' }` without a database query. -- `GET /api/characters/me` obtains the fixed demo ID server-side, loads `currentLocation`, maps `baseHp` to `maxHp` and `baseAttack` to `attack`, and raises `NotFoundException` when the seed is absent. -- Preserved the existing tested `configureApplication()` global-prefix seam and enabled Nest shutdown hooks in `main.ts` without repeating prefix configuration. -- Updated the E2E assertion from the retired hello-world root route to `/api/health`; it replaces both database-dependent modules so the health test remains database independent. - -## Verification - -| Command | Result | -| --- | --- | -| `npm test --workspace=@ashen-realms/api -- health.controller.spec.ts characters.service.spec.ts --runInBand` | PASS: 2 suites, 3 tests | -| `npm run test:e2e --workspace=@ashen-realms/api -- --runInBand` | PASS: 1 suite, 2 tests | -| `npm test --workspace=@ashen-realms/api -- --runInBand` | PASS: 5 suites, 9 tests | -| `npm run build:api` | PASS | -| `apps/api/node_modules/.bin/prettier.cmd --check ` | PASS | -| `git diff --check` | PASS | - -`npx prettier` did not resolve the workspace-local executable in this environment; the checked-in workspace binary at `apps/api/node_modules/.bin/prettier.cmd` was used for the formatting check. - -## Files - -- Added `apps/api/src/health/*` and character controller/service/module plus unit tests. -- Updated `apps/api/src/app.module.ts`, `apps/api/src/main.ts`, and `apps/api/test/app.e2e-spec.ts`. -- Removed `apps/api/src/app.controller.ts`, `app.controller.spec.ts`, and `app.service.ts`. - -## Self-review and concerns - -- Confirmed the repository query loads only the required current-location relation and response does not expose persistence-only base-stat names. -- Confirmed the missing seed path is tested as a 404-producing Nest exception. -- Confirmed `/` remains a 404 while `/api/health` is available through the existing global prefix. -- No task-specific concerns remain. Pre-existing untracked `apps/web/public/images/` and `docs/references/Ashen_Realms_Visual_Asset_Style_Guide_V1.md` are intentionally excluded. - -## Commit - -- Pending: `feat: expose health and demo character APIs` diff --git a/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-5-report.md b/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-5-report.md deleted file mode 100644 index 2ddf12b..0000000 --- a/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-5-report.md +++ /dev/null @@ -1,105 +0,0 @@ -# Task 5 Report: Server-authoritative travel - -## Outcome - -Implemented the NestJS travel domain and public endpoints: - -- `POST /api/travel` -- `GET /api/travel/current` -- injected deterministic/system clock abstraction -- exact `StartTravelDto` input validation -- stable idle, travelling, completed, and domain-error response shapes -- `TravelModule` registration in the application - -Travel start and completion use `DataSource.transaction`. Both operations acquire a pessimistic write lock on the character row followed by the active travel row. Relations are deliberately not joined into either locking query, which keeps the queries compatible with TypeORM/PostgreSQL `FOR UPDATE` behavior. Due completion changes the travel status and character location through repositories owned by the same transaction; a failed second save rolls back both mutations. - -No ambush evaluation or other later-slice logic was added. Existing untracked frontend images and the visual asset guide were preserved and excluded from the commit. - -## RED evidence - -Command: - -```powershell -npm test --workspace=@ashen-realms/api -- travel.service.spec.ts travel.controller.spec.ts --runInBand -``` - -Initial result: exit code 1. Both suites failed to resolve the missing production modules: - -```text -Cannot find module './travel.service' from 'travel/travel.service.spec.ts' -Cannot find module './travel.controller' from 'travel/travel.controller.spec.ts' -Test Suites: 2 failed, 2 total -Tests: 0 total -``` - -The active-travel regression test was also mutation-checked. Temporarily removing the `TRAVEL_ALREADY_ACTIVE` guard produced the expected focused failure (`Expected constructor: TravelDomainError; Received constructor: Object`); restoring the guard returned the test to green. - -## GREEN evidence - -Focused travel tests: - -```powershell -npm test --workspace=@ashen-realms/api -- travel.service.spec.ts travel.controller.spec.ts --runInBand -``` - -```text -Test Suites: 2 passed, 2 total -Tests: 9 passed, 9 total -Time: 10.973 s -``` - -The service suite covers all five required behaviors plus active-travel rejection, public current-travel mapping, idempotent repeat completion, pessimistic-lock observation, and rollback when the second completion save fails. The controller suite drives a real Nest HTTP pipeline and verifies that server-owned timestamp/duration fields receive HTTP 400. - -Full API suite: - -```powershell -npm test --workspace=@ashen-realms/api -- --runInBand -``` - -```text -Test Suites: 7 passed, 7 total -Tests: 18 passed, 18 total -Time: 15.87 s -``` - -API E2E: - -```powershell -npm run test:e2e --workspace=@ashen-realms/api -- --runInBand -``` - -```text -Test Suites: 1 passed, 1 total -Tests: 2 passed, 2 total -Time: 9.406 s -``` - -API build: - -```powershell -npm run build:api -``` - -Result: exit code 0 (`nest build`). - -Formatting and lint: - -```powershell -apps/api/node_modules/.bin/prettier.cmd --check -node_modules/.bin/eslint.cmd -``` - -Both commands exited 0. Prettier reported `All matched files use Prettier code style!`; ESLint reported no findings. - -## Integration notes and self-review - -- The first build exposed TypeScript `TS1272` for a decorated `Clock` parameter under `isolatedModules`; importing `Clock` as a type fixed the root cause, after which tests and build were rerun. -- Registering the database-backed `TravelModule` exposed that the existing health E2E test replaced `DatabaseModule` and `CharactersModule` but not travel. The harness now replaces `TravelModule` as well, preserving the database-free health test. -- Lock order is identical in start and completion, reducing deadlock risk. -- The character row serializes concurrent starts even when no active travel row exists yet; the partial unique database index remains the final invariant. -- The due comparison treats `arrivesAt === now` as due and never moves the character earlier. -- Public responses contain only location summaries and travel timestamps/status, never entities, duration input, ambush probability, or persistence metadata. - -## Remaining concern - -No live-PostgreSQL travel integration test was added because the repository's current E2E harness intentionally runs without a database; clean migration/seed/API database smoke coverage belongs to Task 10. The transaction code uses supported real `EntityManager.getRepository`, `Repository.findOne` lock options, `findOneBy`, `create`, and `save` behavior, and the stateful fake verifies transaction commit/rollback semantics rather than mock call counts. diff --git a/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-6-report.md b/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-6-report.md deleted file mode 100644 index 2ed8589..0000000 --- a/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-6-report.md +++ /dev/null @@ -1,83 +0,0 @@ -# Task 6 — Current-location World API report - -## Scope delivered - -- Added `WorldService.getCurrentLocation(characterId)`. -- Added `GET /api/world/current-location` using the stable demo character. -- Added `WorldModule`, including TypeORM repositories for `Character` and - `LocationConnection`, and imported it through `AppModule`. -- `WorldService` completes due travel before loading the character, returns the - complete current-location DTO, returns only enabled outgoing connections, and - exposes a target summary, duration, and textual danger rating only. The raw - `ambushChance` is not part of the public DTO; `0.0500` maps to `LOW`. -- Kept the existing database-free health E2E harness valid by overriding the - newly imported `WorldModule`, just as it already overrides the database, - character, and travel modules. - -## Required preflight - -- Read the complete Task-6 brief and the binding project documentation, - including the visual asset style guide. -- Inspected `world-travel-screen.png`, `combat-screen.png`, and - `hunting-screen.png` in `docs/references/`. -- Preserved the user-owned untracked `apps/web/public/images/` directory and - `docs/references/Ashen_Realms_Visual_Asset_Style_Guide_V1.md` unchanged. - -## TDD evidence - -### RED - -Command: - -```powershell -npm test --workspace=@ashen-realms/api -- world.service.spec.ts --runInBand -``` - -Initial result: failed because `./world.service` did not exist. After the -minimal initial implementation, the test exposed that a disabled connection -could still be returned by an unexpected repository result. The service now -defensively filters disabled connections in addition to querying with -`enabled: true`. - -### GREEN - -```powershell -npm test --workspace=@ashen-realms/api -- world.service.spec.ts --runInBand -``` - -Result: 1 suite passed, 2 tests passed. - -## Verification evidence - -```powershell -npm test --workspace=@ashen-realms/api -- --runInBand -# 8 suites passed, 20 tests passed - -npm run test:e2e --workspace=@ashen-realms/api -- --runInBand -# 1 suite passed, 2 tests passed - -npm run build:api -# Nest build completed successfully - -# From apps/api: -.\node_modules\.bin\prettier.cmd --check -npx eslint -# Prettier: all matched files use Prettier code style; ESLint exit 0 - -git diff --check -- apps/api/src/app.module.ts apps/api/src/world apps/api/test/app.e2e-spec.ts -# exit 0 -``` - -The initial E2E run was reproducibly red because the new `WorldModule` caused -TypeORM repository construction after the test had intentionally replaced the -database module. Adding its corresponding empty module override restored the -existing database-free health test without changing product behavior. - -## Deliberate limits and concerns - -- The approved first slice only needs the seeded 5% route, so the public - connection danger mapping currently distinguishes `LOW` (at or below 5%) and - `HIGH` (above 5%). Future routes may require finer danger tiers when their - product thresholds are specified. -- This task adds no database-backed route E2E assertion; the dedicated - migration/seed route smoke test is scheduled for Task 10. diff --git a/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-7-report.md b/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-7-report.md deleted file mode 100644 index 372b9cc..0000000 --- a/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-7-report.md +++ /dev/null @@ -1,151 +0,0 @@ -# Task 7 — Angular typed API and signal-driven WorldStore report - -## Scope delivered - -- Added typed public response models and `GameApiService` methods for character, - current location, travel start, and current travel. -- Configured Angular's application providers with `HttpClient`. -- Added `WorldStore` with private writable and public read-only signals for - character, world location, selection, travel, countdown, loading, and errors. -- The store derives presentation-only countdown seconds from server `arrivesAt`. - At zero it polls the API and never assigns the target location locally. -- Character and location are reloaded only after the API returns `COMPLETED`. - -## Required preflight - -- Re-read every document under `docs/`, including the approved design and - implementation plan, and inspected all three PNG reference images. -- Read the user-supplied visual asset guide. The untracked `apps/web/public/images/` - directory and `docs/references/Ashen_Realms_Visual_Asset_Style_Guide_V1.md` - remain unchanged and unstaged. - -## TDD evidence - -### RED - -```powershell -npm test --workspace=@ashen-realms/web -- --watch=false -``` - -Initial result: failed as expected because `game-api.service`, -`game-api.models`, and `world.store` did not exist. The compiler reported only -their unresolved imports from the newly added tests. - -### GREEN - -```powershell -npm test --workspace=@ashen-realms/web -- --watch=false --include='src/app/core/api/game-api.service.spec.ts' --include='src/app/features/world/world.store.spec.ts' -``` - -Result: 2 test files passed, 7 tests passed. - -The store tests cover initial loading, target-only travel start, `arrivesAt` -countdown calculation, polling at zero without local arrival, and reload only -after `COMPLETED`. - -## Verification evidence - -```powershell -npm test --workspace=@ashen-realms/web -- --watch=false -# 3 test files passed, 9 tests passed - -npm run build:web -# Angular production build completed successfully - -npm exec --workspace=@ashen-realms/web -- prettier --check -# All matched files use Prettier code style - -git diff --check -- -# exit 0 -``` - -## Review fix round 2 - -The transient-poll regression now asserts both phases: the failed poll exposes -`Temporary failure`, and the successful authoritative `IDLE` retry clears it. -The new assertion was RED against the prior implementation because the error -remained set after the retry. `refreshCurrentTravel()` now clears the polling -error only after a successful API response and before applying that response; -the countdown contract and all other error paths are unchanged. - -Fresh verification: - -```powershell -npm test --workspace=@ashen-realms/web -- --watch=false --include='src/app/features/world/world.store.spec.ts' -# 1 test file passed, 9 tests passed - -npm test --workspace=@ashen-realms/web -- --watch=false -# 3 test files passed, 13 tests passed - -npm run build:web -# Angular production build completed successfully - -npm exec --workspace=@ashen-realms/web -- prettier --check -# All matched files use Prettier code style - -git diff --check -- -# exit 0 -``` - -The web workspace declares neither a `lint` script nor an ESLint dependency, so -there is no repository-configured lint command to run for this task. - -## Deliberate limits and concerns - -- The store retains a `COMPLETED` travel response after its authoritative - character/location refresh. The following API poll returns `IDLE`; the later - world UI can decide when to clear the completion presentation. -- The mandated code-review workflow normally requires a reviewer subagent, but - this task explicitly prohibited subagents. The implementation was instead - reviewed directly against the task brief and verified through the focused and - complete web test/build checks above. - -## Review fix round 1 - -### Findings addressed - -- A journey whose `arrivesAt` was already in the past made an immediate poll - but also installed a countdown interval. This could overlap an outstanding - request. -- A late response after store destruction could still apply state and start - follow-on work. - -The store now makes a single immediate poll at local zero with no countdown -interval. It uses one in-flight poll at a time and schedules a deliberate -one-second retry when the server still returns `TRAVELLING` or a poll fails. -All late async continuations check the destroy flag before changing state or -scheduling timers. The browser still never declares arrival or changes the -location itself. - -### TDD evidence - -```powershell -npm test --workspace=@ashen-realms/web -- --watch=false --include='src/app/features/world/world.store.spec.ts' -``` - -RED result: 2 of 9 tests failed against the previous implementation. The -already-expired test observed three calls where a pending request must allow -only two, and the destroy test observed an unwanted second character/location -reload after a late `COMPLETED` response. - -GREEN result: 1 test file passed, 9 tests passed. The expanded cases establish -that `IDLE` and continuing `TRAVELLING` do not reload authoritative character -or location data, expired/skewed client time remains single-flight/throttled, -a transient poll error retries and recovers, and destruction ignores a late -response. - -### Fresh verification - -```powershell -npm test --workspace=@ashen-realms/web -- --watch=false -# 3 test files passed, 13 tests passed - -npm run build:web -# Angular production build completed successfully - -npm exec --workspace=@ashen-realms/web -- prettier --check -# All matched files use Prettier code style - -git diff --check -- -# exit 0 -``` diff --git a/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-8-report.md b/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-8-report.md deleted file mode 100644 index 134ed2e..0000000 --- a/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-8-report.md +++ /dev/null @@ -1,74 +0,0 @@ -# Task 8 report: reusable Angular application shell - -## Scope delivered - -- Replaced the Angular scaffold with a route-hosting root component and a reusable dark-fantasy shell. -- Added focused standalone components for the app shell, store-driven top bar, side navigation, footer, and context-panel frame. -- Added requested design tokens, spacing, motion, elevation, global reset, responsive shell grid, and reduced-motion protection. -- Configured `/` and fallback routing to `/world`; the route lazy-loads a deliberately scene-free `WorldPageComponent` placeholder so Task 9 can add the world composition without changing the route contract. -- Made Karte the only enabled active navigation entry. Jagd, Quests, Inventar, and Charakter are disabled buttons with accessible explanatory labels. Shop is not rendered. -- Top-bar character identity, level, and hit points are rendered only from `WorldStore.character`; it has no hardcoded character statistics. - -## Preflight and asset evidence - -- Re-read the Task 8 brief, visible-slice implementation plan, progress ledger, prior task reports, and the full user-provided visual asset style guide. -- Visually inspected `combat-screen.png`, `hunting-screen.png`, and `world-travel-screen.png` before editing. -- Visually inspected the relevant user HUD assets before use. The shell uses only: - - `apps/web/public/images/hud/CharacterIcon.png` - - `apps/web/public/images/hud/MapsIcon.png` - - `apps/web/public/images/hud/HuntIcon.png` - - `apps/web/public/images/hud/QuestsIcon.png` - - `apps/web/public/images/hud/InventoryIcon.png` - -## TDD evidence - -### RED - -`npm test --workspace=@ashen-realms/web -- --watch=false` failed as intended before production work: the new shell specification expected `app-top-bar`, but the scaffold only contained a router outlet. The existing two test files remained green (11 passing tests). - -### GREEN - -`npm test --workspace=@ashen-realms/web -- --watch=false` passed with 3 test files and 12 tests. The added shell test asserts top bar, side navigation, semantic main content, footer, enabled active Karte, disabled future destinations, and Shop absence. - -## Final verification - -- `npm test --workspace=@ashen-realms/web -- --watch=false`: 3 files and 12 tests passing. -- `npm run build:web`: production Angular build passed and emits a lazy `world-page-component` chunk. -- `npm exec --workspace=@ashen-realms/web -- prettier --check ...`: all Task 8 files formatted. -- `git diff --check`: no whitespace errors. - -## Visual QA limitation - -The Browser plugin is not available in this session. The repository has no installed Playwright package, and a non-mutating `npm exec --workspace=@ashen-realms/web -- playwright --version` check could not resolve a local runner and timed out. No browser dependency was added outside task scope. Rendered browser verification remains for Task 11, which owns final browser workflow and fidelity captures. - -## Intentional limits - -- The world route placeholder contains no scene, nodes, API loading, or travel panel; Task 9 owns those surfaces. -- The context panel is only a reusable framed shell until Task 9 supplies world data. - -## Review fix round 1 - -### Accessibility and responsive behavior - -- The active Karte button now has the explicit accessible name `Karte`, so its label remains available when the compact viewport hides visible navigation text. -- At widths below 900px, the context panel now reflows into a full-width row below main content instead of being hidden. At widths below 620px it remains in DOM order after main content. - -### Runtime HUD derivatives - -The five original 1254 x 1254 user assets remain unmodified. The shell now loads deterministic 128 x 128 PNG derivatives from `images/hud/runtime/`; each was resized locally with high-quality bicubic interpolation and no creative image change. - -| Asset | Original bytes | Runtime derivative bytes | -| --- | ---: | ---: | -| CharacterIcon | 2,283,892 | 26,670 | -| MapsIcon | 2,144,772 | 27,774 | -| HuntIcon | 2,313,949 | 29,486 | -| QuestsIcon | 2,235,955 | 29,554 | -| InventoryIcon | 2,060,169 | 26,142 | - -The combined persistent-icon payload is reduced from 11,038,737 bytes to 139,626 bytes (about 98.7%). The resized Maps icon was visually inspected after generation. - -### Regression evidence - -RED: the added explicit accessible-name assertion failed before the fix because the active Karte control had no `aria-label`. - -GREEN: `npm test --workspace=@ashen-realms/web -- --watch=false` passed with 3 test files and 14 tests. The added coverage verifies the explicit Karte name, non-null WorldStore character rendering, and root/wildcard `/world` route redirects. diff --git a/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-9-report.md b/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-9-report.md deleted file mode 100644 index a015e6d..0000000 --- a/.superpowers/sdd/2026-08-18-first-visible-vertical-slice/task-9-report.md +++ /dev/null @@ -1,51 +0,0 @@ -# Task 9 Report: World UI - -## Reference inventory - -- `world-travel-screen.png`: persistent top bar and left navigation, a dominant central map, labelled current/reachable nodes with a dotted path, dense right context, and a bottom-centred travel decision panel. -- `hunting-screen.png`: confirms the shared dark iron/bronze material treatment, restrained gold highlights, readable serif display hierarchy, and dense information without white cards or modern pills. -- `combat-screen.png`: confirms the same persistent shell, dark desaturated palette, thin ornate borders, and blue only as a controlled active-state accent. - -The reference screenshots were inspected but are not shipped or referenced by the application. - -## Artwork and layout decision - -- No ImageGen was used: the controller ruling makes the delivered user artwork final. -- `/images/backgrounds/map_ashen_realm.png` is the dominant WorldPage scene. Its wide path, city, watchtower, and ash-field composition provides a clearer interactive map than either location image. -- The server-delivered location paths are `/images/backgrounds/Suedtor.png` and `/images/backgrounds/Aschestrasse.png`; the ContextPanel renders the authoritative current-location image, so it changes only after server-confirmed arrival. -- This deliberately supersedes the older brief wording that asked for generated assets and API artwork as the main scene background. It preserves the binding controller ruling while retaining the server-provided artwork as context. - -## Delivered behavior - -- `WorldPageComponent` loads `WorldStore` on init, renders a code-native SVG connection and two code-native location buttons, shows loading/error/retry states, and never advances location locally. -- `LocationNodeComponent` exposes current, selected, reachable, disabled, hover, and focus states with textual labels. -- `TravelPanelComponent` presents no-selection guidance, selected target/travel-time/danger with `Reise beginnen`, and an arrivesAt-derived travelling countdown with disabled action. -- `ContextPanelComponent` renders the current/selected location, description, recommended level, safe status, hunting status, and server artwork. -- Seed paths now match the delivered assets and are covered by the API seed test. - -## Review-fix round - -- Map-node geography is now anchored to the stable location keys (`south-gate` and `burned-road`). Current, reachable, and selected state only changes presentation; a regression test swaps the authoritative current location without moving either node. -- On a server `COMPLETED` response, the selected connection is cleared and the store stays loading until the authoritative character/location/travel reload completes. All travel actions are disabled in that interval; no local arrival or location update is performed. -- The moving countdown is a `