docs(02): add gap closure plans

This commit is contained in:
unanmed 2026-09-09 22:31:42 +08:00
parent cdadd3870c
commit 3809b40b41
3 changed files with 260 additions and 1 deletions

View File

@ -80,7 +80,7 @@ Plans:
2. 移动端点击地图上的可达格时,角色自动寻路移动到该格
3. 寻路正确避开不可通行格(碰撞/障碍/墙体)
**Plans**: 3/3 plans executed
**Plans**: 3/5 plans executed
**UI hint**: yes
Plans:
@ -88,6 +88,9 @@ Plans:
- [x] 02-02-PLAN.md — L0 坐标回写缺陷修复 + L2 寻路核心(有向图 + 最小损失 + 仅取路径 + 回退策略槽位)
- [x] 02-03-PLAN.md — L3 接线(逐步/瞬移/回退默认策略/D-08 双语义/打断接管)+ barrel/logger 装配 + 阶段门禁
- [ ] 02-04-PLAN.md — 恢复用户授权的 path/types.ts 契约并收口 moverImpl TS18047
- [ ] 02-05-PLAN.md — 稳定全量 Vitest 门禁并提供非 watch 测试命令
**Wave 1**
- [x] 02-01-PLAN.md — 接口草案与拍板关卡autonomous: false
@ -100,6 +103,11 @@ Plans:
- [x] 02-03-PLAN.md — L3 接线与阶段门禁
### Wave 4 *(gap closure; blocked on Wave 3 completion)*
- [ ] 02-04-PLAN.md — 用户契约范围与阶段类型错误收口
- [ ] 02-05-PLAN.md — 全套件超时与跳过测试门禁收口
### Phase 3: 数据端完成
**Goal**: 数据端 L0L3 接口实现完成,数据层各系统可用并可在 Node 环境独立运行回放验证

View File

