同步canonical content里程碑落地结果与润色口径

里程碑与实施计划状态改为 implemented

记录润色按 token 原位恢复引用与附件、被改写 part 末尾补位

记录遗留 TODO:润色删掉 token 时无法反推原位置
This commit is contained in:
2026-09-21 21:23:17 +08:00
parent 295d4af384
commit 7745264990
2 changed files with 24 additions and 5 deletions
@@ -3,7 +3,7 @@
| 字段 | 值 |
| --------- | --- |
| Milestone | `docs/project-memory/plans/【里程碑】DirectProject composer canonical content闭环-2026-09-21.md` |
| Status | planned |
| Status | implemented |
| Owner | Codex |
## 交付结果
@@ -14,7 +14,7 @@
1. **锁定当前失败面**:补一个最小回归测试,先证明 `applyDraftToRoot` 对含 `agc_attachment_reference` 的 root 重建会丢附件,并记录 Direct 当前的三份并行状态与附件 sidecar 合并点。
2. **收窄编辑器接口**:把 `ChatComposerDraft` 改成 content-only;将 `ResourceReferenceInput` 的受控恢复改为 `initialContent` / `content` 语义,删除 Direct 使用的 `value` + `references` 同步 effect。保留 `ChatReference` 仅用于 picker 节点创建和只读投影。
3. **替换所有 root 写入**:删除 `buildDraftSegments` / `applyDraftToRoot` 的 Direct 调用;提供一个完整的 `applyContentToRoot`(或同等深模块接口),保留文本换写、引用和附件的顺序与字段。AI 润色改为“读取 content → 只替换文本 part 的受控变换 → 按原序写回 content”,禁止用 prompt 文本重新解析 chip
3. **替换所有 root 写入**:删除 `buildDraftSegments` / `applyDraftToRoot` 的 Direct 调用;提供一个完整的 `applyContentToRoot`(或同等深模块接口),保留文本换写、引用和附件的顺序与字段。AI 润色改为“读取 content → 对回包文本按 token 扫描 → 原位换回真 part;被改写的 part 末尾补位”,引用与附件同一套口径
4. **收口 Direct controller**:以 `content[]` 作为草稿事实源;上传完成的附件在一个明确的 `append`/`merge` seam 合并,不再长期维护 `chatInput``chatReferences``chatContent` 三份状态。prompt 只在调用边界派生,队列和策略重试保留原 user item。
5. **隔离非 Direct caller**Planning V2 和资源快速编辑按各自需求选择 content-only 或独立文本 adapter;不得为了兼容它们把旧字段放回共享 Direct 接口。若快速编辑只需要文本,使用不承诺引用/附件语义的窄接口。
6. **补齐验收证据并清理**:删除无调用方的旧 helper、字段和注释;更新测试 fixture、专题文档和本计划状态。完成后把稳定结论合并回功能说明/共享记忆,并删除已完成的临时计划。
@@ -34,7 +34,7 @@
- `content[]` 是唯一可发送事实;任何 `prompt`、label、chip 文案都是派生值。
- `agc_attachment_reference` 不属于 `ChatReference`,不能借 `references` 传递。
- 文本润色只允许改变文本 part;若产品决定重排/删除引用,必须显式产生新的 content 变换,不得通过字符串 token 猜测
- 润色回包只按 token 反解析引用与附件(`draftScanToken` 与出站 `directCodexContentToPromptText` 同口径);token 被删掉时不猜位置,只把该 part 补在末尾,保证不丢
- Direct 初始首轮、普通提交、队列、权限确认重试都使用同一个 `DirectCodexUserItem` 语义。
## 验证命令
@@ -53,3 +53,12 @@ git diff --check
- 附件目前在 Direct controller 里作为待发 sidecar,若直接移入编辑器必须同步处理上传失败、移除、清空和项目切换;任何阶段都不能把附件只留在展示 chip 而未进入 user item。
- 润色服务只返回文本,不能让其响应覆盖原 content;失败时保留原 content。回滚使用 Git revert,不增加运行时开关或兼容分支。
- 工作树已有用户未提交修改,实施时只 stage 本里程碑涉及的 hunk。
## 落地结果
- 编辑器接口收窄为 content-only`ResourceReferenceInput` 只接 `initialContent` / `onChange``ChatComposerDraft` 只剩 `content``applyDraftToRoot` 与受控 `value` / `references` 同步 effect 均删除。
- 所有 root 写入统一走 `applyContentToRoot`;润色走 `applyPolishedTextToRoot`,对引用与附件做同一套 token 扫描并在原位置换回真 part,被改写的 part 末尾补位。
- Direct controller 去掉 `chatInput` / `chatReferences` / `chatContent`,附件在提交边界合成进同一份 canonical contentPlanning 与其它 legacy 消费方改用 `directCodexContentToLegacyContentDto` 单向取文本。
- 删除无调用方的 `EMPTY_CHAT_COMPOSER_DRAFT`
- 回归证据:`resourceReferenceInput`(含附件 round-trip、润色原位恢复、润色末尾补位)、`resourceReferences``chatPromptPolish``usePromptPolish``resourceCanvasAssetGenerationReferences`、全量 `appSurface`、AGC typecheck、`check:encoding``git diff --check`
- 遗留 TODO:润色服务把 token 一起删掉时无法反推原位置;需要精确恢复时由产品补带位置信息的润色协议。
@@ -3,7 +3,7 @@
| 字段 | 值 |
| ----------- | --- |
| Version | 1.0 |
| Status | planned |
| Status | implemented |
| Date | 2026-09-21 |
| Parent Spec | `docs/【功能说明】AGC聊天素材引用-2026-09-08.md` |
| Related ADR | `docs/adr/【ADR】DirectProject独立聊天容器与工作台钱包布局-2026-09-18.md` |
@@ -41,7 +41,8 @@
- `ChatComposerDraft``ResourceReferenceInput` 的 Direct 使用面和 Direct composer props 不再暴露 `text` / `references` 双轨草稿。
- 代码中不存在 Direct 路径对 `applyDraftToRoot(value, references)``replaceText(text)` 或等价 legacy 重建器的调用。
- `content[]` 中交错的文本、资源引用、运行区域引用、Skill 和附件经过:初始恢复 → 读取 → 润色回写 → 再读取,顺序和值完全一致
- `content[]` 中交错的文本、资源引用、运行区域引用、Skill 和附件经过:初始恢复 → 读取 → 润色回写 → 再读取,part 一个不少
- 润色回包还留着 `@显示名` / `$名称` / `@附件名` 时,对应 chip 在原位置复活;token 被整体改写掉的 part 补在末尾,不丢。
- 附件-only、文本+附件、资源引用+附件、文本+资源引用+附件四类提交均只生成一份 canonical user item,附件字段完整保留。
- 队列入队、出队、策略确认重试复用同一份 `userItem.content`,不从 prompt 文本重建。
- Direct 提交清理草稿后,待发附件和 editor content 同时清空;失败或取消不会悄悄丢失待发附件。
@@ -52,3 +53,12 @@
- ResourceReferenceInput 纯投影/回写测试:包含附件节点的 round-trip 与润色回写不丢附件。
- Direct composer appSurface:四类 content 组合、队列、策略重试及清理语义。
- 类型检查、定向 Vitest、`npm run check:encoding``npm run check:doc-index``git diff --check`
## 落地结果
- `ChatComposerDraft` 只剩 `content``ResourceReferenceInput` 的对外接口是 `initialContent` + `onChange` + `getDraft()`,受控 `value` / `references``applyDraftToRoot` 已删除。
- 编辑器 root 回写只剩 `applyContentToRoot`(完整 content,含附件)一条路径;清空、初始恢复、润色回写都走它。
- Direct composer 提交时把 editor content 与待发附件 sidecar 合成同一份 canonical contentcontroller 不再持有 `chatInput` / `chatReferences` / `chatContent`
- Planning 提交与 legacy 消费方通过单向 `directCodexContentToLegacyContentDto` 取文本,不回写编辑器。
- 润色回写(`applyPolishedTextToRoot`)对引用与附件用同一套 token 扫描(`draftScanToken`):token 存活则原位换回真 part,被改写的 part 末尾补位;附件不再丢出 canonical content。
- 遗留 TODO:润色服务整体改写文本、连 token 一起删掉时,前端无法反推原位置,只能末尾补位;需要精确恢复时由产品补带位置信息的润色协议。