chore(road-editor): plan direct-edit task tree and add client test infra
Planning: parent design.md becomes the single authoritative contract (constraint model with 6 kinds, handle manifest, coordinate/unit layering, preview sequencing, storage layout and lazy migration, area config snapshot, API contract). Work is split into four independently verifiable child tasks with per-step gates and rollback points. Test infra: pin vitest 4.1.11, add test:client:unit for client pure logic, extend prettier globs to root *.ts so vitest.config.ts is checked. Add .gitignore: the repo had none, so inputs/, outputs/, workbench-data/ and the client build output were untracked rather than ignored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
{"file": ".trellis/tasks/08-26-direct-manipulation-road-editor/research/junction-tools.md", "reason": "逐条核对四态语义、会话互斥与「应用不等于保存」是否被正确实现"}
|
||||
{"file": ".trellis/tasks/08-26-direct-manipulation-road-editor/design.md", "reason": "核对路口三个 kind 的锚点、approach 优先级与 reserve 独占边界"}
|
||||
{"file": ".trellis/tasks/08-26-direct-manipulation-road-editor/research/joint-solver.md", "reason": "核对预览是否覆盖全部受影响派生对象,以及拟合失败时的诊断行为"}
|
||||
{"file": ".trellis/spec/guides/code-reuse-thinking-guide.md", "reason": "检查是否重复实现 EditSession、命令栈或 ghost/preview 图层"}
|
||||
21
.trellis/tasks/08-26-direct-edit-junction-tools/design.md
Normal file
21
.trellis/tasks/08-26-direct-edit-junction-tools/design.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# 设计
|
||||
|
||||
技术合约不在本文重复定义。权威定义见父任务 `.trellis/tasks/08-26-direct-manipulation-road-editor/design.md` 的以下小节:
|
||||
|
||||
- 「约束模型」— `junction-approach-width`、`junction-cutback`、`junction-corner-radius` 三个 kind 与其锚点。
|
||||
- 「编辑所有权」— junction reserve 独占、`junction-approach-width` 优先于道路 profile、单 `JunctionRef` 会话。
|
||||
- 「Handle manifest」— 手柄字段与 `reserves`。
|
||||
- 「预览时序与延迟预算」— 防抖、`previewSeq` 仲裁、`degraded`。
|
||||
- 「上线与回滚形态」— `directEdit` 开关。
|
||||
|
||||
会话状态、四态语义与所有权边界的完整推导见父任务 `research/junction-tools.md`。
|
||||
|
||||
## 本子任务的局部决定
|
||||
|
||||
- 工作区是独立路由,不是主地图上的浮层面板:路口编辑是高密度局部操作,叠在主地图上会与道路手柄争夺命中区。
|
||||
- 复用 `direct-edit-map-editor` 的 `EditSession`、ghost/preview source 与命令栈,不新建第二套编辑基础设施。差异只在加载的上下文范围与可用 kind。
|
||||
- 草稿属于活动工作副本的 session,不是独立导出文件。因此「取消」只需丢弃 session,不涉及文件回滚。
|
||||
- 「应用到工作区」不写盘:合并后的约束是活动副本的未保存状态,交给主地图的普通 undo/redo 管理。这样保存路径只有一条。
|
||||
- 会话互斥用显式守卫实现:存在未处理草稿时切换 `JunctionRef` 直接拒绝并提示,不做自动应用或自动丢弃——两者都会让用户丢失意图。
|
||||
- 本期只实现 `JunctionRef.type === 'node'`。`cluster` 分支保留类型但入口置灰,避免把 cluster 降级成多个互相冲突的普通路口编辑。
|
||||
- 单个角部圆角:本期只允许编辑一个 corner,多角部批量编辑属后续任务。
|
||||
@@ -0,0 +1,6 @@
|
||||
{"file": ".trellis/tasks/08-26-direct-manipulation-road-editor/design.md", "reason": "父任务权威合约:三个 junction kind、编辑所有权、handle manifest、预览时序、directEdit 开关"}
|
||||
{"file": ".trellis/tasks/08-26-direct-manipulation-road-editor/research/junction-tools.md", "reason": "会话边界、四态语义、入口与上下文加载范围、所有权划分的完整推导"}
|
||||
{"file": ".trellis/tasks/08-26-direct-manipulation-road-editor/research/joint-solver.md", "reason": "路口局部求解必须一起重算的派生对象清单与约束不变量"}
|
||||
{"file": ".trellis/tasks/08-26-direct-manipulation-road-editor/research/current-system.md", "reason": "现有 compileJunctionPlans、cutbackMeters 与 junctionTemplates 的能力边界"}
|
||||
{"file": ".trellis/spec/guides/code-reuse-thinking-guide.md", "reason": "必须复用 EditSession、ghost/preview source 与命令栈,禁止新建第二套编辑基础设施"}
|
||||
{"file": ".trellis/spec/guides/cross-layer-thinking-guide.md", "reason": "会话状态与约束在客户端、API、求解器之间的流转一致性"}
|
||||
41
.trellis/tasks/08-26-direct-edit-junction-tools/implement.md
Normal file
41
.trellis/tasks/08-26-direct-edit-junction-tools/implement.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# 实施计划
|
||||
|
||||
对应父任务 `implement.md` 的第 7 步。每步一个提交,门禁不过就停。
|
||||
|
||||
前置:`direct-edit-solver-api`(junction 三个 kind 的求解与预览端点)与 `direct-edit-map-editor`(`EditSession`、ghost/preview source、命令栈)均已交付。
|
||||
|
||||
## 1. 工作区路由与上下文加载
|
||||
|
||||
- 目标:能进能回,且不丢全局方位。
|
||||
- 范围:单 `JunctionRef` 路由(本期只走 `node`,`cluster` 入口置灰);从路口面或诊断进入;加载该路口的编辑上下文(路口面、进口、相邻道路短上下文、车道/connector、步行带、停止线、斑马线、诊断、当前约束);返回主地图并恢复位置。
|
||||
- 验证:`npm run test:client`、`npm run build`;手测——从路口面进入、从诊断进入、返回后主地图位置与选中态保持。
|
||||
- 门禁:`cluster` 入口置灰且有原因提示,不落到 node 分支。
|
||||
- 回滚点:纯新增路由,`directEdit` 开关关闭即隐藏入口。
|
||||
|
||||
## 2. 会话状态机与互斥守卫
|
||||
|
||||
- 目标:四态语义先于几何落地,避免后续用几何调试状态。
|
||||
- 范围:`draft` / `applied` / `saved` / `cancelled` 的纯逻辑;未处理草稿时切换 `JunctionRef` 的拒绝守卫;取消复原。复用 `EditSession`,不新建第二套命令栈。
|
||||
- 验证:`npm run test:client:unit` —— draft → 应用后成为主工作区未保存约束;取消后活动副本无残留;存在未处理草稿时切换被拒绝且草稿不丢;应用后的编辑可被主地图 undo/redo 撤销。
|
||||
- 门禁:切换拒绝路径有测试;不存在自动应用或自动丢弃草稿的分支。
|
||||
- 回滚点:纯逻辑模块,revert 后回到第 1 步的只读工作区。
|
||||
|
||||
## 3. 三项可拖能力与完整预览
|
||||
|
||||
- 目标:进口宽度、cutback、单角部圆角真正可编辑,预览覆盖全部受影响对象。
|
||||
- 范围:三类手柄的渲染与拖拽;首次拖拽即 ghost;防抖后服务端局部权威预览;预览覆盖道路面、路口面、步行带、车道中心线、connector/movement、停止线、斑马线、标线;拟合失败返回最后有效几何加结构化诊断。
|
||||
- 验证:`npm run test:client:unit`(手柄事件到三个 kind 的约束值投影)、`npm run test`(局部求解与全量编译对同一约束集结果一致)、`npm run test:client`、`npm run build`;手测——三项各自可拖;预览包含上述全部对象;制造拟合失败时不把非法图形显示成已应用。
|
||||
- 门禁:预览对象清单逐项核对通过;失败态显示最后有效几何而非空白或非法图形。
|
||||
- 回滚点:按 kind 分批提交,可单独回退某一类手柄。
|
||||
|
||||
## 4. 闭环验证
|
||||
|
||||
- 目标:与主工作区和持久化链路接通。
|
||||
- 范围:应用回主地图、保存、重新编译的完整往返;`expectedDocumentVersion` 复用主地图已实现的冲突处理。
|
||||
- 验证:`npm run format:check`、`npm run test`、`npm run test:client`、`npm run test:client:unit`、`npm run build`;手测——应用后返回主地图显示同一几何;保存后重新编译几何不变且约束状态 `exact`。
|
||||
- 门禁:`prd.md` 全部验收标准勾选。
|
||||
- 回滚点:revert 后回到第 3 步的预览-only 状态。
|
||||
|
||||
## 步骤依赖
|
||||
|
||||
1 → 2 → 3 → 4 硬顺序。第 2 步先于第 3 步是刻意的:会话四态若在几何可拖之后才做,取消与互斥的缺陷会被误当成求解问题。
|
||||
41
.trellis/tasks/08-26-direct-edit-junction-tools/prd.md
Normal file
41
.trellis/tasks/08-26-direct-edit-junction-tools/prd.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# 最小 JunctionTools
|
||||
|
||||
父任务:`.trellis/tasks/08-26-direct-manipulation-road-editor`。需求来源与权威合约在父任务的 `prd.md` / `design.md`。
|
||||
|
||||
## 目标
|
||||
|
||||
用专用工作区承载路口编辑,验证单一普通路口的进口宽度、cutback 与单个角部圆角,闭合"预览 → 应用到工作区 → 保存 → 取消"四态。这是路口能力的最小可信切片,不是完整路口编辑器。
|
||||
|
||||
## 顺序依赖
|
||||
|
||||
前置:`direct-edit-solver-api`(junction 相关的三个 kind 求解与预览端点)与 `direct-edit-map-editor`(`EditSession`、ghost/preview 图层、命令栈)。
|
||||
后继:无。cluster 高级编辑、多路口联动为独立后续任务。
|
||||
|
||||
## 范围
|
||||
|
||||
- 单 `JunctionRef`(`{type:'node'|'cluster', id}`,本期只走 `node`)的工作区路由与返回主地图的上下文保持。
|
||||
- 加载该路口的编辑上下文:路口面、进口、相邻道路短上下文、车道/connector、步行带、停止线、斑马线、诊断与当前约束。
|
||||
- 三项可拖能力:进口宽度、cutback、单个角部圆角。
|
||||
- session draft:首次拖拽即 ghost,防抖后服务端权威局部预览。
|
||||
- 「应用到工作区」合并有效草稿为活动副本的未保存约束;「保存」持久化;「取消」丢弃草稿并复原。
|
||||
- 会话边界:切换相邻路口前必须应用或取消。
|
||||
|
||||
## 不做
|
||||
|
||||
- cluster 的高级编辑与复合路口模板编排。
|
||||
- 多个路口的联合会话或联动编辑。
|
||||
- 控制设施的逐个手工布置。
|
||||
- 主地图道路区间的编辑(属 `direct-edit-map-editor`)。
|
||||
- OSM 图拓扑的修改。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [ ] 从路口面或诊断可进入工作区,并能带位置返回主地图。
|
||||
- [ ] 三项能力各自可拖,首次拖拽即有 ghost,防抖后显示服务端权威几何。
|
||||
- [ ] 预览包含全部受影响派生对象:道路面、路口面、步行带、车道中心线、connector/movement、停止线、斑马线、标线。
|
||||
- [ ] 拟合失败时返回最后有效几何加结构化诊断,不把非法图形显示成已应用。
|
||||
- [ ] 「应用到工作区」后返回主地图仍显示同一几何,且该编辑处于未保存状态、可被主地图 undo/redo 管理。
|
||||
- [ ] 「取消」后回到进入工作区前的状态,活动副本无残留。
|
||||
- [ ] 未处理草稿时切换相邻路口被拒绝,并提示先应用或取消。
|
||||
- [ ] 「保存」后重新编译几何不变,约束状态 `exact`。
|
||||
- [ ] `npm run format:check`、`npm run test`、`npm run test:client`、`npm run test:client:unit`、`npm run build` 全绿。
|
||||
26
.trellis/tasks/08-26-direct-edit-junction-tools/task.json
Normal file
26
.trellis/tasks/08-26-direct-edit-junction-tools/task.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "direct-edit-junction-tools",
|
||||
"name": "direct-edit-junction-tools",
|
||||
"title": "最小 JunctionTools",
|
||||
"description": "单一普通路口的进口宽度、cutback、单角部圆角与预览/应用/取消",
|
||||
"status": "planning",
|
||||
"dev_type": null,
|
||||
"scope": null,
|
||||
"package": null,
|
||||
"priority": "P2",
|
||||
"creator": "dingkang",
|
||||
"assignee": "dingkang",
|
||||
"createdAt": "2026-08-26",
|
||||
"completedAt": null,
|
||||
"branch": null,
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": "08-26-direct-manipulation-road-editor",
|
||||
"relatedFiles": [],
|
||||
"notes": "",
|
||||
"meta": {}
|
||||
}
|
||||
Reference in New Issue
Block a user