@ -0,0 +1,137 @@
---
phase: 02-pathfinding
plan: 04
type: execute
wave: 4
depends_on: ["02-03"]
files_modified:
- packages-user/data-system/src/path/types.ts
- packages-user/data-system/src/path/graph.ts
- packages-user/data-system/src/path/finder.ts
- packages-user/data-system/src/path/system.ts
- packages-user/data-state/src/hero/moverImpl.ts
- .planning/phases/02-pathfinding/deferred-items.md
autonomous: true
gap_closure: true
requirements: [PATH-01]
estimate:
tokens: 26000
raw_tokens: 26000
tasks: 2
confidence: low
must_haves:
truths:
- "The user-owned path contract matches commit 7a011b2 except for the two authorized nullable moveTo/teleportTo return corrections (D-07)."
- "Existing pathfinding graph, search, and hero movement behavior remains reachable through the restored public contract."
- "The phase-owned moverImpl file has no nullable-static TypeScript diagnostic, while its static and dynamic event collection semantics remain intact."
- "D-01: Existing minimum-loss and custom-cost behavior remains unchanged."
- "D-02: Existing directed reachable-graph behavior remains unchanged."
- "D-03: Existing map-layer and movable binding behavior remains available."
- "D-04: Existing step, teleport, and fallback behavior remains unchanged."
- "D-05: Existing injectable event-aware fallback policy remains unchanged."
- "D-06: Existing path-only retrieval remains unchanged."
- "D-07: The user-authored contract remains the source of truth after review."
- "D-08: Existing approved no-pass OnTouch semantics remain unchanged."
- "D-09: Existing hero-mover hook reuse remains unchanged."
- "D-10: Existing stop-then-await interruption handoff remains unchanged."
- "D-11: This gap closure remains data-side and excludes the Phase 4 click adapter."
artifacts:
- "packages-user/data-system/src/path/types.ts"
- "packages-user/data-system/src/path/graph.ts"
- "packages-user/data-system/src/path/finder.ts"
- "packages-user/data-system/src/path/system.ts"
- "packages-user/data-state/src/hero/moverImpl.ts"
key_links:
- "The restored user contract is consumed by the L2 path implementation without exposing phase-added graph/helper types through types.ts."
- "The nullable static guard still allows dynamic tile events to be collected before the existing source-aware executor path runs."
---
<objective>
Close the unauthorized user-owned path/types.ts expansion and the TS18047 diagnostic in moverImpl.ts without changing the locked Phase 2 pathfinding behavior.
Purpose: The verification report found that the user-owned contract grew beyond the authorized nullable return edits and that a phase-modified event loop still fails the type gate. D-07 makes the user-authored contract authoritative; this plan restores that boundary while preserving the already-verified L2/L3 runtime path.
Output: A baseline-faithful types.ts, relocated implementation-only graph contracts, a nullable-safe event-source loop, and focused evidence that PATH-01 behavior still passes.
</objective>
<execution_context>
@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/02-pathfinding/02-VERIFICATION.md
@.planning/phases/02-pathfinding/02-CONTEXT.md
@.planning/phases/02-pathfinding/02-RESEARCH.md
@.planning/phases/02-pathfinding/02-INTERFACE-DRAFT.md
@.planning/phases/02-pathfinding/02-02-SUMMARY.md
@.planning/phases/02-pathfinding/02-03-SUMMARY.md
@packages-user/data-system/src/path/types.ts
@packages-user/data-system/src/path/graph.ts
@packages-user/data-system/src/path/finder.ts
@packages-user/data-system/src/path/system.ts
@packages-user/data-state/src/hero/moverImpl.ts
@dev.md
</context>
<tasks>
<task type="tracer">
<name>Task 1: Restore the authorized path contract while preserving the end-to-end path stack</name>
<files>packages-user/data-system/src/path/types.ts, packages-user/data-system/src/path/graph.ts, packages-user/data-system/src/path/finder.ts, packages-user/data-system/src/path/system.ts</files>
<read_first>packages-user/data-system/src/path/types.ts, packages-user/data-system/src/path/graph.ts, packages-user/data-system/src/path/finder.ts, packages-user/data-system/src/path/system.ts, packages-user/data-state/src/path/heroPathfinding.ts, .planning/phases/02-pathfinding/02-INTERFACE-DRAFT.md, .planning/phases/02-pathfinding/02-02-SUMMARY.md, dev.md</read_first>
<action>Use commit 7a011b2 as the exact user-owned contract baseline for packages-user/data-system/src/path/types.ts and reapply only the two authorized IPathfindingSystem return-type corrections: moveTo and teleportTo return IPathfindingController | null (D-07: user-authored contract is authoritative after review). Remove the later useMover/IObjectMover contract substitution, regions, and graph-helper interfaces from that file. Relocate IPathGraphEdge, IPathGraphNode, IPathGraph, and IPathfindingGraphBuilder to the implementation-owned graph.ts export surface, then update graph.ts and finder.ts imports accordingly. Keep the public IPathfinder/IPathfindingSystem behavior from the baseline, including useMovable; retain a concrete implementation-only mover bridge in system.ts so HeroPathfinding can continue to bind the existing IObjectMover without adding that bridge to the user-owned interface. Preserve D-01: minimum-loss search with custom cost support; D-02: directed reachable graph construction; D-03: IMapLayer and IObjectMovable binding; D-04: step and teleport modes with fallback; D-05: injectable event-aware fallback policy; D-06: path-only retrieval; D-09: existing hero mover hooks; and D-10: stop-then-await interruption handoff. Preserve the existing controller return behavior and L2-to-L3 dependency direction. Do not modify any client input code: D-11: this phase remains data-side and the mobile click adapter belongs to Phase 4.</action>
<verify>
<automated>node -e "const fs=require('node:fs'),cp=require('node:child_process'); const b=cp.execFileSync('git',['show','7a011b2:packages-user/data-system/src/path/types.ts'],{encoding:'utf8'}).replace(/\r\n/g,'\n').replaceAll('IPathfindingController;','IPathfindingController | null;'); const c=fs.readFileSync('packages-user/data-system/src/path/types.ts','utf8').replace(/\r\n/g,'\n'); if (b!==c) process.exit(1)"; if ($?) { pnpm exec vitest run "packages-user/data-system/src/path" "packages-user/data-state/src/path/heroPathfinding.test.ts" }</automated>
<fails_when>Non-zero exit, the normalized baseline comparison differs, or any focused Vitest suite reports a failed test.</fails_when>
</verify>
<done>types.ts differs from 7a011b2 only at the two authorized nullable return declarations; graph/search/hero integration tests pass through the restored contract with no client-side click wiring added.</done>
</task>
<task type="auto">
<name>Task 2: Close the nullable static event-source type gap</name>
<files>packages-user/data-state/src/hero/moverImpl.ts, .planning/phases/02-pathfinding/deferred-items.md</files>
<read_first>packages-user/data-state/src/hero/moverImpl.ts, packages-user/data-state/src/path/heroPathfinding.test.ts, packages-user/data-state/src/coreEventLayer.test.ts, .planning/phases/02-pathfinding/02-VERIFICATION.md, dev.md</read_first>
<action>Guard the loc.static event-source iteration before calling tileEvent(), while continuing to collect every dynamic tile event from loc.dynamics and preserving the existing priority ordering, trigger value, source-aware environment, and executor call. Update deferred-items.md to record the previously reported moverImpl.ts TS18047 diagnostic as resolved and leave the unrelated Phase 1 TileStore/type and legacy lint baselines unchanged. Preserve D-08: a target reached through allowed movement can receive the approved OnTouch behavior, while mask-blocked movement does not trigger it. Do not alter any Phase 1 source-aware event behavior.</action>
<verify>
<automated>$output = pnpm check:type 2>&1; $output; if ($output -match 'packages-user[\\/]data-state[\\/]src[\\/]hero[\\/]moverImpl\.ts\(') { exit 1 }; if ($?) { pnpm exec vitest run "packages-user/data-state/src/coreEventLayer.test.ts"; if ($?) { pnpm exec vitest run "packages-user/data-state/src/path/heroPathfinding.test.ts" } }</automated>
<fails_when>Non-zero focused test exit, or the type-check output contains any diagnostic path for moverImpl.ts.</fails_when>
</verify>
<done>moverImpl.ts produces no type diagnostic, static-null locations remain safe, dynamic event collection and Phase 1 event regressions pass, and the phase ledger identifies only the unrelated existing baselines as open.</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| User-authored path contract → L2 implementation | The implementation consumes a public interface whose shape is controlled by the user baseline and must not silently expand it. |
| Map location data → event-source collection | A nullable static tile and dynamic tile collection enter the movement event path. |
## STRIDE Threat Register
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|-----------|----------|-----------|----------|-------------|-----------------|
| T-02-06 | Tampering | path/types.ts public contract | medium | mitigate | Compare the final file to git baseline 7a011b2 after applying only the two authorized nullable return edits; keep graph helper contracts outside the user-owned file. |
| T-02-07 | Tampering/DoS | moverImpl.ts event-source loop | medium | mitigate | Narrow the nullable static value before method access, retain dynamic iteration, and run core-event plus hero-path integration tests. |
| T-02-SC | Tampering | npm/pip/cargo installs | low | accept | No package installation is part of this gap closure. |
</threat_model>
<verification>
- `pnpm exec vitest run "packages-user/data-system/src/path" "packages-user/data-state/src/path/heroPathfinding.test.ts"` passes after the contract restoration.
- `pnpm check:type` contains no diagnostic for `packages-user/data-state/src/hero/moverImpl.ts`; unrelated baseline diagnostics remain explicitly scoped in the ledger.
- `pnpm exec vitest run "packages-user/data-state/src/coreEventLayer.test.ts"` and the hero path integration test pass.
- A normalized baseline comparison proves path/types.ts has no unauthorized additions beyond the two nullable return corrections.
</verification>
<success_criteria>
The two verified gaps are closed: the user-owned contract is restored to its authorized scope, the phase-owned TS18047 error is absent, and the existing automatic pathfinding/event behavior remains green. Mobile click integration is not included because D-11 explicitly assigns that rendering concern to Phase 4.
</success_criteria>
<output>
Create `.planning/phases/02-pathfinding/02-04-SUMMARY.md` when done
</output>

