mirror of
https://github.com/motajs/template.git
synced 2026-10-29 12:20:17 +08:00
docs(10): plan advanced I mover and face-handler units
This commit is contained in:
parent
7cfb672b2a
commit
9114a652ee
@ -554,7 +554,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 →
|
||||
**Goal:** 重构过老、结构不佳、新人难懂的项目文档,面向多背景读者(完全新手 / 不懂代码的作者 / 有基础的作者 / AI Agent)提供分层指南。本阶段采用「伞阶段 + 增量派发」:每次只规划执行一个已派发的具体小任务。**第一批已派发 = 中级教程(`docs/intermediate/`,24 篇中文 markdown)+ 在 VitePress 站点注册它们 + 旧内容清空(D-04 并入本批)**(D-01..D-44)。**第二批已派发 = 高级教程 I(`docs/advanced/`,7 篇数据端文档)+ 站点注册 + 独立读者人格审阅 + 用户主导修订循环**(D-53..D-57)。**第三批已完成 = 高级教程 II「深入定制」(`docs/advanced/ii/`,10 篇数据端文档)+ 站点注册 + 独立读者人格审阅 + 用户主导修订循环**(D-67,2026-10-23 收尾)。
|
||||
**Requirements**: (无专属需求 ID;以 `10-CONTEXT.md` 的 D-01..D-74 为需求基线,验收锚在 D-09:用户人工审阅 + 链接全部有效 + 构建通过)
|
||||
**Depends on:** Phase 9
|
||||
**Plans:** 24/27 completed(第一批:中级教程 24 篇 + 站点注册 + D-09 复审修订;第二批:高级 I 7 篇 + 注册 + 读者审阅 + 用户修订循环;第三批:高级 II 10 篇 + 注册 + 读者审阅 + 用户修订循环)。**未完成 3 个**:`10-06`(中级全批验收)、`10-11`(中级读者审阅)、`10-12`(中级最终验收)——其范围已被后续 D-09 修订与高级 I/II 期间的最终状态覆盖,缺独立 SUMMARY,待补跑或并入后续验收。
|
||||
**Plans:** 24/32 completed(第一批:中级教程 24 篇 + 站点注册 + D-09 复审修订;第二批:高级 I 7 篇 + 注册 + 读者审阅 + 用户修订循环;第三批:高级 II 10 篇 + 注册 + 读者审阅 + 用户修订循环;第四批:高级 I 补写 2 篇 + 注册 + 读者审阅 + 用户修订循环,待执行)。**未完成 3 个**(第一批遗留):`10-06`(中级全批验收)、`10-11`(中级读者审阅)、`10-12`(中级最终验收)——其范围已被后续 D-09 修订与高级 I/II 期间的最终状态覆盖,缺独立 SUMMARY,待补跑或并入后续验收。
|
||||
|
||||
Plans:
|
||||
- [x] 10-01-PLAN.md — Wave 0:旧内容清空 + 站点注册(删除 `docs/guide`、`docs/dev`、`docs/logger`、`docs/api` 与首页 `docs/index.md`;清理 `config.ts` 旧 nav/sidebar 键并解除 apiSidebar/api 依赖;`api.ts` 加缺失目录守卫;新增 nav 入口 + `sidebar['/intermediate/']` 4 组/24 条;报告并等待 checkpoint)
|
||||
@ -584,9 +584,16 @@ Plans:
|
||||
- [x] 10-25-PLAN.md — 高级 II 导览 + 侧边栏注册(`/advanced/ii/` 九篇、分组名待用户确认)+ 互链与全量构建
|
||||
- [x] 10-26-PLAN.md — 高级 II 独立读者人格审阅(高代码能力人格,不同于高级 I)→ 问题清单 → 迭代修正(≤3 轮)→ 复审清零
|
||||
- [x] 10-27-PLAN.md — 高级 II 用户主导修订循环 → 用户确认 → 最终格式 / 构建 / SUMMARY 收尾
|
||||
- [ ] 10-28-PLAN.md — 高级 I 补写:移动 Mover(三件套 / 移动计划与执行 / 控制器 / 步骤类型 / 钩子 / 自定义移动器)
|
||||
- [ ] 10-29-PLAN.md — 高级 I 补写:FaceHandler 系列(`FaceDirection` / `FaceGroup` / `IFaceHandler` / 内置处理器 / 自定义处理器 / `IRoleFaceBinder`)
|
||||
- [ ] 10-30-PLAN.md — 高级 I 导览 7 → 9 + 侧边栏注册 + 两篇互链收口 + 全量构建
|
||||
- [ ] 10-31-PLAN.md — 两篇补写内容的独立读者审阅(沿用高级 I 人格)→ 问题清单 → 迭代修正(≤3 轮)→ 复审清零
|
||||
- [ ] 10-32-PLAN.md — 两篇补写内容的用户主导修订循环 → 用户确认 → 最终格式 / 构建 / SUMMARY 收尾
|
||||
|
||||
**说明:** 每篇中级教程遵循 `10-CONTEXT.md` D-21..D-44 的逐篇要点与阅读顺序(4/8/9/3)。**旧内容删除已并入本批(D-04,Wave 0 / 10-01)**:删除 `docs/guide/*`、`docs/dev/*`、`docs/logger/*`、`docs/api/*` 与首页 `docs/index.md`,并清理 `docs/.vitepress/config.ts` 的旧 `nav`/`sidebar` 键。文档改动为 `docs/intermediate/*.md`(新增)、`docs/.vitepress/config.ts` 与 `docs/.vitepress/api.ts`(缺失目录守卫,保留按包生成机制)。构建命令 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`;`init.ts` 在 `docs/api/` 缺失时安全跳过。本机 PowerShell 禁止 `pnpm.ps1`,命令经 `cmd /c "..."` 执行。
|
||||
|
||||
**高级 I 说明:** 第二批(10-13..10-20)只写**数据端**内容,不含渲染端;七篇文件名与侧边栏显示名以各计划 Task 0 的用户确认为准(D-13)。指向高级 II / III 的内容一律使用代码 span 或 HTML 注释占位,不写真实链接(D-47)。每篇保留「怎么验证」小节,并按 D-48 六步 / D-49 改内置优先 / D-50 模板独立 / D-51 落点与副作用 / D-52 加粗边界执行。构建命令同上;10-18 负责站点注册与全量链接收口,10-19 / 10-20 分别执行独立读者人格审阅与用户主导修订循环,**用户明确确认后方可收尾**(D-46 第 2 阶段 / D-57)。
|
||||
|
||||
**高级 II 说明(已完成):** 第三批(10-21..10-27)按 D-67 / D-53 定位为「深入定制」**难度层**(难度标签,非领域分类),只写**数据端**内容;已建 `docs/advanced/ii/` **10 篇**(导览 + 8 个主题 + 点事件与图块事件)。写作按 D-59 库文档风格、D-60 简洁、D-61 主干与边界分离、D-62/D-70 代码块完整、D-63 模板顺序、D-64 只在需实现接口时给模板、D-65 注释充足、D-66 并列功能分开示例、D-69 内部实现章节后置;读者水平按 D-68(已理解绝大多数常用语法,认真阅读后能读明白一部分简单与中等复杂度系统,不预设资深开发者)。侧边栏分组名「高级 II · 深入定制」。渲染端 / 编辑器 / 状态栏 / 怪物图鉴按 D-47 非断链占位;高级 III 只用代码 span 或 `TODO(advanced-III)` 注释。10-25 负责导览与站点注册,10-26 执行独立读者审阅,10-27 执行用户主导修订循环,**用户已明确确认**(D-46 第 2 阶段)并于 2026-10-23 收尾。构建命令同上。
|
||||
|
||||
**高级 I 补写说明(第四批,待执行):** 按 D-75 / D-71,为高级 I 补两篇数据端文档——`docs/advanced/mover.md`(移动 Mover)与 `docs/advanced/face-handler.md`(FaceHandler 系列)。写作按高级 I 读者水平(D-57:了解基本语法、代码能力一般、不熟悉引擎内部架构)与 D-59..D-74 库文档风格;渲染端 / 编辑器按 D-47 非断链占位。10-28 / 10-29 并行写两篇(互引先用代码 span),10-30 负责导览 7 → 9、侧边栏注册与互链收口,10-31 执行独立读者审阅(沿用 10-19 已确认的高级 I 人格),10-32 执行用户主导修订循环,**用户明确确认后方可收尾**。文件名、页面标题、侧边栏显示名与示例标识符名以各计划 Task 0 的用户确认为准(D-13)。D-75 写的 `IMoveController` 与源码 `IMoverController` 不一致,以源码为准。
|
||||
|
||||
186
.planning/phases/10-docs-restructure/10-28-PLAN.md
Normal file
186
.planning/phases/10-docs-restructure/10-28-PLAN.md
Normal file
@ -0,0 +1,186 @@
|
||||
---
|
||||
phase: 10-docs-restructure
|
||||
plan: 28
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- docs/advanced/mover.md
|
||||
- .planning/phases/10-docs-restructure/10-28-SUMMARY.md
|
||||
autonomous: false
|
||||
requirements: []
|
||||
user_setup: []
|
||||
estimate:
|
||||
tokens: 26000
|
||||
raw_tokens: 17000
|
||||
tasks: 3
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "`docs/advanced/mover.md` 存在,kebab-case、CRLF、单 H1「移动 Mover」"
|
||||
- "讲清三件套的分工:`IObjectMovable`(被移动对象)、`IObjectMover`(移动器)、`IMoverController`(一次执行的句柄);说明「先排计划、再执行」是本篇的主线"
|
||||
- "讲清链式规划接口:`step` / `stepFace` / `forward` / `backward` / `face` / `tp` / `jump` / `speed` / `animDir` / `push` / `clear`,并说明 `speed` 与 `animDir` 只设置后续步骤的参数、`face` 只转向、`forward` 以移动方向为基准、`backward` 以当前朝向的反方向为基准、`tp` / `jump` 的 `rel` 含义"
|
||||
- "讲清执行模型与异步语义:`start()` 取队列快照并清空待执行队列、已在移动时返回 `null`、`start()` 会把 `moveDirection` 重置为 `Unknown`、`moving` / `done` / `onEnd`、`controller.push` / `insert` / `stop` 的时机、执行期间用 `mover` 上的链式方法追加不会进入当前这一次执行(只能用 `controller.push`)"
|
||||
- "讲清 `IObjectMoverHooks` 七个钩子:`onMoveStart` / `onMoveEnd` / `onStepStart` / `onStepEnd` / `onSetPos` / `onSetFaceDir` / `onSetMoveDir`;`code` 由 `onStepStart` 传递到 `onStepEnd`;异步钩子由 `Promise.all` 并发等待"
|
||||
- "给出可实现的扩展路径:`ObjectMover` 子类的完整模板(五个抽象方法 + `[需改]`)与一个最小可移动对象 + 最小移动器示例;示例为 class + new,注释充足(D-65)"
|
||||
- "纯内部实现(执行流程源码顺序)单独成节、放在靠后位置,并以「此章节讲解一下移动器的内部执行流程」开头(D-69)"
|
||||
- "数据端 only;渲染端 / 编辑器内容按 D-47 用非断链占位;与 `face-handler.md` 的互引先用代码 span,真实链接由 10-30 统一收口"
|
||||
- "不改 `config.ts`、生产代码与渲染端内容;构建 green、`build complete`、dead link = 0"
|
||||
artifacts:
|
||||
- "docs/advanced/mover.md"
|
||||
- ".planning/phases/10-docs-restructure/10-28-SUMMARY.md"
|
||||
key_links:
|
||||
- "D-75 第 1 项:高级 I 补写「移动 Mover」,补齐 D-71 记录的两个缺口之一"
|
||||
- "`packages-user/data-common/src/common/mover.ts` 是唯一权威来源;`ObjectMover` 的执行流程、控制器语义与钩子签名逐条以它为准"
|
||||
- "向上接 `./hooks-in-depth.md`(`IObjectMoverHooks` 属于该篇讲的多对象钩子族)、`./replay-consistency.md`(`@shouldReplay` 标在步进方法上)、`./ii/static-vs-dynamic-tiles.md`(动态图块的移动器)"
|
||||
---
|
||||
|
||||
<objective>
|
||||
编写高级 I 补写篇目之一:`docs/advanced/mover.md`(移动 Mover)。讲清移动器的三件套分工、移动计划怎么排、执行与异步等待怎么用、步骤类型、控制器语义、`IObjectMoverHooks` 钩子,以及如何通过继承 `ObjectMover` 扩展出自己的移动器。
|
||||
|
||||
Purpose: 中级教程只讲「获取勇士位置」(`hero-location`),移动位置留给高级;高级 II 的寻路、动态图块又反复出现「拿到移动器、排几步、等它走完」。缺这一篇,读者看到 `state.hero.location.mover` 只能猜。D-75 明确要求补上,且要讲「怎么用、怎么改/扩展」。
|
||||
Output: 1 个新 markdown 文件(`docs/advanced/mover.md`)。
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/13194/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/13194/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/phases/10-docs-restructure/10-CONTEXT.md
|
||||
@docs/advanced/index.md
|
||||
@docs/advanced/hooks-in-depth.md
|
||||
@docs/advanced/replay-consistency.md
|
||||
@docs/advanced/ii/static-vs-dynamic-tiles.md
|
||||
@docs/advanced/ii/pathfinding.md
|
||||
@docs/intermediate/hero-location.md
|
||||
@packages-user/data-common/src/common/mover.ts
|
||||
@packages-user/data-common/src/common/types.ts
|
||||
@packages-user/data-base/src/map/mover.ts
|
||||
@packages-user/data-base/src/hero/mover.ts
|
||||
@packages-user/data-base/src/hero/types.ts
|
||||
@packages-user/data-base/src/map/dynamicTile.ts
|
||||
@packages/common/src/utils/types.ts
|
||||
|
||||
**写作规范(高级 I,逐条遵守):**
|
||||
- 读者水平按 D-57:了解基本语法(变量、函数、类、`import`),代码能力一般,不熟悉引擎内部架构;不预设高代码水平,也不当成完全不懂代码。
|
||||
- 按一般库文档方式写(D-59):概念 → 完整示例(含解释性注释)→ 接入位置;不用中级教程的「复制什么 / 改什么」六步。
|
||||
- 简洁优先(D-60):中级已讲过的(位置 `x` / `y`、`hero.location`)不重复;能删就删。
|
||||
- 主干与边界分离(D-61):特殊情况集中到文末「边界与注意」。
|
||||
- 代码块结构完整(D-62 / D-70):完整类 / 完整函数,不写脱离上下文的成员片段。
|
||||
- 模板组织顺序(D-63):先讲理念 → 引导语 → 模板 → 解释模板;只有需要读者自己实现接口时才给模板(D-64)。
|
||||
- 示例注释越多越好(D-65);并列功能分开示例(D-66)。
|
||||
- 纯内部实现章节靠后,并以「此章节讲解一下 XXX 的内部实现」开头(D-69)。
|
||||
- 注释与实现不一致时以方法注释为准,并在对话中向用户报告,不把实现写进注释语义(D-72)。
|
||||
- 假定编辑器已完成(D-73);引用其他文档的具体章节用 `./xxx.md#标题`(D-74)。
|
||||
- 数据端 only;渲染端 / 编辑器相关内容按 D-47 用代码 span 或 HTML 注释占位,不写真实链接、不写 `src/client`。
|
||||
- 加粗边界:`**` 相邻处不得是标点(D-52)。
|
||||
|
||||
**源码事实(写作时逐条核对,勿凭印象):**
|
||||
- 三件套都在 `packages-user/data-common/src/common/mover.ts`:`IObjectMovable`(`x` / `y` / `setPos` / `getCurrentFaceDirection`)、`IObjectMover`(链式规划 + 状态 + `start`)、`IMoverController`(`done` / `onEnd` / `push` / `insert` / `stop`)。
|
||||
- **命名更正:** D-75 写作 `IMoveController`,源码实际是 `IMoverController`。文档按源码写,并在 Task 0 向用户说明(D-13 / D-72)。
|
||||
- 步骤联合类型 `ObjectMoveStep` 有 8 种:`Dir` / `DirFace` / `Speed` / `Face` / `Special` / `AnimDir` / `Teleport` / `Jump`;对应的 `type` 常量来自 `ObjectMoveType`;`ObjectSpecialStep` 有 `Forward` / `Backward`;`ObjectAnimDirection` 有 `Forward` / `Backward`。
|
||||
- `step(dir, count)` 追加 `Dir`;`stepFace(move, face, count)` 追加 `DirFace`;`forward(count)` / `backward(count)` 追加 `Special`;`face(dir)` 追加 `Face`;`speed(value)` 追加 `Speed`(单位 ms/格,默认 `currentSpeed = 100`);`animDir(dir)` 追加 `AnimDir`;`tp(x, y, rel)` 追加 `Teleport`;`jump(x, y, rel)` 追加 `Jump`;`push(steps)` 一次追加数组;`clear()` 清空尚未执行的队列。
|
||||
- `start()`:已在移动时返回 `null`;否则把 `moveQueue` 切片成局部队列、调用 `clear()` 清空内部队列、`shouldStop = false`、`moveDirection` 重置为 `Unknown`,返回控制器并驱动执行。
|
||||
- 执行顺序(`moveProgress`):`onMoveStart`(子类)→ 钩子 `onMoveStart`(`Promise.all`)→ 每个步骤:`prepareStep`(先同步更新内部状态)→ `onStepStart`(返回 `code`)→ 钩子 `onStepStart` → `onStepEnd`(返回落点 `ITileLocator`)→ 坐标变化时 `tile.setPos` → `onStepSettled` → 钩子 `onStepEnd` → 全部步骤结束后 `onMoveEnd` → 钩子 `onMoveEnd`。
|
||||
- 控制器:`push` / `insert` 只在仍在移动、未 `stop`、未 `done` 时生效;`insert` 把步骤放在「当前步之后」;`stop()` 把 `shouldStop` 置真并返回 `onEnd`,当前步会走完再停;`done` 在整次执行结束时置真,`onEnd` 同时兑现。
|
||||
- **执行期间的坑:** `moveProgress` 用的是 `start()` 时的局部队列快照;执行期间再调用 `mover.step` / `mover.face` 等只会写回内部 `moveQueue`,不会被当前这一次执行消费。要在执行中追加,只能用 `controller.push` / `controller.insert`。
|
||||
- `prepareStep` 的语义:`Dir` 同时写移动方向与朝向;`DirFace` 分开写;`Face` 只写朝向;`Special` 前进用当前朝向、后退用 `faceHandler.opposite(当前朝向)` 并保持朝向不变;`Speed` 写 `currentSpeed`;`AnimDir` 写 `currAnimDir`。
|
||||
- `setPos` / `setFaceDir` / `setMoveDir` 立即生效、不排队,并分别触发 `onSetPos` / `onSetFaceDir` / `onSetMoveDir`;这三个钩子是同步的(返回 `void`)。
|
||||
- 参考实现:`packages-user/data-base/src/hero/mover.ts`(`HeroMover` 继承 `ObjectMover`,实现边检、通行判断、撞击、步前步后事件,并在步进方法上标 `@shouldReplay`)、`packages-user/data-base/src/map/mover.ts`(`DynamicTileMover`,最小实现:只处理 8 种步骤的落点)。
|
||||
- 现成入口:`state.hero.location.mover`(`IHeroMover`,另有 `config` / `getConfig` / `useTopImplementation`)、动态图块的 `mover` 字段;`IHeroMover` 与 `HeroMoveCode` 在 `packages-user/data-base/src/hero/types.ts`。移动器拿到的朝向处理器是 `IFaceHandler`(`packages/common/src/utils/types.ts`),本篇只说明「构造时要传一个」,细节由 10-29 的 `FaceHandler 系列` 承担。
|
||||
- 通行性不在移动器里:`HeroMover` 把判断交给顶层实现对象(`IHeroMoveTopImpl` 的 `predicate` / `inBound`)。自定义移动器只负责「这一步落到哪」,通行判定属于调用方。
|
||||
- 录像:`HeroMover` / `DynamicTileMover` 在会改状态的步进方法上标了 `@shouldReplay`;自定义移动器若要让移动进录像,同样标在改状态的方法上(详见 `./replay-consistency.md`)。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking-human">
|
||||
<name>Task 0: 向用户汇报本计划并等待「可以执行」</name>
|
||||
<action>向用户汇报:**要做什么**(新增 `docs/advanced/mover.md`,讲移动器三件套、移动计划、执行与异步等待、步骤类型、控制器、钩子与自定义移动器)、**为什么**(D-75 / D-71 要求补「移动 Mover」;中级只讲获取位置,高级 II 的寻路与动态图块又反复用到移动器,缺这篇读者只能猜)、**大致怎么做**(先讲三件套与「先排计划再执行」的主线,再讲链式接口与步骤类型、执行与控制器语义、状态与钩子,然后给 `ObjectMover` 子类模板与最小可移动对象示例,最后是内部执行流程(D-69 靠后)、边界与注意、「怎么验证」)、**影响范围**(仅新增 1 个 `docs/advanced/*.md`;不改 `config.ts`、生产代码与渲染端内容;侧边栏注册由 10-30 负责)。请用户确认三件事:① 文件名 `mover.md` 与页面标题「移动 Mover」(D-13);② 示例中会出现的标识符名:被移动对象 `SimpleTile`、移动器 `SimpleMover`、结果码 `SimpleMoveCode`(如不同意请给替代名);③ **命名更正**:D-75 写的 `IMoveController` 在源码里是 `IMoverController`,文档将以源码为准。汇报中明确:本计划的修改方式为**派发子代理执行**,范围严格限于 `docs/advanced/mover.md` 与 `.planning/.../10-28-SUMMARY.md`,执行者不内联修改文档。停下等待用户明确回复「可以执行」四个字;未收到前不得写任何文件。</action>
|
||||
<what-built>本计划内容:高级 I 补写篇目「移动 Mover」。</what-built>
|
||||
<how-to-verify>阅读上面的四段说明,确认文件名 / 标题 / 示例标识符名与 `IMoverController` 的命名更正;如不同意请给出替代。</how-to-verify>
|
||||
<resume-signal>回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。</resume-signal>
|
||||
<verify>
|
||||
<human-check>用户已回复「可以执行」,且未对文件名 / 页面标题 / 示例标识符名提出替代。</human-check>
|
||||
</verify>
|
||||
<done>用户回复「可以执行」。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: 编写 mover.md 正文</name>
|
||||
<files>docs/advanced/mover.md</files>
|
||||
<action>(1) 新建 `docs/advanced/mover.md`,单 H1 为「移动 Mover」。(2) 开头用两三段说清问题:对象要从一格走到另一格;移动器把「想怎么走」和「实际怎么走」分开——先用链式调用排出移动计划,`start()` 后才按步执行,每一步落点由子类决定;并说明本篇讲数据端的移动器,画面上的移动表现由渲染端负责(按 D-47 用代码 span 占位,不写 `src/client`)。(3) 正文按以下顺序组织,每节只讲一件事:
|
||||
① `## 三个角色`:表格列 `IObjectMovable`(被移动对象:`x` / `y` / `setPos` / `getCurrentFaceDirection`)、`IObjectMover`(移动器:规划 + 执行 + 状态)、`IMoverController`(一次执行的句柄:`done` / `onEnd` / `push` / `insert` / `stop`);说明继承关系是「对象实现 `IObjectMovable`,移动器持有对象」。
|
||||
② `## 拿到现成的移动器`:`state.hero.location.mover`(`IHeroMover`,额外提供 `config` / `getConfig` / `useTopImplementation`)与动态图块的 `mover` 字段;说明这两个都是引擎已经建好的实例,不要重复 `new`;链接 `../intermediate/hero-location.md` 与 `./ii/static-vs-dynamic-tiles.md`。
|
||||
③ `## 排一个移动计划`:给链式接口表(方法 / 追加的步骤类型 / 作用),逐条讲:`step` 一步一方向并同步朝向;`stepFace` 移动与朝向分开;`forward` 沿当前移动方向;`backward` 沿当前朝向的反方向且朝向不变;`face` 只转向不移动;`tp` 瞬移;`jump` 跳跃(数据端只体现为直接落到目标格);`speed` 设置每格耗时(ms);`animDir` 设置动画播放方向;`push` 追加一组步骤;`clear` 清空尚未执行的队列。明确 `speed` / `animDir` 只是写状态,本身不产生移动,由消费方(渲染端)读取。
|
||||
④ `## 执行与等待`:`start()` 返回控制器或 `null`(已在移动);用 `controller.onEnd` 等待整次移动结束,或用 `controller.done` 查询;给一个完整示例:勇士先向右走两格、转向下、再走一格,`await controller.onEnd` 后打印坐标。示例含解释性注释、标注 `[需改]`。同时点明 `start()` 会把 `moveDirection` 重置为 `Unknown`,所以 `forward()` 之前必须先有 `step` / `stepFace`。
|
||||
⑤ `## 执行中追加、插入与停止`:`controller.push` 追加到队列末尾、`controller.insert` 插到当前步之后、`controller.stop()` 返回 `onEnd` 且当前步走完后才停;说明停止后 `done` 变真,想继续走要重新排计划并 `start()`。**并给出关键边界**:执行期间调用移动器自身的 `step` / `face` 等方法只会写回内部待执行队列,不会被当前这次执行消费;执行中要追加,只能用控制器。
|
||||
⑥ `## 步骤类型`:`ObjectMoveStep` 联合类型表(`type` / 字段 / 效果),八种逐一对应 `ObjectMoveType`;说明自定义移动器必须自己处理这些 `type`,未识别的类型应当原样返回当前坐标。
|
||||
⑦ `## 移动器状态`:`moving` / `faceDirection` / `moveDirection` / `currAnimDir` / `currentSpeed` / `faceHandler`;说明 `setPos` / `setFaceDir` / `setMoveDir` 是立即生效、不排队,并会触发对应钩子;`faceDirection` 是朝向、`moveDirection` 是移动方向,二者在 `stepFace` / `backward` 下会不同。
|
||||
⑧ `## 钩子`:`IObjectMoverHooks` 表(钩子 / 触发时机 / 参数 / 是否异步);讲清 `code` 由 `onStepStart` 的返回值一路传到 `onStepEnd`;`onStepStart` 时坐标仍是移动前,`onStepEnd` 时坐标已更新;异步钩子由 `Promise.all` 并发等待,不要依赖彼此的先后(链接 `./hooks-in-depth.md`);`onSetPos` / `onSetFaceDir` / `onSetMoveDir` 只由对应的 setter 触发。
|
||||
⑨ `## 实现自己的移动器`:先讲什么时候需要自己写(现有 `HeroMover` / `DynamicTileMover` 不满足需求时),再给「模板:一个自定义移动器」——`class SimpleMover extends ObjectMover` 的完整类骨架,构造里接收对象与朝向处理器,实现 `onMoveStart` / `onMoveEnd` / `onStepStart` / `onStepEnd` / `onStepSettled` 五个抽象方法,并用 `const enum SimpleMoveCode` 定义自己的结果码;模板后用文字解释每个方法的职责、`onStepEnd` 返回落点而坐标由基类写入、`onStepSettled` 在坐标更新之后运行、五个方法都是 `protected` 不能被外部调用;用 `[需改]` 标出需要按需求修改的部分。
|
||||
⑩ `## 示例:一个最小可移动对象`:给 `class SimpleTile implements IObjectMovable`(`x` / `y`、`setPos`、`getCurrentFaceDirection`)与一个只处理四方向与瞬移的最小移动器,演示「方向 → 偏移 → 落点」的完整链路;说明通行判断不在移动器里,由调用方负责(`HeroMover` 就是交给顶层实现对象的)。
|
||||
⑪ `## 与录像、存档的关系`:`HeroMover` / `DynamicTileMover` 把 `@shouldReplay` 标在会改状态的步进方法上,所以移动会进录像;自定义移动器同理(链接 `./replay-consistency.md`)。位置本身是存档内容,移动过程不产生存档条目。
|
||||
⑫ `## 内部执行流程`(D-69,靠后):以小标题开头写「此章节讲解一下移动器的内部执行流程」,然后按源码顺序讲 `start` → 队列快照 → `prepareStep` → 步内五个阶段 → 钩子并发等待;只讲与使用相关的时序,不逐行翻译源码。
|
||||
⑬ `## 边界与注意`(D-61):集中列 `start` 返回 `null`、`moveDirection` 被重置、执行期间链式方法无效、`stop` 不立刻中断、`setPos` 不触发步进钩子、`speed` / `animDir` 只是状态、`faceHandler` 必须与对象方向体系一致、无人读取 `currentSpeed` 时速度不产生可见效果(渲染端占位)等。
|
||||
⑭ `## 怎么验证`:给可操作的自检——排三步后打印移动前后的 `x` / `y`、`controller.done`、钩子打印顺序;执行中 `controller.push` 一步看是否被消费;`stop()` 后看是否停在当前步末尾。
|
||||
(4) 提到朝向处理器时只用代码 span 写 `FaceHandler 系列`,不写指向 `face-handler.md` 的相对链接(该页由并行计划 10-29 创建,链接由 10-30 统一收口);提到高级 III / 编辑器内容一律用代码 span 或 HTML 注释占位。不要写 `src/client`、不要写「后续再讲」式元叙述、不要给中级教程的六步实操。完成后跑 prettier `--write`。Commit:`docs(10-28): 编写移动 Mover 文档`。</action>
|
||||
<verify>
|
||||
<automated>$ErrorActionPreference='Stop'; $p='docs/advanced/mover.md'; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($raw -match "(?<!`r)`n"){ Write-Error "LF-ONLY $p" }; if(([regex]::Matches($raw,'(?m)^# ')).Count -ne 1){ Write-Error "H1-COUNT $p" }; foreach($needle in @('IObjectMovable','IObjectMover','IMoverController','ObjectMoveStep','ObjectMover','IObjectMoverHooks','moveDirection','currentSpeed','animDir','onEnd','start()','怎么验证','边界与注意','此章节讲解一下')){ if($raw -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-CONTENT $needle" } }; foreach($needle in @('state.hero.location.mover','DynamicTile','shouldReplay','controller.push','stop()')){ if($raw -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-DETAIL $needle" } }; if($raw -match 'src/client'){ Write-Error "RENDERER-CONTENT" }; if($raw -match '\*\*[,。!?;:、()《》「」『』【】,.!?;:\(\)\[\]{}"'']' -or $raw -match '[,。!?;:、()《》「」『』【】,.!?;:\(\)\[\]{}"'']\*\*'){ Write-Error "BOLD-FLANK" }; foreach($m in [regex]::Matches($raw,'\]\((\.{1,2}/[^)#]+\.md)(#[^)]*)?\)')){ $t=Join-Path (Split-Path -Parent $p) $m.Groups[1].Value; if(-not(Test-Path -LiteralPath $t)){ Write-Error ("DEAD-LINK " + $m.Groups[1].Value) } }; Write-Output 'STATIC-OK'</automated>
|
||||
<fails_when>non-zero exit, or output contains "MISSING", "LF-ONLY", "H1-COUNT", "MISSING-CONTENT", "MISSING-DETAIL", "RENDERER-CONTENT", "BOLD-FLANK", or "DEAD-LINK"; or output lacks "STATIC-OK"</fails_when>
|
||||
</verify>
|
||||
<done>文件存在、CRLF、单 H1;三件套、链式接口、执行与控制器、步骤类型、状态、钩子、模板与最小示例、内部执行流程(D-69)、边界与注意、「怎么验证」齐全;无渲染端内容;无死链。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: 源码核对、格式与构建收口</name>
|
||||
<files>docs/advanced/mover.md, .planning/phases/10-docs-restructure/10-28-SUMMARY.md</files>
|
||||
<action>逐条核对正文与源码,确认没有把语义写反:① `packages-user/data-common/src/common/mover.ts`——五个抽象方法的签名与调用顺序、`prepareStep` 对 `Special` 的朝向/移动方向处理(后退用 `opposite` 且朝向不变)、`start` 对队列的切片与清空、`moveDirection` 重置、`shouldStop` 与 `stop` 的兑现时机、`done` / `onEnd` 的设置点、`push` / `insert` 的生效条件、`onStepEnd` 后先 `setPos` 再 `onStepSettled`。② `packages-user/data-base/src/hero/mover.ts`——`@shouldReplay` 标在哪些方法上、通行判断交给顶层实现、`cannotEnter` / `hit` 后调用 `controller.stop()`(并说明此处不能 `await`)。③ `packages-user/data-base/src/map/mover.ts`——最小实现如何只处理落点。④ `packages-user/data-base/src/hero/types.ts`——`IHeroMover` 的 `config` / `getConfig` / `useTopImplementation`、`IHeroMoverConfig` 三个字段、`HeroMoveCode` 四个值。⑤ `packages/common/src/utils/types.ts`——`IFaceHandler` 方法名与 `IFaceDescriptor` 形状,确认正文只写「构造时要传朝向处理器」而不展开 FaceHandler 细节。若发现源码注释与实现不一致(例如某方法的行为与注释描述不符),**只向用户报告,不写进文档、不擅自记录为问题**(AGENTS.md / D-72)。然后跑 prettier `--write`,再跑构建门禁 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,确认 green、`build complete`、dead link = 0。写 `.planning/phases/10-docs-restructure/10-28-SUMMARY.md`:章节结构、引用的源码落点、核对到的关键语义、构建与格式结论、向用户报告的不一致(若无可写「无」)。Commit:`docs(10-28): 核对源码并收口移动文档`。</action>
|
||||
<verify>
|
||||
<automated>$ErrorActionPreference='Stop'; $p='docs/advanced/mover.md'; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); foreach($needle in @('onStepSettled','内部执行流程','ObjectSpecialStep','rel','Promise.all','stop')){ if($raw -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-AFTER-CHECK $needle" } }; $sum='.planning/phases/10-docs-restructure/10-28-SUMMARY.md'; if(-not(Test-Path -LiteralPath $sum)){ Write-Error "MISSING $sum" }; $s=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $sum)); foreach($needle in @('mover.md','构建','源码')){ if($s -notmatch [regex]::Escape($needle)){ Write-Error "SUMMARY-MISSING $needle" } }; $ErrorActionPreference='Continue'; $pf = cmd /c "node node_modules/prettier/bin/prettier.cjs --check docs/advanced/mover.md" 2>&1; $pfe=$LASTEXITCODE; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($pfe -ne 0){ $pf | Write-Output; Write-Error "PRETTIER-FAIL" }; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'GATE-OK'</automated>
|
||||
<fails_when>non-zero exit, or output contains "MISSING", "MISSING-AFTER-CHECK", "SUMMARY-MISSING", "PRETTIER-FAIL", "BUILD-FAIL", "NO-BUILD-COMPLETE", or "DEAD-LINK"; or output lacks "GATE-OK"</fails_when>
|
||||
</verify>
|
||||
<done>正文语义与 `mover.ts` / `hero/mover.ts` / `map/mover.ts` / `hero/types.ts` 逐条一致;注释不一致已向用户报告且未写入文档;prettier 通过;构建 green、`build complete`、dead link = 0;SUMMARY 已写。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 构建期 markdown → 静态站点 | 正文由构建期静态渲染,无运行时输入 |
|
||||
| 站点 → 浏览器读者 | 站内链接是唯一可点击指向面 |
|
||||
| 执行者 → 子代理 | 写作子代理只改 `mover.md`,不触碰配置与生产代码 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-10-82 | Tampering / XSS | `mover.md` 正文与代码块 | low | mitigate | 只写文本、代码块、表格;不引入原始 `<script>` 或内联 HTML |
|
||||
| T-10-83 | Spoofing | 站内链接 | low | mitigate | 只链已存在页面;逐条断言相对 `.md` 目标存在;与 `face-handler.md` 的互引由 10-30 收口 |
|
||||
| T-10-84 | Information Disclosure | 正文示例 | low | mitigate | 只用源码已公开的接口与路径;不写密钥、账号 |
|
||||
| T-10-SC | Tampering | npm/pip/cargo installs | low | accept | 本阶段不安装任何包,无供应链安装面 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- 结构门禁:`docs/advanced/mover.md` 存在、kebab-case、CRLF、单 H1。
|
||||
- 内容门禁:三件套、链式接口与步骤类型、执行与控制器语义、状态、钩子、扩展模板、最小示例、内部执行流程(D-69 靠后且带开头说明)、边界、怎么验证齐全。
|
||||
- 事实门禁:`start` 快照 / 清空 / 重置 `moveDirection`、执行期链式方法无效、`stop` 完成当前步、`code` 传递、`Promise.all` 并发,逐条与 `mover.ts` 一致。
|
||||
- 边界门禁:无渲染端内容;不改 `config.ts` 与生产代码。
|
||||
- 格式门禁:prettier `--check` 通过。
|
||||
- 构建门禁:`cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"` 通过,`build complete`,dead link = 0。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- 读者看完能用现成移动器排出并等待一次移动,也知道执行中该怎么追加、什么时候会静默无效。
|
||||
- 读者需要自定义时,能照着模板实现一个 `ObjectMover` 子类,并知道哪五个方法必须实现、落点由谁写入坐标。
|
||||
- 构建通过、无死链、无渲染端内容;向用户报告的不一致(如有)已记录。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/10-docs-restructure/10-28-SUMMARY.md` when done
|
||||
</output>
|
||||
182
.planning/phases/10-docs-restructure/10-29-PLAN.md
Normal file
182
.planning/phases/10-docs-restructure/10-29-PLAN.md
Normal file
@ -0,0 +1,182 @@
|
||||
---
|
||||
phase: 10-docs-restructure
|
||||
plan: 29
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- docs/advanced/face-handler.md
|
||||
- .planning/phases/10-docs-restructure/10-29-SUMMARY.md
|
||||
autonomous: false
|
||||
requirements: []
|
||||
user_setup: []
|
||||
estimate:
|
||||
tokens: 26000
|
||||
raw_tokens: 17000
|
||||
tasks: 3
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "`docs/advanced/face-handler.md` 存在,kebab-case、CRLF、单 H1「FaceHandler 系列」"
|
||||
- "讲清三个概念的分工:`FaceDirection` 是方向值、`FaceGroup` 是「这一组认哪些方向」的编号、`IFaceHandler` 负责把方向换算成偏移 / 反方向 / 旋转;`IFaceDescriptor` 是 `{ x, y }` 增量"
|
||||
- "讲清 `IFaceHandler` 八个方法的语义:`degrade` / `movement` / `move` / `opposite` / `next` / `dirOf` / `mapDirection` / `mapMovement`,并说明哪些方法内部先经过 `degrade`、`Unknown` 的返回值、`mapMovement` 含 `Unknown` 对应零偏移"
|
||||
- "讲清两个内置处理器:`Dir8FaceHandler`(八方向,`degrade` 原样返回)与 `Dir4FaceHandler`(四方向,`degrade` 把斜向折到左右,不是折到上下);`get` / `getById` 找不到返回 `null`;注册位置在 `src/data/initialize.ts` 的 `FaceGroup.Dir4` / `FaceGroup.Dir8` 与 `'dir4'` / `'dir8'`"
|
||||
- "讲清 `IRoleFaceBinder`(`state.roleFace`):`malloc` / `bind` / `getFaceOf` / `getFaceDirection` / `getMainFace`;`bind` 必须先 `malloc`;`getFaceOf` 找不到返回 `null`;说明它是「朝向 → 图块数字」的映射,与逻辑朝向分层"
|
||||
- "给出可实现的扩展路径:自定义 `IFaceHandler` 的完整模板(含「把四方向的斜向降级折到上下」的可运行示例),说明注册后哪些使用方会生效(移动器构造、寻路 `useFaceHandler`)"
|
||||
- "讲清与另外两处的关系:移动器构造时传入朝向处理器(代码 span 指向 `移动 Mover`,真实链接由 10-30 收口);寻路 `useFaceHandler` 与范围对象的 `IFaceDescriptor` 列表(真实链接到高级 II 两篇)"
|
||||
- "数据端 only;渲染端 / 编辑器内容按 D-47 用非断链占位;不改 `config.ts`、生产代码与渲染端内容;构建 green、`build complete`、dead link = 0"
|
||||
artifacts:
|
||||
- "docs/advanced/face-handler.md"
|
||||
- ".planning/phases/10-docs-restructure/10-29-SUMMARY.md"
|
||||
key_links:
|
||||
- "D-75 第 2 项:高级 I 补写「FaceHandler 系列」,补齐 D-71 记录的两个缺口之二"
|
||||
- "`packages/common/src/utils/types.ts`(`IFaceHandler` / `IFaceDescriptor`)与 `packages-user/data-common/src/common/faceManager.ts`(`FaceGroup` / 内置处理器)是权威来源"
|
||||
- "向上接 `./mover.md`(移动器构造要传处理器)、`./ii/pathfinding.md`(`useFaceHandler`)、`./ii/custom-range.md`(`IFaceDescriptor` 复用)"
|
||||
---
|
||||
|
||||
<objective>
|
||||
编写高级 I 补写篇目之二:`docs/advanced/face-handler.md`(FaceHandler 系列)。讲清方向与朝向的两层结构——`FaceDirection` / `FaceGroup` / `IFaceHandler` 负责「方向怎么换算」,`IRoleFaceBinder` 负责「朝向怎么映射到图块数字」;并用可运行示例说明如何自定义一个朝向处理器。
|
||||
|
||||
Purpose: 移动器构造时要传一个朝向处理器,动态图块取朝向要经过 `roleFace`,寻路也要 `useFaceHandler`。这几处散落在不同包,读者看到 `FaceGroup.Dir8` 或 `degrade` 没有一处能系统讲清。D-75 明确要求补上,且要讲「怎么用、怎么改/扩展」。
|
||||
Output: 1 个新 markdown 文件(`docs/advanced/face-handler.md`)。
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/13194/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/13194/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/phases/10-docs-restructure/10-CONTEXT.md
|
||||
@docs/advanced/index.md
|
||||
@docs/advanced/ii/custom-range.md
|
||||
@docs/advanced/ii/pathfinding.md
|
||||
@docs/advanced/ii/static-vs-dynamic-tiles.md
|
||||
@docs/intermediate/hero-location.md
|
||||
@packages/common/src/utils/types.ts
|
||||
@packages-user/data-common/src/common/faceManager.ts
|
||||
@packages-user/data-common/src/common/face.ts
|
||||
@packages-user/data-common/src/common/types.ts
|
||||
@packages-user/data-common/src/types.ts
|
||||
@packages-user/data-base/src/shared.ts
|
||||
@packages-user/data-base/src/map/dynamicTile.ts
|
||||
@packages-user/data-base/src/map/mover.ts
|
||||
@src/data/initialize.ts
|
||||
|
||||
**写作规范(高级 I,逐条遵守):**
|
||||
- 读者水平按 D-57:了解基本语法(变量、函数、类、`import`),代码能力一般,不熟悉引擎内部架构。
|
||||
- 按一般库文档方式写(D-59):概念 → 完整示例(含解释性注释)→ 接入位置;不用中级教程的「复制什么 / 改什么」六步。
|
||||
- 简洁优先(D-60):不要为了完整而把每个枚举值都展开成表;能删就删。
|
||||
- 主干与边界分离(D-61):特殊情况集中到文末「边界与注意」。
|
||||
- 代码块结构完整(D-62 / D-70):完整类 / 完整函数。
|
||||
- 模板组织顺序(D-63):先讲理念 → 引导语 → 模板 → 解释模板;只有需要读者自己实现接口时才给模板(D-64)。
|
||||
- 示例注释越多越好(D-65);并列功能分开示例(D-66)。
|
||||
- 纯内部实现章节靠后,并以「此章节讲解一下 XXX 的内部实现」开头(D-69)。
|
||||
- 注释与实现不一致时以方法注释为准,并在对话中向用户报告,不按实现改写注释语义(D-72)。
|
||||
- 假定编辑器已完成(D-73);引用其他文档的具体章节用 `./xxx.md#标题`(D-74)。
|
||||
- 数据端 only;渲染端 / 编辑器内容按 D-47 用代码 span 或 HTML 注释占位,不写真实链接、不写 `src/client`。
|
||||
- 加粗边界:`**` 相邻处不得是标点(D-52)。
|
||||
|
||||
**源码事实(写作时逐条核对,勿凭印象):**
|
||||
- `FaceDirection`(`packages-user/data-common/src/common/types.ts`)是 `const enum`,顺序为 `Unknown`、`Left`、`Up`、`Right`、`Down`、`LeftUp`、`RightUp`、`LeftDown`、`RightDown`。文档不要教读者按数值硬编码。
|
||||
- `FaceGroup`(`faceManager.ts`)是 `const enum`:`Dir4`、`Dir8`。
|
||||
- `IFaceHandler`(`packages/common/src/utils/types.ts`)八个方法,注释原文要点:`degrade` 把任意朝向降级为本组支持的方向,无法合理降级(含 `Unknown`)返回 `Unknown`;`movement` 返回单步偏移,输入先经过 `degrade`;`move(dir, count)` 等价于偏移乘 `count`,`count` 可为负,输入先经过 `degrade`;`opposite` 返回本组内反方向,`Unknown` 返回 `Unknown`,输入先经过 `degrade`;`next(dir, anticlockwise)` 在本组内顺时针(默认)或逆时针旋转一步,输入先经过 `degrade`,`Unknown` 返回 `Unknown`;`dirOf(dx, dy)` 返回对应偏移量的朝向,有多个符合时返回其中一个;`mapDirection` 迭代本组所有朝向(含 `Unknown`);`mapMovement` 迭代本组所有朝向及其偏移(含 `Unknown` 对应 `{ x: 0, y: 0 }`)。
|
||||
- `IFaceDescriptor` 是只读的 `{ x, y }`;`IRayRangeParam.dir` 就是 `IFaceDescriptor` 列表。
|
||||
- `Dir8FaceHandler`:`degrade` 原样返回;运动表覆盖八方向 + `Unknown`;`opposite` / `next` 用独立映射表,查不到返回 `Unknown`。
|
||||
- `Dir4FaceHandler`:`degrade` 的映射是 `Left` / `Up` / `Right` / `Down` 原样,`LeftUp` / `LeftDown` → `Left`,`RightUp` / `RightDown` → `Right`,其余(含 `Unknown`)→ `Unknown`;运动表只含四方向 + `Unknown`。
|
||||
- `dirOf` 的实现会遍历一张方向表并返回第一个匹配;**不要**在文档里断言 `Dir4FaceHandler.dirOf` 对斜向偏移的具体返回(源码使用的表与 `degrade` 语义可能不一致)。若核对时确认不一致,只向用户报告,不写进文档、不记录为问题(AGENTS.md / D-72)。
|
||||
- `FaceManager`(`faceManager.ts`)实现 `IFaceManager`:`register(group, handler)`、`registerById(id, handler)`、`get(group)`、`getById(id)`;后两者找不到返回 `null`。
|
||||
- 注册位置:`src/data/initialize.ts` 里 `state.faceManager.register(FaceGroup.Dir4, dir4)`、`registerById('dir4', dir4)`、`register(FaceGroup.Dir8, dir8)`、`registerById('dir8', dir8)`。
|
||||
- `data-base/src/shared.ts` 的 `HERO_MOVER_FACE` 与 `DYNAMIC_MOVER_FACE` 都是 `FaceGroup.Dir8`;`DynamicTileMover` 构造时用 `face.get(DYNAMIC_MOVER_FACE)!` 取处理器,`DynamicTile.getCurrentFaceDirection()` 则用 `layer.faceBinder.getFaceDirection(tileNum)`。
|
||||
- `IRoleFaceBinder`(`common/types.ts`):`malloc(identifier, main)` 分配主朝向(注释:主朝向一般是朝下);`bind(identifier, main, face)` 把一个图块与主图块绑定朝向,注释明确要求先 `malloc`;`getFaceOf(identifier, face)` 返回 `IFaceData | null`;`getFaceDirection(identifier)` 没有数据时返回 `Unknown`;`getMainFace(identifier)` 返回 `IFaceData | null`。实现类 `RoleFaceBinder` 在 `face.ts`;`bind` 时主图块未 `malloc` 或朝向与主朝向相同会报错并放弃绑定。
|
||||
- 使用方:`state.faceManager` 与 `state.roleFace` 都挂在 Layer 0 的 `IDataCommon`(`packages-user/data-common/src/types.ts`);寻路的 `useFaceHandler`(`data-system/src/path/finder.ts` / `graph.ts`)。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking-human">
|
||||
<name>Task 0: 向用户汇报本计划并等待「可以执行」</name>
|
||||
<action>向用户汇报:**要做什么**(新增 `docs/advanced/face-handler.md`,讲方向值 / 方向组 / 朝向处理器三者的分工、内置 `Dir4FaceHandler` 与 `Dir8FaceHandler`、怎样自定义处理器、以及 `IRoleFaceBinder` 的朝向图块映射)、**为什么**(D-75 / D-71 要求补「FaceHandler 系列」;移动器构造、动态图块取朝向、寻路注入处理器都依赖它,但内容散在 `@motajs/common` 与 `@user/data-common` 两个包,没有一处系统讲解)、**大致怎么做**(先讲三个概念与 `IFaceHandler` 的八个方法,再讲两个内置处理器与获取/注册方式,然后给用处理器算位置与方向的示例、自定义处理器模板、`IRoleFaceBinder` 与朝向图块示例,最后讲它与移动器 / 寻路 / 范围对象的关系、边界与注意、「怎么验证」)、**影响范围**(仅新增 1 个 `docs/advanced/*.md`;不改 `config.ts`、生产代码与渲染端内容;侧边栏注册由 10-30 负责)。请用户确认三件事:① 文件名 `face-handler.md` 与页面标题「FaceHandler 系列」(D-13);② 自定义处理器的示例标识符名:`VerticalDir4FaceHandler`(四方向,但把斜向降级折到上下,用来演示 `degrade` 的策略作用)与自定义分组键 `3`(如不同意请给替代名);③ 说明文档会用 `state.faceManager` 与 `state.roleFace` 这两个已存在入口,不新增命名。汇报中明确:本计划的修改方式为**派发子代理执行**,范围严格限于 `docs/advanced/face-handler.md` 与 `.planning/.../10-29-SUMMARY.md`,执行者不内联修改文档。停下等待用户明确回复「可以执行」四个字;未收到前不得写任何文件。</action>
|
||||
<what-built>本计划内容:高级 I 补写篇目「FaceHandler 系列」。</what-built>
|
||||
<how-to-verify>阅读上面的四段说明,确认文件名 / 标题 / 示例标识符名与分组键;如不同意请给出替代。</how-to-verify>
|
||||
<resume-signal>回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。</resume-signal>
|
||||
<verify>
|
||||
<human-check>用户已回复「可以执行」,且未对文件名 / 页面标题 / 示例标识符名提出替代。</human-check>
|
||||
</verify>
|
||||
<done>用户回复「可以执行」。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: 编写 face-handler.md 正文</name>
|
||||
<files>docs/advanced/face-handler.md</files>
|
||||
<action>(1) 新建 `docs/advanced/face-handler.md`,单 H1 为「FaceHandler 系列」。(2) 开头用两三段说清问题:方向在引擎里有两层含义——一层是「往哪走」(逻辑朝向),另一层是「该画哪张图块」(朝向图块);四方向与八方向又需要一套统一的换算;`IFaceHandler` 负责第一层的换算,`IRoleFaceBinder` 负责第二层的映射。说明本篇只讲数据端,画面怎么用这些值由渲染端负责(按 D-47 用代码 span 占位)。(3) 正文按以下顺序组织,每节只讲一件事:
|
||||
① `## 三个概念`:表格列 `FaceDirection`(方向值,九个成员含 `Unknown`;不要按数值硬编码)、`FaceGroup`(`Dir4` / `Dir8`,表示「这一组认哪些方向」)、`IFaceHandler`(把任意方向换算成本组支持的方向、偏移、反方向、旋转);再补一句 `IFaceDescriptor` 是 `{ x, y }` 增量。
|
||||
② `## 拿到朝向处理器`:`state.faceManager.get(FaceGroup.Dir8)` 按数字组取、`getById('dir8')` 按字符串 id 取,找不到返回 `null`;注册在 `src/data/initialize.ts`,四个内置注册分别是 `Dir4` + `'dir4'`、`Dir8` + `'dir8'`;说明注册是启动期的事,运行期只读。
|
||||
③ `## IFaceHandler 能做什么`:方法表(方法 / 作用 / 输入是否先 `degrade` / `Unknown` 的返回);逐条讲 `degrade`(降级策略,本组不认的方向怎么归并)、`movement`(单步偏移)、`move`(多步,`count` 可为负)、`opposite`(反方向)、`next`(顺时针 / 逆时针转一步)、`dirOf`(由偏移反推方向,多解时返回其中一个)、`mapDirection` / `mapMovement`(遍历本组,含 `Unknown` 与零偏移)。明确:`degrade` 是这一整套的核心,因为使用者会传进任意方向值。
|
||||
④ `## 两个内置处理器`:`Dir8FaceHandler` 与 `Dir4FaceHandler` 对比表(支持方向 / `degrade` 行为 / 典型用途);重点讲 `Dir4FaceHandler` 的 `degrade` 把斜向折到左右(`LeftUp` / `LeftDown` → `Left`,`RightUp` / `RightDown` → `Right`),**不是**折到上下——这一点决定了四方向游戏里斜向输入会变成横向走。说明 `Unknown` 在所有方法里保持 `Unknown`。
|
||||
⑤ `## 用处理器算位置与方向`:分段示例(D-66):一段算「往某方向走一格的目标坐标」,一段算反方向,一段用 `mapMovement` 遍历四方向。示例都输出到 `console.log`,含解释性注释,`[需改]` 标出方向常量。
|
||||
⑥ `## 实现自己的朝向处理器`:先讲什么时候需要(四方向但要换斜向归并策略、或方向数不是 4 / 8 的自定义规则),再给「模板:一个自定义朝向处理器」——`class VerticalDir4FaceHandler implements IFaceHandler` 的完整类骨架:内部维护「降级表」与「四方向运动表」,`degrade` 把四个斜向分别折到上 / 下,`movement` / `move` / `opposite` / `next` / `dirOf` / `mapDirection` / `mapMovement` 全部实现;模板后用文字解释每个方法的契约(输入先 `degrade`、`Unknown` 恒 `Unknown`、`mapMovement` 必须含 `Unknown` 的零偏移、`next` 的 `anticlockwise` 参数),并给出注册方式 `state.faceManager.register(3, new VerticalDir4FaceHandler())` 与取回方式;说明注入了这个处理器的移动器与寻路会立刻按新策略走。
|
||||
⑦ `## 朝向图块:IRoleFaceBinder`:讲清它解决的是「同一角色有多张朝向图块,按当前朝向取对应图块数字」;接口表(方法 / 作用 / 返回);示例:先 `malloc(1, FaceDirection.Down)` 分配主朝向,再 `bind(2, 1, FaceDirection.Right)` 绑定另一朝向,然后 `getFaceOf(1, FaceDirection.Right)` 取到绑定的图块数据、`getFaceDirection(2)` 得到 `Right`、`getMainFace(2)` 得到主图块;说明 `getFaceOf` 找不到返回 `null`,`bind` 前必须先 `malloc`(否则绑定失败)。
|
||||
⑧ `## 它们怎么串起来`:`DynamicTile.getCurrentFaceDirection()` 通过 `layer.faceBinder.getFaceDirection(tileNum)` 取朝向;`DynamicTileMover` 构造时从 `state.faceManager` 取 `Dir8` 处理器;移动器用处理器把 `moveDirection` 换成落点偏移。说明分工:`FaceDirection` 是逻辑朝向,`IFaceHandler` 把它变成位移与转向,`IRoleFaceBinder` 把它变成图块数字,渲染端再按图块数字绘制(占位)。移动器只用代码 span 写 `移动 Mover`,不写相对链接(由 10-30 收口)。
|
||||
⑨ `## 与寻路、范围对象的关系`:寻路通过 `finder.useFaceHandler(handler)` 注入方向规则(链接 `./ii/pathfinding.md`);射线范围参数 `dir` 是 `IFaceDescriptor` 列表(链接 `./ii/custom-range.md`);说明「方向即偏移」这一层被多处复用,改处理器的行为会同时影响移动与寻路。
|
||||
⑩ `## 边界与注意`(D-61):`Dir4` 的斜向折左右;`get` / `getById` 可能返回 `null`,自建分组时要先判空;`dirOf` 多解只返回一个;`Unknown` 的偏移是零、反方向与旋转仍是 `Unknown`;`bind` 不 `malloc` 会失败;同一图块数字不要重复 `malloc`(会覆盖);处理器是共享对象,不要在实例上存「当前对象」的状态;不同 group 的处理器互不影响。
|
||||
⑪ `## 怎么验证`:给可操作自检——打印 `degrade(LeftUp)`、`movement(Up)`、`opposite(Right)`、`next(Up)` 的结果;`malloc` + `bind` 后核对 `getFaceOf` 与 `getFaceDirection`;换上自定义处理器后再算一次目标格,确认斜向按新策略归并。
|
||||
(4) 提到 `Dir4FaceHandler.dirOf` 时只写通用语义(由偏移反推方向、多解取其一),不断言斜向偏移的具体返回值;若核对源码发现与注释语义不一致,只向用户报告,不写进文档。不要写 `src/client`、不要写「后续再讲」式元叙述、不要给中级教程的六步实操。完成后跑 prettier `--write`。Commit:`docs(10-29): 编写 FaceHandler 系列文档`。</action>
|
||||
<verify>
|
||||
<automated>$ErrorActionPreference='Stop'; $p='docs/advanced/face-handler.md'; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($raw -match "(?<!`r)`n"){ Write-Error "LF-ONLY $p" }; if(([regex]::Matches($raw,'(?m)^# ')).Count -ne 1){ Write-Error "H1-COUNT $p" }; foreach($needle in @('FaceDirection','FaceGroup','IFaceHandler','IFaceDescriptor','Dir4FaceHandler','Dir8FaceHandler','degrade','opposite','next','mapMovement','IRoleFaceBinder','faceManager','roleFace','怎么验证','边界与注意')){ if($raw -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-CONTENT $needle" } }; foreach($needle in @('malloc','bind','getFaceOf','getFaceDirection','getMainFace','useFaceHandler')){ if($raw -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-DETAIL $needle" } }; if($raw -match 'src/client'){ Write-Error "RENDERER-CONTENT" }; if($raw -match '\*\*[,。!?;:、()《》「」『』【】,.!?;:\(\)\[\]{}"'']' -or $raw -match '[,。!?;:、()《》「」『』【】,.!?;:\(\)\[\]{}"'']\*\*'){ Write-Error "BOLD-FLANK" }; foreach($m in [regex]::Matches($raw,'\]\((\.{1,2}/[^)#]+\.md)(#[^)]*)?\)')){ $t=Join-Path (Split-Path -Parent $p) $m.Groups[1].Value; if(-not(Test-Path -LiteralPath $t)){ Write-Error ("DEAD-LINK " + $m.Groups[1].Value) } }; Write-Output 'STATIC-OK'</automated>
|
||||
<fails_when>non-zero exit, or output contains "MISSING", "LF-ONLY", "H1-COUNT", "MISSING-CONTENT", "MISSING-DETAIL", "RENDERER-CONTENT", "BOLD-FLANK", or "DEAD-LINK"; or output lacks "STATIC-OK"</fails_when>
|
||||
</verify>
|
||||
<done>文件存在、CRLF、单 H1;三个概念、八个方法、两个内置处理器、用法示例、自定义模板、`IRoleFaceBinder`、串联关系、与寻路 / 范围对象的关系、边界与注意、「怎么验证」齐全;无渲染端内容;无死链。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: 源码核对、格式与构建收口</name>
|
||||
<files>docs/advanced/face-handler.md, .planning/phases/10-docs-restructure/10-29-SUMMARY.md</files>
|
||||
<action>逐条核对正文与源码:① `packages/common/src/utils/types.ts`——`IFaceHandler` 八个方法名、参数、返回值与注释原文(尤其 `degrade` 对无法降级方向的处理、`next` 的 `anticlockwise` 默认值、`mapMovement` 含 `Unknown`)。② `packages-user/data-common/src/common/faceManager.ts`——`FaceGroup` 两个成员、`Dir8FaceHandler` 与 `Dir4FaceHandler` 的 `degrade` 映射、`FaceManager` 的四个方法。③ `packages-user/data-common/src/common/face.ts` 与 `common/types.ts`——`IRoleFaceBinder` 五个方法、`bind` 的 `malloc` 前置要求、`getFaceOf` 的 `null` 返回。④ `packages-user/data-common/src/types.ts`——`state.faceManager` 与 `state.roleFace` 的挂载点。⑤ `src/data/initialize.ts`——四个注册调用的分组与 id。⑥ `packages-user/data-base/src/map/dynamicTile.ts` 与 `map/mover.ts`——动态图块如何取朝向、移动器如何取处理器。⑦ `packages-user/data-system/src/path/finder.ts`——`useFaceHandler` 的签名与用途。**重点核对 `Dir4FaceHandler.dirOf`:** 若实现使用的方向表与注释语义不一致,只在对话中向用户报告,不写进文档、不当作文档问题记录(AGENTS.md / D-72)。然后跑 prettier `--write`,再跑构建门禁 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,确认 green、`build complete`、dead link = 0。写 `.planning/phases/10-docs-restructure/10-29-SUMMARY.md`:章节结构、引用的源码落点、核对到的关键语义(含 `Dir4` 的降级映射与 `bind` 前置条件)、构建与格式结论、向用户报告的不一致(若无可写「无」)。Commit:`docs(10-29): 核对源码并收口朝向文档`。</action>
|
||||
<verify>
|
||||
<automated>$ErrorActionPreference='Stop'; $p='docs/advanced/face-handler.md'; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); foreach($needle in @('Dir4','Dir8','register','anticlockwise','Unknown')){ if($raw -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-AFTER-CHECK $needle" } }; $sum='.planning/phases/10-docs-restructure/10-29-SUMMARY.md'; if(-not(Test-Path -LiteralPath $sum)){ Write-Error "MISSING $sum" }; $s=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $sum)); foreach($needle in @('face-handler.md','构建','源码')){ if($s -notmatch [regex]::Escape($needle)){ Write-Error "SUMMARY-MISSING $needle" } }; $ErrorActionPreference='Continue'; $pf = cmd /c "node node_modules/prettier/bin/prettier.cjs --check docs/advanced/face-handler.md" 2>&1; $pfe=$LASTEXITCODE; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($pfe -ne 0){ $pf | Write-Output; Write-Error "PRETTIER-FAIL" }; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'GATE-OK'</automated>
|
||||
<fails_when>non-zero exit, or output contains "MISSING", "MISSING-AFTER-CHECK", "SUMMARY-MISSING", "PRETTIER-FAIL", "BUILD-FAIL", "NO-BUILD-COMPLETE", or "DEAD-LINK"; or output lacks "GATE-OK"</fails_when>
|
||||
</verify>
|
||||
<done>八个方法语义、两个内置处理器的 `degrade` 映射、`FaceManager`、`IRoleFaceBinder` 五个方法与前置条件、注册位置逐条与源码一致;`dirOf` 的不一致(如有)已向用户报告且未写入文档;prettier 通过;构建 green、`build complete`、dead link = 0;SUMMARY 已写。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 构建期 markdown → 静态站点 | 正文由构建期静态渲染,无运行时输入 |
|
||||
| 站点 → 浏览器读者 | 站内链接是唯一可点击指向面 |
|
||||
| 执行者 → 子代理 | 写作子代理只改 `face-handler.md`,不触碰配置与生产代码 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-10-85 | Tampering / XSS | `face-handler.md` 正文与代码块 | low | mitigate | 只写文本、代码块、表格;不引入原始 `<script>` 或内联 HTML |
|
||||
| T-10-86 | Spoofing | 站内链接 | low | mitigate | 只链已存在页面;逐条断言相对 `.md` 目标存在;与 `mover.md` 的互引由 10-30 收口 |
|
||||
| T-10-87 | Information Disclosure | 正文示例 | low | mitigate | 只用源码已公开的接口与路径;不写密钥、账号 |
|
||||
| T-10-SC | Tampering | npm/pip/cargo installs | low | accept | 本阶段不安装任何包,无供应链安装面 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- 结构门禁:`docs/advanced/face-handler.md` 存在、kebab-case、CRLF、单 H1。
|
||||
- 内容门禁:三个概念、八个方法、两个内置处理器、用法示例、自定义模板、`IRoleFaceBinder`、串联关系、寻路 / 范围对象关系、边界、怎么验证齐全。
|
||||
- 事实门禁:`Dir4` 的降级折左右、`Unknown` 行为、`bind` 的 `malloc` 前置、`get` / `getById` 返回 `null`、注册位置,逐条与源码一致。
|
||||
- 边界门禁:无渲染端内容;不改 `config.ts` 与生产代码。
|
||||
- 格式门禁:prettier `--check` 通过。
|
||||
- 构建门禁:`cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"` 通过,`build complete`,dead link = 0。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- 读者能判断该用哪个内置处理器、四方向的斜向输入会被怎么归并,并能取出目标格偏移与反方向。
|
||||
- 读者需要自定义时,能照着模板实现 `IFaceHandler` 并注册,知道哪些使用方会立刻按新策略走。
|
||||
- 读者知道 `IRoleFaceBinder` 解决的是「朝向 → 图块数字」,且 `bind` 前必须 `malloc`。
|
||||
- 构建通过、无死链、无渲染端内容;向用户报告的不一致(如有)已记录。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/10-docs-restructure/10-29-SUMMARY.md` when done
|
||||
</output>
|
||||
148
.planning/phases/10-docs-restructure/10-30-PLAN.md
Normal file
148
.planning/phases/10-docs-restructure/10-30-PLAN.md
Normal file
@ -0,0 +1,148 @@
|
||||
---
|
||||
phase: 10-docs-restructure
|
||||
plan: 30
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on: [10-28, 10-29]
|
||||
files_modified:
|
||||
- docs/advanced/index.md
|
||||
- docs/.vitepress/config.ts
|
||||
- docs/advanced/mover.md
|
||||
- docs/advanced/face-handler.md
|
||||
- .planning/phases/10-docs-restructure/10-30-SUMMARY.md
|
||||
autonomous: false
|
||||
requirements: []
|
||||
user_setup: []
|
||||
estimate:
|
||||
tokens: 16000
|
||||
raw_tokens: 11000
|
||||
tasks: 3
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "`docs/advanced/index.md` 把高级 I 从「七篇」更新为「九篇」(导览 + 八篇正文),篇目表新增「移动 Mover」与「FaceHandler 系列」两行,结尾「继续阅读」补上两个真实链接"
|
||||
- "`docs/.vitepress/config.ts` 的 `sidebar['/advanced/']` 高级 I 组从 7 个目标变为 9 个目标(`/advanced/` + 八个文件名),顺序与导览一致:… → 钩子深入 → 移动 Mover → FaceHandler 系列;分组显示名仍为「高级 I · 扩展基础」"
|
||||
- "不新增分组、不改 `nav`、不改 `'/advanced/ii/'` 分组、不改 `outDir` / `base` / 搜索 / mermaid 等其他配置"
|
||||
- "两篇新文档之间的互引由代码 span 改为真实相对链接(`./mover.md` ↔ `./face-handler.md`),并各自补上与其余六篇一致的「返回高级 I 导览」结尾"
|
||||
- "四个被改文件中的相对 `.md` 链接全部可解析;两篇新文档仍 kebab-case、CRLF、单 H1;无渲染端内容"
|
||||
- "prettier `--check` 对三篇 markdown 通过;构建 green、`build complete`、dead link = 0;侧边栏 9 个目标与实际文件一一对应"
|
||||
artifacts:
|
||||
- "docs/advanced/index.md"
|
||||
- "docs/.vitepress/config.ts"
|
||||
- "docs/advanced/mover.md"
|
||||
- "docs/advanced/face-handler.md"
|
||||
- ".planning/phases/10-docs-restructure/10-30-SUMMARY.md"
|
||||
key_links:
|
||||
- "把 10-28 / 10-29 的两篇接入站点,使高级 I 从七篇变成可浏览的九篇"
|
||||
- "导览表与侧边栏必须同序:钩子深入之后才是移动 Mover 与 FaceHandler 系列(不重排既有顺序)"
|
||||
- "本计划完成后,10-31 的读者审阅对象是「站点上可见的九篇中的两篇新页」"
|
||||
---
|
||||
|
||||
<objective>
|
||||
把 10-28 / 10-29 的两篇新文档接入站点:更新 `docs/advanced/index.md`(七篇 → 九篇、篇目表、继续阅读)、在 `docs/.vitepress/config.ts` 的高级 I 侧边栏组追加两项(7 → 9),并把两篇之间的互引收口成真实链接,最后做格式、链接与构建收口。
|
||||
|
||||
Purpose: 文档写完但没有入口等于不存在;而两篇新页面在并行计划里只能互相用代码 span 占位,链接必须在这里统一收口,否则会留下断链或永远不生效的占位。
|
||||
Output: 导览、侧边栏注册、两篇互链与 `10-30-SUMMARY.md`。
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/13194/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/13194/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/phases/10-docs-restructure/10-CONTEXT.md
|
||||
@.planning/phases/10-docs-restructure/10-28-PLAN.md
|
||||
@.planning/phases/10-docs-restructure/10-29-PLAN.md
|
||||
@docs/advanced/index.md
|
||||
@docs/advanced/mover.md
|
||||
@docs/advanced/face-handler.md
|
||||
@docs/advanced/hooks-in-depth.md
|
||||
@docs/.vitepress/config.ts
|
||||
|
||||
**现状与约束:**
|
||||
- `docs/advanced/index.md` 当前写「高级 I 一共七篇,包含本导览与六篇正文」,篇目表 1–7,结尾「继续阅读」列六篇;需要**最小改动**:改篇数、加两行、加两个链接,不重写导览的其它段落。
|
||||
- `docs/.vitepress/config.ts` 的 `sidebar['/advanced/']` 第一组「高级 I · 扩展基础」当前 7 项(`/advanced/` + `data-stores` / `declarative-vs-imperative` / `hooks-in-depth` / `plugin-system` / `replay-consistency` / `saveable-content`);新增 `mover` / `face-handler` 两项,插在「钩子深入」之后。
|
||||
- 链接写法沿用现有约定:绝对路径、不带 `.md`、不带尾斜杠(`{ text: '移动 Mover', link: '/advanced/mover' }`)。
|
||||
- 两篇新文档在 10-28 / 10-29 中互相只用代码 span / 文字提及;本计划把它们改成真实链接,并补「返回[高级 I 导览](./index.md)。」结尾(与其余六篇一致)。
|
||||
- 只改上述四个文件与 `10-30-SUMMARY.md`;不改生产代码、不改渲染端内容、不改其他站点配置。加粗遵守 flanking(D-52);引用具体章节用 `./xxx.md#标题`(D-74)。
|
||||
- 命令一律经 `cmd /c "..."` 执行(本机 PowerShell 禁止 `pnpm.ps1`)。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking-human">
|
||||
<name>Task 0: 向用户汇报本计划并等待「可以执行」</name>
|
||||
<action>向用户汇报:**要做什么**(把两篇新文档接入高级 I:导览改九篇、侧边栏高级 I 组 7 → 9、两篇互引收口成真实链接、补「返回导览」结尾,最后跑格式与构建)、**为什么**(没有入口的文档读者找不到;并行计划里两篇只能互相用代码 span 占位,必须在这里统一收口,否则断链或占位永久残留)、**大致怎么做**(先改导览与侧边栏并核对 9 个目标,再把两篇互引改成 `./mover.md` / `./face-handler.md` 并补结尾,最后 prettier + 全量构建)、**影响范围**(改 `docs/advanced/index.md`、`docs/.vitepress/config.ts` 的高级 I 侧边栏组、`mover.md` 与 `face-handler.md` 的互引与结尾;不动既有六篇正文、不动高级 II 分组、不动 nav 与其它配置)。请用户确认两个侧边栏显示名(同时作为篇目表用名):「移动 Mover」与「FaceHandler 系列」,以及它们在导览与侧边栏中的顺序——排在「钩子深入」之后(D-13)。汇报中明确:本计划的修改方式为**派发子代理执行**,范围严格限于 `files_modified` 列出的四个文档 / 配置文件与 SUMMARY,执行者不内联修改文件。停下等待用户明确回复「可以执行」四个字;未收到前不得改任何文件。</action>
|
||||
<what-built>本计划内容:导览更新(7 → 9)+ 侧边栏注册 + 两篇互链收口。</what-built>
|
||||
<how-to-verify>阅读上面的四段说明,确认两个显示名与排序;如不同意请给出替代名称或顺序。</how-to-verify>
|
||||
<resume-signal>回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。</resume-signal>
|
||||
<verify>
|
||||
<human-check>用户已回复「可以执行」,且未对显示名 / 排序提出替代。</human-check>
|
||||
</verify>
|
||||
<done>用户回复「可以执行」。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: 更新导览并在侧边栏注册两篇</name>
|
||||
<files>docs/advanced/index.md, docs/.vitepress/config.ts</files>
|
||||
<action>(1) 改 `docs/advanced/index.md`,只做必要改动:①「高级 I 一共七篇,包含本导览与六篇正文」改为「高级 I 一共九篇,包含本导览与八篇正文」;②「高级 I 包含什么」的篇目表末尾追加两行——第 8 行「移动 Mover」,一句话说明「能排出一次移动、等它走完,并在需要时自己实现移动器」;第 9 行「FaceHandler 系列」,一句话说明「能选对朝向处理器、算出目标格与反方向,并把朝向映射到图块数字」;③该节末尾的「推荐阅读顺序」在原有顺序后补一句:移动 Mover 与 FaceHandler 系列偏参考性质,可等用到时再读(保留原有六篇顺序不变);④「继续阅读」的六篇列表追加 `[移动 Mover](./mover.md)` 与 `[FaceHandler 系列](./face-handler.md)`;⑤「阅读路径与前置」若提到篇数或范围,一并微调,但不重写既有段落,不新增「七篇」这类旧数字。
|
||||
(2) 改 `docs/.vitepress/config.ts`:在 `sidebar` 的 `'/advanced/'` 键、分组「高级 I · 扩展基础」的 `items` 里,「钩子深入」之后追加两项:`{ text: '移动 Mover', link: '/advanced/mover' }` 与 `{ text: 'FaceHandler 系列', link: '/advanced/face-handler' }`。保持现有缩进与对象书写风格;不要改 `nav`、不要改「高级 II · 深入定制」分组、不要改 `outDir` / `base` / 搜索 / mermaid / api 相关配置。
|
||||
(3) 自查:`git diff -- docs/.vitepress/config.ts` 应只显示新增两行对象;`docs/advanced/index.md` 的 diff 应只有篇数、两行表格、一句阅读顺序说明与两个链接。Commit:`docs(10-30): 导览与侧边栏注册移动与朝向两篇`。</action>
|
||||
<verify>
|
||||
<automated>$ErrorActionPreference='Stop'; $idx='docs/advanced/index.md'; $cfg='docs/.vitepress/config.ts'; if(-not(Test-Path -LiteralPath $idx)){ Write-Error "MISSING $idx" }; if(-not(Test-Path -LiteralPath $cfg)){ Write-Error "MISSING $cfg" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $idx)); if($raw -notmatch '九篇'){ Write-Error "NO-NINE" }; if($raw -match '一共七篇'){ Write-Error "STALE-SEVEN" }; foreach($target in @('./mover.md','./face-handler.md')){ if($raw -notmatch [regex]::Escape($target)){ Write-Error "MISSING-LINK $target" } }; if($raw -notmatch '移动 Mover'){ Write-Error "NO-MOVER-ROW" }; if($raw -notmatch 'FaceHandler 系列'){ Write-Error "NO-FACE-ROW" }; $c=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $cfg)); if($c -notmatch "text:\s*'高级 I · 扩展基础'"){ Write-Error "NO-GROUP-I" }; if($c -notmatch "text:\s*'移动 Mover'"){ Write-Error "NO-NAV-MOVER" }; if($c -notmatch "text:\s*'FaceHandler 系列'"){ Write-Error "NO-NAV-FACE" }; $targets=[regex]::Matches($c,"link:\s*'/advanced/(?!ii/)([^']*)'") | ForEach-Object { $_.Groups[1].Value } | Sort-Object -Unique; $want=@('','data-stores','declarative-vs-imperative','face-handler','hooks-in-depth','mover','plugin-system','replay-consistency','saveable-content') | Sort-Object -Unique; if(($targets -join ',') -ne ($want -join ',')){ Write-Error ("ADVANCED-LINKS " + ($targets -join ',')) }; if(([regex]::Matches($c,"link:\s*'/advanced/ii/[^']*'")).Count -ne 10){ Write-Error "II-LINKS-CHANGED" }; Write-Output 'REGISTER-OK'</automated>
|
||||
<fails_when>non-zero exit, or output contains "MISSING", "NO-NINE", "STALE-SEVEN", "MISSING-LINK", "NO-MOVER-ROW", "NO-FACE-ROW", "NO-GROUP-I", "NO-NAV-MOVER", "NO-NAV-FACE", "ADVANCED-LINKS", or "II-LINKS-CHANGED"; or output lacks "REGISTER-OK"</fails_when>
|
||||
</verify>
|
||||
<done>导览改为九篇、两行表格与两个链接补齐、无残留「七篇」;侧边栏高级 I 组 9 个目标且顺序正确;高级 II 分组未动;nav 与其它配置未动。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: 两篇互引收口、格式与全量构建</name>
|
||||
<files>docs/advanced/mover.md, docs/advanced/face-handler.md</files>
|
||||
<action>(1) 在 `docs/advanced/mover.md` 里把提到朝向处理器的那处「FaceHandler 系列」代码 span 改成真实链接 `[FaceHandler 系列](./face-handler.md)`(只改必要处,不要把所有提及都改成链接;D-17 链接适量);在 `docs/advanced/face-handler.md` 里把提到移动器的那处改成 `[移动 Mover](./mover.md)`。(2) 两篇末尾各补一行「返回[高级 I 导览](./index.md)。」,与其余六篇一致;若已有类似结尾则只校正为这个写法,不重复添加。(3) 逐篇自查:相对 `.md` 链接目标存在;无 `src/client`;仍是 kebab-case、CRLF、单 H1;加粗符合 flanking;没有把具体示例当模板、模板仍单独成节(D-50 / D-63)。(4) 跑 prettier:`node node_modules/prettier/bin/prettier.cjs --write docs/advanced/index.md docs/advanced/mover.md docs/advanced/face-handler.md`,再 `--check` 三个文件。(5) 跑构建门禁 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,确认 green、`build complete`、dead link = 0,并确认构建输出包含 `/advanced/mover.html` 与 `/advanced/face-handler.html` 两个页面(若构建日志不打印页面清单,则以产物目录中存在对应 html 为准)。(6) 写 `.planning/phases/10-docs-restructure/10-30-SUMMARY.md`:导览改动点、侧边栏 9 个目标清单、互链收口点、prettier / 构建 / 链接结论。Commit:`docs(10-30): 收口高级 I 两篇互链与构建`。</action>
|
||||
<verify>
|
||||
<automated>$ErrorActionPreference='Stop'; $names=@('mover','face-handler'); foreach($n in $names){ $p="docs/advanced/$n.md"; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $body=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($body -match "(?<!`r)`n"){ Write-Error "LF-ONLY $p" }; if(([regex]::Matches($body,'(?m)^# ')).Count -ne 1){ Write-Error "H1-COUNT $p" }; if($body -match 'src/client'){ Write-Error "RENDERER-CONTENT $p" }; if($body -notmatch '\./index\.md'){ Write-Error "NO-BACKLINK $p" }; if($body -match '\*\*[,。!?;:、()《》「」『』【】,.!?;:\(\)\[\]{}"'']' -or $body -match '[,。!?;:、()《》「」『』【】,.!?;:\(\)\[\]{}"'']\*\*'){ Write-Error "BOLD-FLANK $p" }; foreach($m in [regex]::Matches($body,'\]\((\.{1,2}/[^)#]+\.md)(#[^)]*)?\)')){ $t=Join-Path (Split-Path -Parent $p) $m.Groups[1].Value; if(-not(Test-Path -LiteralPath $t)){ Write-Error ("DEAD-LINK $p -> " + $m.Groups[1].Value) } } }; $mv=[IO.File]::ReadAllText((Resolve-Path -LiteralPath 'docs/advanced/mover.md')); if($mv -notmatch '\./face-handler\.md'){ Write-Error "NO-CROSS-MOVER" }; $fh=[IO.File]::ReadAllText((Resolve-Path -LiteralPath 'docs/advanced/face-handler.md')); if($fh -notmatch '\./mover\.md'){ Write-Error "NO-CROSS-FACE" }; $sum='.planning/phases/10-docs-restructure/10-30-SUMMARY.md'; if(-not(Test-Path -LiteralPath $sum)){ Write-Error "MISSING $sum" }; $s=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $sum)); foreach($needle in @('九篇','侧边栏','构建')){ if($s -notmatch [regex]::Escape($needle)){ Write-Error "SUMMARY-MISSING $needle" } }; $ErrorActionPreference='Continue'; $pf = cmd /c "node node_modules/prettier/bin/prettier.cjs --check docs/advanced/index.md docs/advanced/mover.md docs/advanced/face-handler.md" 2>&1; $pfe=$LASTEXITCODE; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($pfe -ne 0){ $pf | Write-Output; Write-Error "PRETTIER-FAIL" }; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'FINAL-OK'</automated>
|
||||
<fails_when>non-zero exit, or output contains "MISSING", "LF-ONLY", "H1-COUNT", "RENDERER-CONTENT", "NO-BACKLINK", "BOLD-FLANK", "DEAD-LINK", "NO-CROSS-MOVER", "NO-CROSS-FACE", "SUMMARY-MISSING", "PRETTIER-FAIL", "BUILD-FAIL", "NO-BUILD-COMPLETE"; or output lacks "FINAL-OK"</fails_when>
|
||||
</verify>
|
||||
<done>两篇互链为真实相对链接、结尾有返回导览;prettier 三篇通过;构建 green、`build complete`、dead link = 0;SUMMARY 已写。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 构建期 markdown / 配置 → 静态站点 | 正文与侧边栏由构建期静态处理,无运行时输入 |
|
||||
| 站点 → 浏览器读者 | 站内链接是唯一可点击指向面 |
|
||||
| 配置层 → 构建产物 | `sidebar` 决定可浏览页面集合 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-10-88 | Tampering / XSS | 导览正文与两篇文档 | low | mitigate | 只写文本、代码块、表格;不引入原始 `<script>` 或内联 HTML |
|
||||
| T-10-89 | Spoofing | 侧边栏与站内链接 | low | mitigate | 侧边栏只挂已存在页面;断言 9 个目标集合完全匹配;逐条检查相对 `.md` 目标 |
|
||||
| T-10-90 | Information Disclosure | 导览与 SUMMARY | low | mitigate | 只引用仓库已公开路径与接口;不写密钥、账号 |
|
||||
| T-10-SC | Tampering | npm/pip/cargo installs | low | accept | 本阶段不安装任何包,无供应链安装面 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- 注册门禁:高级 I 组恰好 9 个目标(`/advanced/` + 八个文件名),顺序为既有六篇后接 `mover`、`face-handler`;高级 II 仍 10 个目标;`nav` 未动。
|
||||
- 导览门禁:篇数改为九篇、两行表格、两个继续阅读链接、无「七篇」残留。
|
||||
- 链接门禁:两篇互引为真实链接;两篇都有返回导览;所有相对 `.md` 目标存在。
|
||||
- 结构门禁:两篇 kebab-case、CRLF、单 H1;无渲染端内容。
|
||||
- 格式门禁:prettier `--check` 对三篇通过。
|
||||
- 构建门禁:`cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"` 通过,`build complete`,dead link = 0。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- 高级 I 在站点上显示为九篇,两篇新页可从导览与侧边栏进入。
|
||||
- 两篇之间的互引与返回导览链接全部可解析,无占位残留。
|
||||
- 构建通过、无死链;只改了四个文件与 SUMMARY。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/10-docs-restructure/10-30-SUMMARY.md` when done
|
||||
</output>
|
||||
170
.planning/phases/10-docs-restructure/10-31-PLAN.md
Normal file
170
.planning/phases/10-docs-restructure/10-31-PLAN.md
Normal file
@ -0,0 +1,170 @@
|
||||
---
|
||||
phase: 10-docs-restructure
|
||||
plan: 31
|
||||
type: execute
|
||||
wave: 3
|
||||
depends_on: [10-30]
|
||||
files_modified:
|
||||
- .planning/phases/10-docs-restructure/10-31-READER-REVIEW.md
|
||||
- docs/advanced/mover.md
|
||||
- docs/advanced/face-handler.md
|
||||
- .planning/phases/10-docs-restructure/10-31-SUMMARY.md
|
||||
autonomous: false
|
||||
requirements: []
|
||||
user_setup: []
|
||||
estimate:
|
||||
tokens: 32000
|
||||
raw_tokens: 21000
|
||||
tasks: 4
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "读者人格沿用 10-19 Task 0 已经用户确认的高级 I 提示词,逐字不变(D-57):不预设高代码水平、也不是完全不懂代码,且不复用中级教程人格"
|
||||
- "`10-31-READER-REVIEW.md` 逐字记录人格提示词、审阅范围(`mover.md` + `face-handler.md`,含它们在导览与侧边栏中的接入)、首轮问题清单,按阻断性与非阻断归类并定位到文件与章节"
|
||||
- "阻断性问题被迭代修正(上限 3 轮);每轮后构建 green、`build complete`、dead link = 0;达到上限仍有阻断问题时停下交用户,不无限循环"
|
||||
- "迭代结束再派发一个独立子代理(同一人格)复审,记录逐条标注「已消除」或「仍存在」;结束标记为「阻断性问题 = 0」或「阻断性问题余项:已交用户」(后者须列余项与用户处置)"
|
||||
- "只改 `docs/advanced/mover.md` / `face-handler.md` 与审阅记录;不改 `config.ts`、导览以外的页面、生产代码与渲染端内容"
|
||||
- "非阻断问题只记录、不擅自扩大范围(D-14);不因读者提问删掉 D-75 要求覆盖的内容(三件套、步骤、控制器、钩子、`degrade` / `next` / `opposite` / `mapMovement`、`IRoleFaceBinder`)"
|
||||
- "复审后两篇仍 kebab-case、CRLF、单 H1;构建 green、`build complete`、dead link = 0"
|
||||
artifacts:
|
||||
- ".planning/phases/10-docs-restructure/10-31-READER-REVIEW.md"
|
||||
- "docs/advanced/mover.md(仅存在阻断性问题的部分)"
|
||||
- "docs/advanced/face-handler.md(仅存在阻断性问题的部分)"
|
||||
- ".planning/phases/10-docs-restructure/10-31-SUMMARY.md"
|
||||
key_links:
|
||||
- "执行 D-46 第 1 阶段 / D-57 / D-75:两篇补写内容必须走独立读者审阅 → 问题清单 → 迭代 → 复审"
|
||||
- "人格沿用 10-19 已确认的提示词,不新造人格;审阅对象是 10-30 已接入侧边栏的两篇,而不是未注册草稿"
|
||||
- "复审通过后,10-32 才进入用户主导修订循环;本计划不替用户收尾"
|
||||
---
|
||||
|
||||
<objective>
|
||||
执行两篇补写内容的高级 I 独立读者审阅:派发一个与执行者不共享上下文的子代理,用 10-19 已经用户确认的高级 I 人格提示词通读 `mover.md` 与 `face-handler.md`(含它们在导览与侧边栏中的接入方式),产出问题清单;据此迭代修正阻断性问题,最后再派一个同人格子代理复审,直到阻断问题为零或把余项交给用户。
|
||||
|
||||
Purpose: 这两篇是「库文档式」的机制说明,读者真正会做的事是「照着接口排出一次移动」「换一个朝向处理器」「把朝向映射到图块数字」。所以问题通常不是代码放哪,而是「这个方法到底在什么时候被调用」「我换了处理器,为什么寻路没变」「这个偏移是谁算的」。这类问题必须由目标读者视角发现,而不是由作者视角自证。
|
||||
Output: `10-31-READER-REVIEW.md`(人格、问题、迭代、复审)、两篇文档的阻断问题修正、`10-31-SUMMARY.md`。
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/13194/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/13194/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/phases/10-docs-restructure/10-CONTEXT.md
|
||||
@.planning/phases/10-docs-restructure/10-19-READER-REVIEW.md
|
||||
@.planning/phases/10-docs-restructure/10-28-PLAN.md
|
||||
@.planning/phases/10-docs-restructure/10-29-PLAN.md
|
||||
@.planning/phases/10-docs-restructure/10-30-PLAN.md
|
||||
@docs/advanced/index.md
|
||||
@docs/advanced/mover.md
|
||||
@docs/advanced/face-handler.md
|
||||
@docs/advanced/hooks-in-depth.md
|
||||
@docs/advanced/ii/pathfinding.md
|
||||
@packages-user/data-common/src/common/mover.ts
|
||||
@packages-user/data-common/src/common/faceManager.ts
|
||||
@packages-user/data-common/src/common/face.ts
|
||||
@packages/common/src/utils/types.ts
|
||||
|
||||
**人格设定(D-57,沿用 10-19 已确认提示词,逐字不得改):**
|
||||
> 假设你是一位对代码有一定了解、了解基本语法(变量、函数、类、import 等),但代码能力一般、不熟悉引擎内部架构的游戏作者。你已经读完中级教程,正在阅读高级教程 I,想判断自己能不能照着文档完成插件等扩展。
|
||||
|
||||
**与中级审阅的区别:**
|
||||
- 中级人格是「不懂代码的游戏作者」(见 `10-11-READER-REVIEW.md`);本计划**禁止**复用该人格或该提示词。记录中可引用该名称说明差异,但不据此设置全文禁语。
|
||||
- 高级 I 读者了解基本语法、能看懂简单代码,但**不预设高代码水平**;问题应落在「这段代码该放哪」「两个系统怎么接」「照做之后为什么没有效果」「这个方法在什么时机被调用」「我改了处理器为什么另一处没变」。
|
||||
- 审阅对象是 `docs/advanced/` 的两篇新页(`mover.md` / `face-handler.md`),以及它们在导览与侧边栏中的接入;不要求重审既有七篇。
|
||||
|
||||
**流程约定:**
|
||||
- 迭代上限 **3 轮**;每轮后跑构建门禁;达到上限仍有阻断问题时停下向用户汇报。
|
||||
- 只改 `docs/advanced/mover.md` 与 `docs/advanced/face-handler.md`;不触碰 `config.ts`、导览与其它正文。
|
||||
- 命令一律经 `cmd /c "..."` 执行(本机 PowerShell 禁止 `pnpm.ps1`)。
|
||||
- 修正须守住 D-57..D-74(库文档风格、简洁、边界分离、代码块完整、模板顺序、注释充足、内部实现后置、注释优先、锚点链接);不因读者提问删掉 D-75 要求覆盖的内容。
|
||||
- 阻断性判定口径:读者据此**无法完成操作**(排不出一次移动 / 换不了处理器 / 取不到朝向图块),或会对**执行时序、状态归属、两层朝向模型产生实质误解**。
|
||||
- 非阻断问题只记录,不修(D-14),留给 10-32 的用户循环决定。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking-human">
|
||||
<name>Task 0: 向用户汇报读者审阅计划并确认人格沿用</name>
|
||||
<action>向用户汇报:**要做什么**(派发独立子代理,沿用 10-19 已确认的高级 I 人格提示词,通读 `mover.md` 与 `face-handler.md` 及其导览 / 侧边栏接入,产出问题清单,据此迭代修正阻断问题并复审)、**为什么**(D-75 明确要求补写完成后同样走独立读者审阅;D-46 第 1 阶段要求子代理自审;这两篇是机制说明,最容易出现「时序讲反 / 状态归属讲错 / 两层朝向混为一谈」)、**大致怎么做**(Task 1 派发 persona 子代理并落清单;Task 2 按清单修阻断问题,最多 3 轮、每轮构建;Task 3 复跑同人格审阅确认阻断清零并写 SUMMARY)、**影响范围**(可能修改两篇新文档中确有阻断问题的段落 + 新增 `.planning` 下的审阅记录与 SUMMARY;不改配置、导览与其它正文)。请用户确认:沿用 10-19 的人格提示词原文、不新造人格、审阅范围仅两篇新页(如希望扩展到既有七篇请明确说明,否则按本计划范围执行)。汇报中明确:本计划的修改方式为**派发子代理执行**,范围严格限于 `docs/advanced/mover.md`、`docs/advanced/face-handler.md` 与 `.planning/.../10-31-READER-REVIEW.md`、`10-31-SUMMARY.md`。停下等待用户明确回复「可以执行」四个字;未收到前不得派发子代理或改任何文件。</action>
|
||||
<what-built>本计划内容:两篇补写内容的高级 I 独立读者审阅 → 问题清单 → 迭代修正 → 复审确认。</what-built>
|
||||
<how-to-verify>阅读上面的四段说明;确认沿用 10-19 人格提示词、范围仅两篇新页、迭代上限 3 轮;如对范围或人格有修改请直接给出。</how-to-verify>
|
||||
<resume-signal>回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。</resume-signal>
|
||||
<verify>
|
||||
<human-check>用户已确认人格沿用与审阅范围,并回复「可以执行」。</human-check>
|
||||
</verify>
|
||||
<done>用户确认范围与人格并回复「可以执行」。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: 派发独立读者子代理并产出问题清单</name>
|
||||
<files>.planning/phases/10-docs-restructure/10-31-READER-REVIEW.md</files>
|
||||
<action>派发一个**独立子代理**(不与执行者共享上下文),人格与任务设定逐字为:「假设你是一位对代码有一定了解、了解基本语法(变量、函数、类、import 等),但代码能力一般、不熟悉引擎内部架构的游戏作者。你已经读完中级教程,正在阅读高级教程 I,想判断自己能不能照着文档完成插件等扩展。」让子代理先读 `docs/advanced/index.md` 确认这两篇在高级 I 中的位置,再通读 `docs/advanced/mover.md` 与 `docs/advanced/face-handler.md`,可以打开文档中被引用的源码核对,但**不假定它已通读引擎**。然后回答:「读完后你有哪些问题?哪些地方你照做会卡住、会改错接口、会把执行时序或状态归属理解反,或者分不清逻辑朝向与朝向图块?」子代理**只以读者身份提问**、不修改文件、不代入引擎作者视角。把原始提问与执行者的归类写进 `.planning/phases/10-docs-restructure/10-31-READER-REVIEW.md`:开头逐字记录高级 I 人格提示词与两篇范围,并单独写一行「未复用中级人格」标记;每条问题附文件与章节定位;按**阻断性**与**非阻断**分组。阻断性口径:读者据此无法完成操作,或会对执行时序、状态归属、两层朝向模型产生实质误解。**本轮不改文档**。Commit:`docs(10-31): 记录移动与朝向两篇读者问题清单`。</action>
|
||||
<verify>
|
||||
<automated>$ErrorActionPreference='Stop'; $f='.planning/phases/10-docs-restructure/10-31-READER-REVIEW.md'; if(-not(Test-Path -LiteralPath $f)){ Write-Error "MISSING $f" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $f)); foreach($needle in @('对代码有一定了解','了解基本语法','代码能力一般','不熟悉引擎内部架构','已读完中级教程','未复用中级人格','阻断','非阻断','docs/advanced/mover.md','docs/advanced/face-handler.md')){ if($raw -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-CONTENT $needle" } }; $flat=$raw -replace '\s',''; $persona='假设你是一位对代码有一定了解、了解基本语法(变量、函数、类、import等),但代码能力一般、不熟悉引擎内部架构的游戏作者。你已经读完中级教程,正在阅读高级教程I,想判断自己能不能照着文档完成插件等扩展。'; if(-not $flat.Contains($persona)){ Write-Error "MISSING-PERSONA-PROMPT" }; Write-Output 'REVIEW-OK'</automated>
|
||||
<fails_when>non-zero exit, or output contains "MISSING" or "MISSING-CONTENT" or "MISSING-PERSONA-PROMPT"; or output lacks "REVIEW-OK"</fails_when>
|
||||
</verify>
|
||||
<done>审阅记录存在;逐字含高级 I 人格提示词与两篇范围;问题按阻断 / 非阻断归类并定位到文件章节;标记未复用中级人格。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: 按清单迭代修正阻断问题(上限 3 轮)</name>
|
||||
<files>docs/advanced/mover.md, docs/advanced/face-handler.md, .planning/phases/10-docs-restructure/10-31-READER-REVIEW.md</files>
|
||||
<action>逐个消除 `10-31-READER-REVIEW.md` 中的**阻断性问题**:对每个阻断问题,修改对应文档的相应段落,使一个「了解基本语法但代码能力一般、不熟悉引擎内部架构」的读者也能完成操作——典型修法包括:补「这一步由谁调用、在什么时候调用」「这个状态写在移动器上还是对象上」「执行中追加为什么没生效,该用哪个接口」「逻辑朝向、方向处理器、朝向图块三者各自负责什么」「换了处理器后哪些使用方会变、哪些不会」;必要时补最短可行示例或调整章节顺序。只改确有阻断问题的部分;非阻断问题不修、仅保留在清单中供用户判断(D-14)。每轮修正后:(a) 跑构建门禁 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,须 green、`build complete`、dead link = 0;(b) 在 `10-31-READER-REVIEW.md` 追加该轮记录(本轮修了哪些问题、依据、构建结论)。迭代**最多 3 轮**:3 轮后仍有阻断问题时,停下把余项列给用户,不继续循环。守住 D-57..D-74,不因读者提问删掉 D-75 要求覆盖的内容(三件套、步骤类型、控制器、钩子、`degrade` / `next` / `opposite` / `mapMovement`、`IRoleFaceBinder`);不改 `config.ts`、导览与其它正文。每轮 Commit:`docs(10-31): 迭代修正移动与朝向文档阻断问题(第N轮)`。</action>
|
||||
<verify>
|
||||
<automated>$ErrorActionPreference='Stop'; $names=@('mover','face-handler'); foreach($n in $names){ $p="docs/advanced/$n.md"; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($raw -match "(?<!`r)`n"){ Write-Error "LF-ONLY $p" }; if(([regex]::Matches($raw,'(?m)^# ')).Count -ne 1){ Write-Error "H1-COUNT $p" }; if($raw -match 'src/client'){ Write-Error "RENDERER-CONTENT $p" } }; $f='.planning/phases/10-docs-restructure/10-31-READER-REVIEW.md'; if(([IO.File]::ReadAllText((Resolve-Path -LiteralPath $f))) -notmatch '轮|迭代'){ Write-Error "NO-ROUND-LOG" }; $ErrorActionPreference='Continue'; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'ITERATE-OK'</automated>
|
||||
<fails_when>non-zero exit, or output contains "MISSING", "LF-ONLY", "H1-COUNT", "RENDERER-CONTENT", "NO-ROUND-LOG", "BUILD-FAIL", "NO-BUILD-COMPLETE", or "DEAD-LINK"; or output lacks "ITERATE-OK"</fails_when>
|
||||
</verify>
|
||||
<done>阻断问题按最多 3 轮修正完毕(余项已交用户);每轮记录进 `10-31-READER-REVIEW.md`;构建 green、`build complete`、dead link = 0。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: 复跑同人格审阅确认阻断清零并写 SUMMARY</name>
|
||||
<files>.planning/phases/10-docs-restructure/10-31-READER-REVIEW.md, .planning/phases/10-docs-restructure/10-31-SUMMARY.md</files>
|
||||
<action>再次派发一个**独立子代理**(人格提示词逐字同 Task 1,不得换回中级教程人格),让它重新通读两篇并回答「现在还有哪些看不懂、照做会卡住、会把执行时序或状态归属理解反,或分不清逻辑朝向与朝向图块的地方?」。把复审结果追加进 `10-31-READER-REVIEW.md`:对照首轮清单,逐条标注「已消除」或「仍存在」;若仍有**阻断性**问题,回到 Task 2 再修(受 3 轮上限约束)。收敛时二选一写结构化结束标记:阻断问题清零记「阻断性问题 = 0,审阅通过」;3 轮上限后仍有阻断问题记「阻断性问题余项:已交用户」并列出余项与用户处置。复审记录同样保留「未复用中级人格」标记。最后跑一次构建门禁确认 green。写 `.planning/phases/10-docs-restructure/10-31-SUMMARY.md`:人格与范围、首轮问题数与分类、每轮修正摘要、复审逐条结论、结束标记、构建 / 链接 / 结构结论、非阻断残项(只记录)。Commit:`docs(10-31): 复审移动与朝向文档读者视角(收敛)`。</action>
|
||||
<verify>
|
||||
<automated>$ErrorActionPreference='Stop'; $f='.planning/phases/10-docs-restructure/10-31-READER-REVIEW.md'; if(-not(Test-Path -LiteralPath $f)){ Write-Error "MISSING $f" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $f)); foreach($needle in @('对代码有一定了解','了解基本语法','代码能力一般','不熟悉引擎内部架构','已读完中级教程','已消除','仍存在','未复用中级人格')){ if($raw -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-CONTENT $needle" } }; $flat=$raw -replace '\s',''; $persona='假设你是一位对代码有一定了解、了解基本语法(变量、函数、类、import等),但代码能力一般、不熟悉引擎内部架构的游戏作者。你已经读完中级教程,正在阅读高级教程I,想判断自己能不能照着文档完成插件等扩展。'; if(-not $flat.Contains($persona)){ Write-Error "MISSING-PERSONA-PROMPT" }; if($raw -notmatch '阻断性问题 = 0' -and $raw -notmatch '阻断性问题余项:已交用户'){ Write-Error "NO-TERMINAL-MARKER" }; $sum='.planning/phases/10-docs-restructure/10-31-SUMMARY.md'; if(-not(Test-Path -LiteralPath $sum)){ Write-Error "MISSING $sum" }; $s=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $sum)); foreach($needle in @('人格','复审','构建')){ if($s -notmatch [regex]::Escape($needle)){ Write-Error "SUMMARY-MISSING $needle" } }; $ErrorActionPreference='Continue'; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'RECHECK-OK'</automated>
|
||||
<fails_when>non-zero exit, or output contains "MISSING", "MISSING-CONTENT", "MISSING-PERSONA-PROMPT", "NO-TERMINAL-MARKER", "SUMMARY-MISSING", "BUILD-FAIL", "NO-BUILD-COMPLETE", or "DEAD-LINK"; or output lacks "RECHECK-OK"</fails_when>
|
||||
</verify>
|
||||
<done>复审结果记录进 `10-31-READER-REVIEW.md`(逐条已消除 / 仍存在);结束标记为「阻断性问题 = 0」或「阻断性问题余项:已交用户」(后者含余项与用户处置);SUMMARY 已写;构建 green、`build complete`、dead link = 0。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 执行者 → 子代理 | 读者人格子代理以独立上下文阅读两篇并提问,不修改文件 |
|
||||
| 构建期 markdown → 静态站点 | 正文由构建期静态渲染,无运行时输入 |
|
||||
| 站点 → 浏览器读者 | 站内链接是唯一可点击指向面 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-10-91 | Tampering / XSS | 被改的两篇正文 | low | mitigate | 只写文本、代码块、表格;不引入原始 `<script>` 或内联 HTML |
|
||||
| T-10-92 | Spoofing | 审阅记录 / 链接 | low | mitigate | 记录逐字保留人格与来源;链接检查断言目标存在 |
|
||||
| T-10-93 | Information Disclosure | 审阅记录 / 正文 | low | mitigate | 只引用仓库已公开路径与接口;不写密钥、账号 |
|
||||
| T-10-SC | Tampering | npm/pip/cargo installs | low | accept | 本阶段不安装任何包,无供应链安装面 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- 机制门禁:`10-31-READER-REVIEW.md` 含逐字人格提示词(按空白归一化后完整包含)、两篇范围、首轮清单、每轮迭代记录、复审对照结果、结束标记。
|
||||
- 人格门禁:沿用 10-19 已确认提示词,记录含「未复用中级人格」标记。
|
||||
- 迭代门禁:上限 3 轮;结束标记为「阻断性问题 = 0」或「阻断性问题余项:已交用户」。
|
||||
- 结构门禁:两篇仍 kebab-case、CRLF、单 H1;无渲染端内容。
|
||||
- 构建门禁:每轮及收尾均 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"` 通过,`build complete`,dead link = 0。
|
||||
- 越界门禁:`git status` 仅含两篇文档的修改与新增的 `.planning` 记录 / SUMMARY。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- 两篇补写内容按 D-46 第 1 阶段完成独立读者审阅:独立子代理 + 沿用已确认人格 + 问题清单 + 迭代 + 复审。
|
||||
- 阻断性问题清零(或余项已明确交用户);构建通过;两篇内容覆盖未被读者提问削掉。
|
||||
- 没有复用中级人格,没有越界改动。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/10-docs-restructure/10-31-SUMMARY.md` when done
|
||||
</output>
|
||||
176
.planning/phases/10-docs-restructure/10-32-PLAN.md
Normal file
176
.planning/phases/10-docs-restructure/10-32-PLAN.md
Normal file
@ -0,0 +1,176 @@
|
||||
---
|
||||
phase: 10-docs-restructure
|
||||
plan: 32
|
||||
type: execute
|
||||
wave: 4
|
||||
depends_on: [10-31]
|
||||
files_modified:
|
||||
- .planning/phases/10-docs-restructure/10-32-USER-REVIEW.md
|
||||
- .planning/phases/10-docs-restructure/10-32-SUMMARY.md
|
||||
- docs/advanced/mover.md
|
||||
- docs/advanced/face-handler.md
|
||||
- docs/advanced/index.md
|
||||
autonomous: false
|
||||
requirements: []
|
||||
user_setup: []
|
||||
estimate:
|
||||
tokens: 30000
|
||||
raw_tokens: 20000
|
||||
tasks: 5
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "用户主导的修订循环被真正执行:用户以本领域视角逐条提出问题 → 派子代理修改 → 回报 → 用户继续提,直到用户明确确认满意(D-46 第 2 阶段 / D-57)"
|
||||
- "`10-32-USER-REVIEW.md` 记录每一轮用户意见、落点、处置与构建结论;最终确认以独占一行的 `用户最终确认:通过` 或 `用户最终确认:满意` 记录"
|
||||
- "收尾由用户确认触发,不由 AI 自行收尾;用户未确认前不得写 SUMMARY 或宣称完成"
|
||||
- "两篇新文档与导览最终全部 kebab-case、CRLF、单 H1;prettier 检查通过;构建 green、`build complete`、dead link = 0"
|
||||
- "不改 `config.ts`、生产代码与渲染端内容;越界问题只记录、不实施(D-14);侧边栏高级 I 仍为 9 个目标"
|
||||
- "修订中不删除 D-75 要求覆盖的内容,也不把渲染端 / 编辑器 / 高级 III 的占位改成死链"
|
||||
artifacts:
|
||||
- ".planning/phases/10-docs-restructure/10-32-USER-REVIEW.md"
|
||||
- ".planning/phases/10-docs-restructure/10-32-SUMMARY.md"
|
||||
- "docs/advanced/mover.md"
|
||||
- "docs/advanced/face-handler.md"
|
||||
- "docs/advanced/index.md"
|
||||
key_links:
|
||||
- "执行 D-46 第 2 阶段 / D-57 的用户主导修订循环;这是本单元收尾的唯一合法出口"
|
||||
- "10-31 已消除独立读者人格的阻断问题;本计划处理用户以领域视角提出的问题"
|
||||
- "最终构建产物与审阅记录共同构成 D-09 的人工验收依据"
|
||||
---
|
||||
|
||||
<objective>
|
||||
执行两篇补写内容的用户主导修订循环并收尾:把接入站点后的 `mover.md` / `face-handler.md`(含导览条目)交给用户,由用户以本领域视角逐条提出问题;AI 派子代理修改、回报;用户继续提,直到用户明确确认满意。只有用户确认后才做最终格式与构建收口并写 SUMMARY。
|
||||
|
||||
Purpose: D-46 / D-57 明确要求:子代理审阅之后必须再经用户主导的修订循环,且必须获用户确认才可收尾,不得由 AI 自行收尾。本计划就是这条出口。
|
||||
Output: `10-32-USER-REVIEW.md`(用户意见与处置)、最终文档修订、`10-32-SUMMARY.md`。
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/13194/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/13194/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/phases/10-docs-restructure/10-CONTEXT.md
|
||||
@.planning/phases/10-docs-restructure/10-31-READER-REVIEW.md
|
||||
@.planning/phases/10-docs-restructure/10-27-USER-REVIEW.md
|
||||
@docs/advanced/index.md
|
||||
@docs/advanced/mover.md
|
||||
@docs/advanced/face-handler.md
|
||||
@docs/advanced/hooks-in-depth.md
|
||||
@docs/.vitepress/config.ts
|
||||
|
||||
**流程约定(D-46 第 2 阶段 / D-57):**
|
||||
- 用户主导:用户提问题,AI 不替用户判断「这不算问题」;用户说改就改,用户说不用改就不改。
|
||||
- 每轮:记录用户意见 → 派子代理逐条修改 → 回报 → 等用户继续提或确认。
|
||||
- 条目状态固定为 `状态:待处理` / `状态:已处理` / `状态:越界-不实施`(可带列表符号);最终确认单独写一行 `用户最终确认:通过` 或 `用户最终确认:满意`。收尾只检查以状态标记开头的条目行与这行最终标记,不把历史轮次里的字样当作未完成项。
|
||||
- **必须获用户明确确认(「通过」或「满意」)后才可收尾**;AI 不得自行收尾。
|
||||
- 用户指出的越界内容(超出这两篇与导览条目的范围)只记录、不实施(D-14)。
|
||||
- 修订不得删除 D-75 要求覆盖的内容;渲染端 / 编辑器 / 高级 III 仍只用代码 span 或 HTML 注释占位。
|
||||
- 命令一律经 `cmd /c "..."` 执行;不改 `config.ts`、生产代码与渲染端内容。
|
||||
|
||||
**交付方式:**
|
||||
- 本地预览:`cmd /c "pnpm docs:preview"`(预览 `public/_docs`);或直接浏览构建产物。
|
||||
- 审阅对象:`docs/advanced/mover.md`、`docs/advanced/face-handler.md`,以及 `docs/advanced/index.md` 中新增的两行与两个链接;重点看接口语义是否讲对、时序是否讲反、两层朝向模型是否清楚、示例能否照做、有没有死链。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking-human">
|
||||
<name>Task 0: 向用户汇报用户修订循环计划并等待「可以执行」</name>
|
||||
<action>向用户汇报:**要做什么**(执行两篇补写内容的用户主导修订循环:用户逐条提问题 → AI 派子代理修改 → 回报 → 用户继续提,直到用户确认满意;确认后做最终格式与构建收口)、**为什么**(D-46 第 2 阶段 / D-57 要求必须经用户循环且获用户确认才可收尾,不得由 AI 自行收尾)、**大致怎么做**(Task 1 交付构建产物并收集用户意见;Task 2 逐条修改并记录;Task 3 回报并等待用户继续提或确认;用户确认后 Task 4 做最终 prettier / 构建 / SUMMARY)、**影响范围**(可能修改 `docs/advanced/mover.md`、`docs/advanced/face-handler.md` 与 `docs/advanced/index.md` 的两个条目 + 新增 `.planning` 下的用户审阅记录与 SUMMARY;不改 `config.ts`、生产代码与渲染端内容)。汇报中明确:本计划的修改方式为**派发子代理执行**,范围严格限于上述三个文档与 `.planning/.../10-32-USER-REVIEW.md`、`10-32-SUMMARY.md`。停下等待用户明确回复「可以执行」四个字;未收到前不得交付审阅、不得派发修改子代理、不得写任何文件。</action>
|
||||
<what-built>本计划内容:两篇补写内容的用户主导修订循环 + 用户确认后的收尾。</what-built>
|
||||
<how-to-verify>阅读上面的四段说明,确认「用户确认后才收尾」的流程;如对交付方式(预览命令 / 审阅范围)有要求请一并说明。</how-to-verify>
|
||||
<resume-signal>回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。</resume-signal>
|
||||
<verify>
|
||||
<human-check>用户已回复「可以执行」。</human-check>
|
||||
</verify>
|
||||
<done>用户回复「可以执行」。</done>
|
||||
</task>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking-human">
|
||||
<name>Task 1: 交付构建产物,收集用户意见</name>
|
||||
<action>先跑 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"` 确认构建 green、`build complete`、dead link = 0,然后向用户交付:两篇的路径、它们在高级 I 导览与侧边栏中的位置、本地预览方式 `cmd /c "pnpm docs:preview"`,以及 10-31 的读者审阅结论摘要(阻断问题是否清零、非阻断残项列表)。请用户以本领域视角逐条提出:接口语义是否正确(`start` / 控制器 / 钩子时序、`degrade` / `next` / `opposite` / `mapMovement`、`RoleFaceBinder` 的绑定规则)、有没有讲错或讲漏、照着做会不会卡住、两层朝向模型是否讲清、示例能否直接运行、有没有死链或排版问题。**不要替用户判断某条算不算问题**;用户提出的每一条都记录到 `.planning/phases/10-docs-restructure/10-32-USER-REVIEW.md`(意见、定位、`状态:待处理`)。若用户直接回复「通过」或「满意」,就在记录中写独占一行的 `用户最终确认:通过` 或 `用户最终确认:满意`,并跳到 Task 3 的确认分支;否则本任务结束时带着用户意见清单进入 Task 2。Commit:`docs(10-32): 记录用户修订意见(第1轮)`。</action>
|
||||
<what-built>构建后的两篇文档与预览方式;10-31 的读者审阅结论摘要。</what-built>
|
||||
<how-to-verify>本地 `cmd /c "pnpm docs:preview"` 预览,或直接阅读两篇文档;按「接口语义 / 时序与状态归属 / 两层朝向模型 / 示例可照做 / 链接与排版」五类逐条提问。</how-to-verify>
|
||||
<resume-signal>请逐条列出问题(可带文件名与章节);若已满意,请直接回复「通过」或「满意」。</resume-signal>
|
||||
<verify>
|
||||
<human-check>用户已给出至少一条具体意见,或明确回复「通过」/「满意」。</human-check>
|
||||
</verify>
|
||||
<done>用户意见已记录,或用户已明确确认通过。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: 按用户意见逐条派子代理修改并回报</name>
|
||||
<files>docs/advanced/mover.md, docs/advanced/face-handler.md, docs/advanced/index.md, .planning/phases/10-docs-restructure/10-32-USER-REVIEW.md</files>
|
||||
<action>读取 `10-32-USER-REVIEW.md` 中 `状态:待处理` 的用户意见,逐条派子代理修改对应文档:每条意见都要落到具体文件与段落;用户说改哪里就改哪里,不擅自扩大范围;用户指出但属于渲染端、编辑器、高级 III 或生产代码的内容只记录、不实施(D-14),状态行写 `状态:越界-不实施`。每轮修改后:(a) 跑构建门禁 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,须 green、`build complete`、dead link = 0;(b) 在 `10-32-USER-REVIEW.md` 把该条状态行改为 `状态:已处理` 并写明处置与改动文件;(c) 向用户回报本轮改了哪些、怎么改的、构建结论。若用户又提出新意见,追加到记录并继续处理——这个循环由 Task 2 / Task 3 反复执行,直到用户确认。守住 D-57..D-74;不删除 D-75 要求覆盖的内容;不把占位改成死链;不改 `config.ts`、生产代码与渲染端内容。每轮 Commit:`docs(10-32): 按用户意见修订移动与朝向文档(第N轮)`。</action>
|
||||
<verify>
|
||||
<automated>$ErrorActionPreference='Stop'; $f='.planning/phases/10-docs-restructure/10-32-USER-REVIEW.md'; if(-not(Test-Path -LiteralPath $f)){ Write-Error "MISSING $f" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $f)); if($raw -notmatch '状态:已处理' -and $raw -notmatch '状态:越界-不实施' -and $raw -notmatch '用户最终确认:通过' -and $raw -notmatch '用户最终确认:满意'){ Write-Error "NO-DISPOSITION" }; if($raw -notmatch 'docs/advanced/'){ Write-Error "NO-TARGET" }; $names=@('mover','face-handler'); foreach($n in $names){ $p="docs/advanced/$n.md"; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $body=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($body -match "(?<!`r)`n"){ Write-Error "LF-ONLY $p" }; if(([regex]::Matches($body,'(?m)^# ')).Count -ne 1){ Write-Error "H1-COUNT $p" } }; $idx='docs/advanced/index.md'; if(-not(Test-Path -LiteralPath $idx)){ Write-Error "MISSING $idx" }; $i=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $idx)); foreach($needle in @('九篇','./mover.md','./face-handler.md')){ if($i -notmatch [regex]::Escape($needle)){ Write-Error "INDEX-MISSING $needle" } }; $ErrorActionPreference='Continue'; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'FIX-OK'</automated>
|
||||
<fails_when>non-zero exit, or output contains "MISSING", "NO-DISPOSITION", "NO-TARGET", "LF-ONLY", "H1-COUNT", "INDEX-MISSING", "BUILD-FAIL", "NO-BUILD-COMPLETE", or "DEAD-LINK"; or output lacks "FIX-OK"</fails_when>
|
||||
</verify>
|
||||
<done>本轮用户意见逐条落到具体段落;记录中状态与改动文件清楚;构建 green、`build complete`、dead link = 0。</done>
|
||||
</task>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking-human">
|
||||
<name>Task 3: 回报修改结果,等待用户继续提或确认满意</name>
|
||||
<action>向用户回报本轮处置:逐条列出用户意见 → 改了哪个文件/段落 → 怎么改的 → 构建结论;附上更新后的预览方式。然后请用户继续审阅:如果还有问题,请继续逐条提出(执行者回到 Task 2 继续改,循环不限轮次,直到用户满意);如果已经满意,请明确回复「通过」或「满意」。**只有用户明确回复「通过」或「满意」才可进入 Task 4 收尾**;用户沉默、只回复「可以」、或回复其它内容(包括「不满意」「未通过」)都不算确认,不得自行收尾。确认后在 `10-32-USER-REVIEW.md` 写独占一行的 `用户最终确认:通过` 或 `用户最终确认:满意`,并附用户原文。Commit:`docs(10-32): 记录用户确认结论`(仅在用户确认后提交)。</action>
|
||||
<what-built>按用户意见修订后的两篇文档与导览条目,以及逐条处置说明。</what-built>
|
||||
<how-to-verify>按上一轮的预览方式重新查看改动处;确认每条意见都已处理,且没有引入新的错误或死链。</how-to-verify>
|
||||
<resume-signal>若仍有问题,请逐条列出;若已满意,请回复「通过」或「满意」。</resume-signal>
|
||||
<verify>
|
||||
<human-check>用户已明确回复「通过」或「满意」(不含「不满意」「未通过」),或提出了新的具体意见。</human-check>
|
||||
</verify>
|
||||
<done>用户确认满意(记录原文),或用户提出了新的具体意见(回到 Task 2)。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 4: 用户确认后的最终格式、构建与 SUMMARY</name>
|
||||
<files>.planning/phases/10-docs-restructure/10-32-USER-REVIEW.md, .planning/phases/10-docs-restructure/10-32-SUMMARY.md, docs/advanced/mover.md, docs/advanced/face-handler.md, docs/advanced/index.md</files>
|
||||
<action>**前置:`10-32-USER-REVIEW.md` 已有独占一行的 `用户最终确认:通过` 或 `用户最终确认:满意`;未确认则不得执行本任务。** (1) 最终格式:`node node_modules/prettier/bin/prettier.cjs --write docs/advanced/index.md docs/advanced/mover.md docs/advanced/face-handler.md`,再 `--check` 确认通过。(2) 最终构建:`cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,确认 green、`build complete`、dead link = 0。(3) 最终结构:两篇 kebab-case、CRLF、单 H1;`config.ts` 的 `/advanced/` 侧边栏仍为 9 个目标(不含 `/advanced/ii/` 分组);两篇仍有返回导览链接与互链;无渲染端内容;渲染端 / 编辑器 / 高级 III 仍无真实链接。(4) 在 `10-32-USER-REVIEW.md` 记录最终结论:确认标记与用户原文、最终构建结论、非阻断残项(只记录,标注 `状态:越界-不实施` 或保留为非阻断说明,不写 `状态:待处理`)。(5) 写 `10-32-SUMMARY.md`,含:两篇文档与导览改动清单、用户循环轮次与处置摘要、10-31 读者审阅结论、最终构建 / prettier / 链接结论、未处理项(仅越界或非阻断)、以及「用户已确认收尾」的明确记录。Commit:`docs(10-32): 移动与朝向两篇用户修订循环收尾`。</action>
|
||||
<verify>
|
||||
<automated>$ErrorActionPreference='Stop'; $rev='.planning/phases/10-docs-restructure/10-32-USER-REVIEW.md'; $sum='.planning/phases/10-docs-restructure/10-32-SUMMARY.md'; if(-not(Test-Path -LiteralPath $rev)){ Write-Error "MISSING $rev" }; if(-not(Test-Path -LiteralPath $sum)){ Write-Error "MISSING $sum" }; $r=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $rev)); if($r -notmatch '(?m)^\s*(?:[-*]\s*)?用户最终确认:(通过|满意)\s*$'){ Write-Error "NO-USER-CONFIRMATION" }; if($r -match '(?m)^\s*(?:[-*]\s*)?状态:待处理\s*$'){ Write-Error "PENDING-USER-ITEMS" }; $s=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $sum)); foreach($needle in @('用户','确认','构建','两篇')){ if($s -notmatch [regex]::Escape($needle)){ Write-Error "SUMMARY-MISSING $needle" } }; $names=@('mover','face-handler'); foreach($n in $names){ $p="docs/advanced/$n.md"; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $body=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($body -match "(?<!`r)`n"){ Write-Error "LF-ONLY $p" }; if(([regex]::Matches($body,'(?m)^# ')).Count -ne 1){ Write-Error "H1-COUNT $p" }; if($body -match 'src/client'){ Write-Error "RENDERER-CONTENT $p" }; if($body -notmatch '\./index\.md'){ Write-Error "NO-BACKLINK $p" } }; $cfg=[IO.File]::ReadAllText((Resolve-Path 'docs/.vitepress/config.ts')); $targets=[regex]::Matches($cfg,"link:\s*'/advanced/(?!ii/)([^']*)'") | ForEach-Object { $_.Groups[1].Value } | Sort-Object -Unique; if($targets.Count -ne 9){ Write-Error ("ADV-LINK-COUNT " + $targets.Count) }; $ErrorActionPreference='Continue'; $pf = cmd /c "node node_modules/prettier/bin/prettier.cjs --check docs/advanced/index.md docs/advanced/mover.md docs/advanced/face-handler.md" 2>&1; $pfe=$LASTEXITCODE; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($pfe -ne 0){ $pf | Write-Output; Write-Error "PRETTIER-FAIL" }; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'CLOSEOUT-OK'</automated>
|
||||
<fails_when>non-zero exit, or output contains "MISSING", "NO-USER-CONFIRMATION", "PENDING-USER-ITEMS", "SUMMARY-MISSING", "LF-ONLY", "H1-COUNT", "RENDERER-CONTENT", "NO-BACKLINK", "ADV-LINK-COUNT", "PRETTIER-FAIL", "BUILD-FAIL", "NO-BUILD-COMPLETE", or "DEAD-LINK"; or output lacks "CLOSEOUT-OK"</fails_when>
|
||||
</verify>
|
||||
<done>用户确认已记录且无待处理项;两篇结构正确、有互链与返回导览、无渲染端内容;侧边栏 9 个目标;prettier 通过;构建 green、`build complete`、dead link = 0;SUMMARY 写明用户确认收尾。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 用户 → 执行者 | 用户意见是修订输入;执行者不得替用户判断某条不算问题 |
|
||||
| 执行者 → 子代理 | 修改子代理按用户意见改文档,不扩大范围 |
|
||||
| 构建期 markdown → 静态站点 | 正文由构建期静态渲染,无运行时输入 |
|
||||
| 站点 → 浏览器读者 | 站内链接是唯一可点击指向面 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-10-94 | Tampering / XSS | 用户修订后的两篇正文 | low | mitigate | 只写文本、代码块、表格;不引入原始 `<script>` 或内联 HTML |
|
||||
| T-10-95 | Spoofing | 用户确认记录 | low | mitigate | 只把用户明确回复的「通过」/「满意」记为确认;沉默或其它回复不算 |
|
||||
| T-10-96 | Information Disclosure | 审阅记录 / 正文 | low | mitigate | 只引用仓库已公开路径与接口;不写密钥、账号 |
|
||||
| T-10-SC | Tampering | npm/pip/cargo installs | low | accept | 本阶段不安装任何包,无供应链安装面 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- 机制门禁:`10-32-USER-REVIEW.md` 含每轮用户意见、定位、处置、构建结论与最终确认原文。
|
||||
- 确认门禁:记录含独占一行的 `用户最终确认:通过` 或 `用户最终确认:满意`;条目级 `状态:待处理` 为 0(越界项记 `状态:越界-不实施`)。
|
||||
- 构建门禁:每轮及收尾均 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"` 通过。
|
||||
- 格式门禁:prettier `--check` 对导览与两篇通过。
|
||||
- 结构门禁:两篇 kebab-case、CRLF、单 H1,互链与返回导览齐全;侧边栏高级 I 仍 9 个目标。
|
||||
- 越界门禁:不改 `config.ts`、生产代码与渲染端内容;越界意见只记录、不实施。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- 用户主导修订循环真实执行,用户明确确认满意;AI 未自行收尾。
|
||||
- 最终两篇可构建、可预览、无死链、无渲染端内容,导览与侧边栏仍为九篇。
|
||||
- 审阅记录与 SUMMARY 完整,能支撑 D-09 的人工验收。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/10-docs-restructure/10-32-SUMMARY.md` when done
|
||||
</output>
|
||||
Loading…
Reference in New Issue
Block a user