diff --git a/.planning/WINDOWS.md b/.planning/WINDOWS.md index 7f16795..eb22e8b 100644 --- a/.planning/WINDOWS.md +++ b/.planning/WINDOWS.md @@ -1,10 +1,10 @@ --- schema_version: 1 -open_count: 4 +open_count: 9 waived_count: 0 fixed_count: 2 -total_count: 6 -last_updated: 2026-09-10T01:38:48.570Z +total_count: 11 +last_updated: 2026-09-10T07:45:45.249Z --- # Broken Windows Ledger @@ -21,6 +21,11 @@ last_updated: 2026-09-10T01:38:48.570Z | 4 | 02 | skipped-test | packages-user/data-common/src/common/mover.test.ts | | 4 个 it.skip 坐标回写回归用例(x/y 正交、斜向、传送),待 02-02 修复 mover.ts:651 后翻绿 | fixed | | 2026-09-09T07:51:25.555Z | 2026-09-09T09:34:39.843Z | | 5 | 02 | stub | packages-user/data-system/src/path/system.ts | 254 | interrupt() is an intentional placeholder that only stops the in-flight move; takeover sequencing (stop-then-await per approved option 1) is implemented by 02-03 Task 4 | fixed | | 2026-09-09T09:34:59.707Z | 2026-09-09T13:24:24.755Z | | 6 | 02 | stub | packages-user/data-state/src/hero/moverImpl.ts | 284 | Existing cannotEnter() is intentionally empty because no event trigger corresponds to movement blocked by an impassable mask; D-08 direct OnTouch dispatch handles allowed adjacent no-pass targets. | open | | 2026-09-10T01:38:48.570Z | | +| 7 | 03 | stub | packages-user/data-common/src/save/memory.ts | 90 | MemorySaveSystem.saveAutosaveToDB is an intentional no-op because Node never persists to IndexedDB. | open | | 2026-09-10T07:45:16.944Z | | +| 8 | 03 | stub | packages-user/data-common/src/save/memory.ts | 90 | MemorySaveSystem.saveAutosaveToDB is an intentional no-op because Node never persists to IndexedDB. | open | | 2026-09-10T07:45:32.524Z | | +| 9 | 03 | stub | packages-user/data-state/src/legacy/dependencies.ts | 53 | Node legacy dependency boundary intentionally registers no browser loading callbacks. | open | | 2026-09-10T07:45:33.228Z | | +| 10 | 03 | deviation | packages-user/data-base/src/map/mapLayer.ts | 216 | Replaced Map.getOrInsertComputed with explicit Map lookup so the replay event path is Node-safe without a global prototype shim. | open | | 2026-09-10T07:45:33.930Z | | +| 11 | 03 | unrun-verify | .planning/phases/03-data-completion/deferred-items.md | | Repository type gate remains non-zero on pre-existing render/legacy and Tile contract diagnostics; owned Node tracer and data tests pass. | open | | 2026-09-10T07:45:45.249Z | | ````json [ @@ -95,6 +100,66 @@ last_updated: 2026-09-10T01:38:48.570Z "reason": "", "recorded_at": "2026-09-10T01:38:48.570Z", "resolved_at": null + }, + { + "id": 7, + "kind": "stub", + "phase": "03", + "file": "packages-user/data-common/src/save/memory.ts", + "line": 90, + "description": "MemorySaveSystem.saveAutosaveToDB is an intentional no-op because Node never persists to IndexedDB.", + "status": "open", + "reason": "", + "recorded_at": "2026-09-10T07:45:16.944Z", + "resolved_at": null + }, + { + "id": 8, + "kind": "stub", + "phase": "03", + "file": "packages-user/data-common/src/save/memory.ts", + "line": 90, + "description": "MemorySaveSystem.saveAutosaveToDB is an intentional no-op because Node never persists to IndexedDB.", + "status": "open", + "reason": "", + "recorded_at": "2026-09-10T07:45:32.524Z", + "resolved_at": null + }, + { + "id": 9, + "kind": "stub", + "phase": "03", + "file": "packages-user/data-state/src/legacy/dependencies.ts", + "line": 53, + "description": "Node legacy dependency boundary intentionally registers no browser loading callbacks.", + "status": "open", + "reason": "", + "recorded_at": "2026-09-10T07:45:33.228Z", + "resolved_at": null + }, + { + "id": 10, + "kind": "deviation", + "phase": "03", + "file": "packages-user/data-base/src/map/mapLayer.ts", + "line": 216, + "description": "Replaced Map.getOrInsertComputed with explicit Map lookup so the replay event path is Node-safe without a global prototype shim.", + "status": "open", + "reason": "", + "recorded_at": "2026-09-10T07:45:33.930Z", + "resolved_at": null + }, + { + "id": 11, + "kind": "unrun-verify", + "phase": "03", + "file": ".planning/phases/03-data-completion/deferred-items.md", + "line": null, + "description": "Repository type gate remains non-zero on pre-existing render/legacy and Tile contract diagnostics; owned Node tracer and data tests pass.", + "status": "open", + "reason": "", + "recorded_at": "2026-09-10T07:45:45.249Z", + "resolved_at": null } ] ```` diff --git a/.planning/phases/03-data-completion/03-01-SUMMARY.md b/.planning/phases/03-data-completion/03-01-SUMMARY.md new file mode 100644 index 0000000..9b11b91 --- /dev/null +++ b/.planning/phases/03-data-completion/03-01-SUMMARY.md @@ -0,0 +1,198 @@ +--- +phase: 03-data-completion +plan: 01 +subsystem: data-state +tags: [node, replay, core-state, memory-save, legacy-boundary, vitest] + +requires: + - phase: 02-pathfinding + provides: awaited hero mover and source-aware movement integration path +provides: + - Node-safe no-argument CoreState factory with independent memory-backed instances + - Internal legacy converter/data-source boundary with browser compatibility loading + - Fixed closed-loop replay fixture covering movement, event execution, map mutation, and normal replay end +affects: [03-02, 03-03, 03-04, 03-05, 03-06] + +actuals: + tokens: 7872 + tasks: 2 + commits: 3 + +tech-stack: + added: [] + patterns: + - Internal host-detection boundary selects MemorySaveSystem for Node and preserves SaveSystem for browser/legacy hosts + - Focused replay tests use a private direct ReplaySystem harness and explicit state/map/event fixtures + +key-files: + created: + - packages-user/data-common/src/save/memory.ts + - packages-user/data-state/src/legacy/dependencies.ts + - packages-user/data-state/test/fixtures/closed-loop.ts + - packages-user/data-state/test/nodeTracer.test.ts + - .planning/phases/03-data-completion/deferred-items.md + modified: + - packages/common/src/logger.ts + - packages-user/data-base/src/game.ts + - packages-user/data-base/src/hero/mover.ts + - packages-user/data-base/src/map/mapLayer.ts + - packages-user/data-common/src/replay/sandbox.ts + - packages-user/data-common/src/save/index.ts + - packages-user/data-state/src/core.ts + - packages-user/data-state/src/enemy/calculator.ts + - packages-user/data-state/src/legacy/move.ts + +key-decisions: + - "createCoreState() remains parameterless and directly returns new CoreState(); Node composition is selected internally rather than through factory options." + - "CoreState consumes the internal legacy dependency boundary only; the Node branch skips legacy loading and IndexedDB initialization." + - "The tracer owns a private direct ReplaySystem harness until later top-level replay registration plans assemble the public compatibility path." + +requirements-completed: [] + +coverage: + - id: D1 + description: "Node imports CoreState without browser globals and creates two independent MemorySaveSystem-backed instances." + verification: + - kind: other + ref: "pnpm exec tsx -e import createCoreState; create two instances and assert identity/save backend" + status: pass + human_judgment: false + - id: D2 + description: "The fixed replay fixture performs a real rightward hero move, awaits the event, mutates the event-layer matrix, and reaches ended state." + requirement: DATA-01 + verification: + - kind: integration + ref: "packages-user/data-state/test/nodeTracer.test.ts#replays movement, awaits event mutation, and ends normally" + status: pass + - kind: unit + ref: "pnpm exec vitest run packages-user/data-state/test/nodeTracer.test.ts" + status: pass + human_judgment: false + - id: D3 + description: "The existing four-package data test suite remains green after the Node-safe composition and replay fixes." + verification: + - kind: integration + ref: "pnpm test:ci packages-user/data-common packages-user/data-base packages-user/data-system packages-user/data-state" + status: pass + human_judgment: false + +duration: 19 min +completed: 2026-09-10 +status: complete +--- + +# Phase 3 Plan 1 Summary + +**Node-safe four-layer state construction with injected legacy boundaries and an awaited replay movement/event/map tracer** + +## Performance + +- **Duration:** 19 min +- **Started:** 2026-09-10T15:27:00+08:00 +- **Completed:** 2026-09-10T15:46:21+08:00 +- **Tasks:** 2 +- **Files modified:** 13 implementation/test files, plus planning ledgers + +## Accomplishments + +- Guarded logger and game-loading module evaluation against missing `main`, `window`, `document`, and `location` globals +- Added `MemorySaveSystem`, parameterless `createCoreState()`, independent Node-safe construction, and centralized legacy dependency injection +- Removed the enemy calculator singleton edge and legacy movement barrel edge without reintroducing a data-state singleton into the Node path +- Added a fixed three-cell map tracer that awaits hero movement and source-aware enter-event mutation before replay completion +- Removed two Node blockers: nonstandard `Map.getOrInsertComputed` use in the event path and the replay sandbox play-loop state guard + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: singleton back-edge 修复与 Node-safe CoreState construction tracer** - `a707be4` (feat) +2. **Task 2: Node-safe CoreState 与最小 replay→move→event→map tracer** - `4eec086` (feat) + +**Plan metadata:** pending final metadata commit + +## Files Created/Modified + +- `packages-user/data-common/src/save/memory.ts` - in-memory save/global storage adapter that does not instantiate Dexie +- `packages-user/data-state/src/legacy/dependencies.ts` - internal host-aware legacy converter and loading boundary +- `packages-user/data-state/src/core.ts` - no-options factory and dependency-driven four-layer constructor +- `packages-user/data-state/test/fixtures/closed-loop.ts` - fixed map, event, and direct replay fixture +- `packages-user/data-state/test/nodeTracer.test.ts` - focused Node construction and replay closure tests with Chinese `it` comments +- `packages/common/src/logger.ts`, `packages-user/data-base/src/game.ts` - Node-safe global guards +- `packages-user/data-base/src/map/mapLayer.ts`, `packages-user/data-common/src/replay/sandbox.ts` - runtime fixes required by the tracer + +## Decisions Made + +- Kept the public factory contract parameterless; host selection and legacy injection remain internal to the constructor boundary +- Kept the compatibility singleton available through the existing barrel while direct Node tests import `src/core.ts` +- Used the existing `DefaultHeroMoveTopImpl`, `EventExecutor`, and `ReplaySandbox` instead of creating a parallel movement or event engine + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] Avoided reading an uninitialized hero mover during construction** +- **Found during:** Task 1 +- **Issue:** `HeroLocation` constructs `HeroMover` before assigning `location.mover`, while the mover constructor read `tile.getCurrentFaceDirection()` and crashed in Node +- **Fix:** Initialize the base mover with `FaceDirection.Unknown`; the location constructor applies the requested initial direction immediately afterward +- **Files modified:** `packages-user/data-base/src/hero/mover.ts` +- **Verification:** Node factory probe and focused tracer pass +- **Committed in:** `a707be4` + +**2. [Rule 3 - Blocking] Removed the event-layer dependency on a nonstandard Map prototype extension** +- **Found during:** Task 2 tracer execution +- **Issue:** The real movement path called `Map.getOrInsertComputed`, which is absent in a clean Node process and stalled the movement Promise +- **Fix:** Replaced it with explicit `Map.get`/`Map.set` construction +- **Files modified:** `packages-user/data-base/src/map/mapLayer.ts` +- **Verification:** Focused tracer and full four-package data suite pass without a global Map shim +- **Committed in:** `4eec086` + +**3. [Rule 1 - Bug] Allowed ReplaySandbox.play() to execute its command loop** +- **Found during:** Task 2 tracer execution +- **Issue:** `ReplaySandbox.play()` sets `pausing` false, but `step()` rejected every step while not paused, so replay never reached `ended` +- **Fix:** `step()` now rejects only inactive or already-ended sandboxes, preserving paused single-step behavior while allowing the play loop +- **Files modified:** `packages-user/data-common/src/replay/sandbox.ts` +- **Verification:** Replay tracer reaches normal end after the awaited movement/event Promise; full data suite passes +- **Committed in:** `4eec086` + +--- + +**Total deviations:** 3 auto-fixed (1 Rule 1 bug, 1 Rule 3 blocking issue, 1 Rule 1 replay bug) +**Impact on plan:** All fixes were direct blockers for the requested Node/replay vertical tracer; no new public interface or package dependency was introduced. + +## Known Stubs + +- `packages-user/data-common/src/save/memory.ts:90` — `saveAutosaveToDB()` is intentionally a no-op in the Node adapter because the Node path must not persist to IndexedDB; recorded in `.planning/WINDOWS.md`. +- `packages-user/data-state/src/legacy/dependencies.ts:51` — the Node boundary intentionally registers no browser loading callback; recorded in `.planning/WINDOWS.md`. +- `packages-user/data-state/src/core.ts:156` — serialized external event registration remains the existing deferred TODO for later Phase 3 assembly; recorded in `.planning/WINDOWS.md`. + +## Issues Encountered + +- `pnpm check:type` remains non-zero on pre-existing render/legacy diagnostics and the user-owned Tile events contract mismatch (`TileStore`/`TileLegacyBridge` still use the old `trigger` shape). No new diagnostics were reported in the new fixture/test files or the memory/dependency boundary files. The issue is logged in `deferred-items.md` and `.planning/WINDOWS.md` for the later tile-events/type closure plan. + +## Verification + +- PASS: `pnpm exec vitest run packages-user/data-state/test/nodeTracer.test.ts` — 2 tests +- PASS: `pnpm test:ci packages-user/data-common packages-user/data-base packages-user/data-system packages-user/data-state` — 11 files, 60 tests +- PASS: exact canonical madge back-edge check for `enemy/calculator.ts -> ins.ts` and `legacy/move.ts -> index.ts` +- PASS: direct Node factory probe creates two distinct `MemorySaveSystem`-backed states +- DEFERRED: repository-wide `pnpm check:type`, due only to pre-existing render/legacy and Tile contract diagnostics + +## User Setup Required + +None - no external service configuration required. + +## Next Phase Readiness + +- The next replay/event plans can consume a direct Node-safe `CoreState` and fixed fixture without browser globals or IndexedDB. +- Top-level replay enum/registration and event built-ins remain intentionally delegated to the subsequent Phase 3 plans. +- The repository-wide type gate remains deferred as documented; the focused Node tracer and all current data-package tests are green. + +--- +*Phase: 03-data-completion* +*Completed: 2026-09-10* + +## Self-Check: PASSED + +- Summary and all declared created artifacts exist on disk +- Task commits `a707be4` and `4eec086` are present in git history +- Focused tracer and full data-package test suite passed diff --git a/.planning/phases/03-data-completion/deferred-items.md b/.planning/phases/03-data-completion/deferred-items.md new file mode 100644 index 0000000..2f79412 --- /dev/null +++ b/.planning/phases/03-data-completion/deferred-items.md @@ -0,0 +1,3 @@ +# Deferred Items — Phase 03 + +- `pnpm check:type` remains blocked by pre-existing render/legacy diagnostics and the user-owned Tile events contract migration (`TileStore.getEvent` and `TileLegacyBridge` still use the old `trigger` shape). The migration is outside Plan 03-01 and remains assigned to the later Phase 3 tile-events plan.