View File

@ -0,0 +1,114 @@
---
phase: 02-pathfinding
plan: 05
type: execute
wave: 4
depends_on: ["02-03"]
files_modified:
- vite.config.ts
- package.json
autonomous: true
gap_closure: true
requirements: [PATH-01, PATH-02]
estimate:
tokens: 16000
raw_tokens: 16000
tasks: 2
confidence: low
must_haves:
truths:
- "The complete Vitest suite has enough hook timeout budget for the two phase suites whose beforeAll imports exceeded the default threshold under full-suite load."
- "The repository exposes a deterministic non-watch full-suite command that reports a passing run without timeout-induced skipped tests."
- "The quality gate validates the existing data-side path entry and does not introduce mobile click wiring contrary to D-11."
artifacts:
- "vite.config.ts"
- "package.json"
key_links:
- "Vitest reads the root Vite test configuration when `pnpm exec vitest run` or the repository test script executes."
- "The CI-style script invokes Vitest run mode rather than the existing watch-mode `pnpm test` script."
---
<objective>
Make the Phase 2 full-suite quality gate reliable by addressing the observed beforeAll timeout cascade and exposing a reproducible non-watch command that confirms the suite completes without skipped tests.
Purpose: Verification recorded two hook-timeout failures and eight tests skipped as a consequence of those failed hooks, even though focused path tests passed. The fix must stabilize the runner gate without changing pathfinding behavior or the D-11 rendering scope.
Output: Root Vitest timeout configuration and a deterministic `test:ci` package script, validated by repeated full-suite runs.
</objective>
<execution_context>
@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/02-pathfinding/02-VERIFICATION.md
@.planning/phases/02-pathfinding/02-VALIDATION.md
@.planning/phases/02-pathfinding/02-RESEARCH.md
@.planning/phases/02-pathfinding/02-03-SUMMARY.md
@vite.config.ts
@package.json
@packages-user/data-state/src/coreEventLayer.test.ts
@packages-user/data-state/src/path/heroPathfinding.test.ts
</context>
<tasks>
<task type="tracer">
<name>Task 1: Stabilize Vitest hook execution under the full-suite load</name>
<files>vite.config.ts</files>
<read_first>vite.config.ts, package.json, packages-user/data-state/src/coreEventLayer.test.ts, packages-user/data-state/src/path/heroPathfinding.test.ts, .planning/phases/02-pathfinding/02-VERIFICATION.md</read_first>
<action>Make the root configuration Vitest-aware by using the existing vitest/config defineConfig entry point and add explicit test and hook timeout budgets of 30 seconds. This addresses the observed default 10-second beforeAll failures in coreEventLayer.test.ts and heroPathfinding.test.ts while leaving test bodies, fixture behavior, plugin setup, aliases, and data/render separation unchanged. Do not alter any client action or map-pointer code; the Phase 2 data-side entry remains the only PATH-02 artifact per D-11.</action>
<verify>
<automated>$first = pnpm exec vitest run 2>&1; $first; if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }; $second = pnpm exec vitest run 2>&1; $second; if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }; $all = ($first + $second) -join "`n"; if ($all -match 'hook timed out|[1-9][0-9]* skipped|[1-9][0-9]* failed') { exit 1 }</automated>
<fails_when>Either full-suite run exits non-zero, or combined output reports a hook timeout, a positive skipped-test count, or a positive failed-test count.</fails_when>
</verify>
<done>Two consecutive executions of the existing full-suite command finish successfully without beforeAll hook timeouts, timeout-induced skipped tests, or failed tests.</done>
</task>
<task type="auto">
<name>Task 2: Add a reproducible CI-style full-suite entry point</name>
<files>package.json</files>
<read_first>package.json, .planning/phases/02-pathfinding/02-VALIDATION.md, dev.md</read_first>
<action>Add a `test:ci` script that invokes `vitest run` without watch mode, preserving the existing `test` script for interactive development. Use the already-installed Vitest dependency and do not add packages, reporters that hide failures, or a separate click-flow test that would contradict D-11. The command must be suitable as the phase-wide gate for PATH-01 and the delivered data-side PATH-02 entry.</action>
<verify>
<automated>$output = pnpm test:ci 2>&1; $output; if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }; if ($output -match 'hook timed out|[1-9][0-9]* skipped|[1-9][0-9]* failed') { exit 1 }</automated>
<fails_when>The test:ci command exits non-zero, or its output reports a hook timeout, a positive skipped-test count, or a positive failed-test count.</fails_when>
</verify>
<done>`pnpm test:ci` is a non-watch, zero-exit full-suite gate with no timeout-induced skipped tests, and the existing interactive `pnpm test` behavior is unchanged.</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| Test runner configuration → repository test execution | Timeout and script settings control whether initialization failures are surfaced or converted into skipped dependent tests. |
## STRIDE Threat Register
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|-----------|----------|-----------|----------|-------------|-----------------|
| T-02-08 | Denial of Service | Vitest beforeAll hooks | medium | mitigate | Set explicit hook/test budgets above the observed import cost and require two consecutive full-suite runs with no timeout or skipped-test summary. |
| T-02-09 | Repudiation | package test gate | low | mitigate | Add a named non-watch `test:ci` command and retain the complete Vitest exit status instead of masking failures. |
| T-02-SC | Tampering | npm/pip/cargo installs | low | accept | No package installation is part of this gap closure. |
</threat_model>
<verification>
- `pnpm exec vitest run` passes twice consecutively after the timeout configuration change.
- `pnpm test:ci` passes as the named non-watch full-suite gate.
- The full-suite output contains no hook timeout, skipped-test, or failed-test count.
- No client-side click handler or Phase 1 file is modified.
</verification>
<success_criteria>
The verified full-suite gap is closed: the suite completes reliably under the configured hook budget, dependent tests are not skipped by initialization timeouts, and a reproducible CI-style command exists for phase verification. The D-11 Phase 4 rendering boundary remains intact.
</success_criteria>
<output>
Create `.planning/phases/02-pathfinding/02-05-SUMMARY.md` when done
</output>