Skip to content

fix(goals): isolate Objective presentation and unify legacy readback - #4402

Merged
huangruiteng merged 4 commits into
loopx-project:mainfrom
ehz0ah:codex/fix-fenced-goal-prompt
Sep 15, 2026
Merged

huangruiteng merged 4 commits into
loopx-project:mainfrom
ehz0ah:codex/fix-fenced-goal-prompt

Conversation

@ehz0ah

@ehz0ah ehz0ah commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Problem and resulting behavior

Closes #4401.

Objective text containing Markdown fences, HTML comments, headings or Todo examples could change the generated Goal document structure. In the guided start path, whitespace normalization could turn a closed multiline fence into an unclosed fence for the Todo reader and hide the real connection-validation Todo.

Both bootstrap and project registration now quote and HTML-escape Objective content, with shared JSON-compatible frontmatter encoding/readback. Chat preserves the original narrative and its existing 600-character display limit. Repeated registration accepts equivalent legacy presentation without rewriting it; changed metadata or surrounding narrative still conflicts.

RFC-aligned companion refactor

  • Reuse the existing Goal metadata and section owners; delete Chat's duplicate section scanner.
  • Compare decoded metadata and exact narrative instead of rebuilding a legacy document through replacement.
  • Keep this in the permanent Python presentation/legacy-input adapter permitted by the TypeScript RFC. No new TS RPC, business state machine, provider or authority write is introduced.
  • Preserve the shared-authority RFC boundary: canonical Todo consumers use canonical state even when Markdown display is malformed. Objective remains independent Goal narrative outside the Todo store/recovery scope. This does not qualify D1–D3 or promote whole-Goal authority.
  • Update the protocol boundary and both RFCs in English and Chinese. Existing malformed documents are not automatically repaired.

Validation

Reviewed head: 6c83dec7147601bd2559565163632db25a66137a; base: b2516b25a37aae37374cdce9754c5ce0e092f7b2.

  • 437 tests passed with an isolated qualified Node 22.22.3 runtime: Objective, registration, canonical File/SQLite projection/recovery, handoff/alignment, Chat HTTP/configuration and architecture checks.
  • The same real public CLI harness at base/head covers plain text, closed fences, open comments and escaped text: plain parity; baseline fails three independent invariants; head passes all four scenarios.
  • Canonical recovery tests hold canonical records fixed while replacing/corrupting Markdown; real CLI Todo reads still return canonical work.
  • Ruff passes all seven changed Python files; configured Mypy passes 22 source files; diff hygiene passes. The earlier equivalent product tree also passed installed-wheel CLI checks.
  • All four branch commits include DCO sign-offs. The earlier failed DCO check identified the old merge commit, not the original author's two signed commits.

Affected entry points: CLI bootstrap/project registration and Chat goal-context readback. No frontend control or packaged asset changes are needed: the existing context field remains text with the same display limit; the producer/readback contract is what changes.

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

详细中文评审

审查对象:51a5a3409a8a29217478263917759e14902e8444fix(goals): isolate objective Markdown from Todo state,base main,7 文件 +171/-24)。执行契约 policy_revision=3;结果 JSON 已通过 pr-review --check-result

动机

与并行 PR #4418 同一个洞,但本 PR 的边界画得更完整:不只是正文被 objective 打开语法,frontmatter 也只用 objective.replace('"','\\"') 这种手写转义,所以 objective 里的反斜杠与 U+0085/U+2028/U+2029 行分隔符会让「写回」和「读回」不再对称。结果同样是静默的:Todo 源被吞、读回文本与原文不一致,都没有报错。本 PR 把「编码」与「解码」定义成一对共享规则,并让正文与 frontmatter 同时受它保护。

改动思路

把呈现层规则搬进 goals 边界上下文 loopx/control_plane/goals/active_state_metadata.py(与 parse_state_frontmatter 同域),提供三个函数:markdown_frontmatter_string(JSON 字符串编码并转义行分隔符)、markdown_blockquote(逐行引用 + HTML 元字符转义)、active_state_section_text(按标题读段并解码)。两个 renderer 共用编码函数,chat server 的私有 _active_state_section 被删除并改调共享读回。项目注册新增 legacy 形态比较,使既有未引用状态无需改写即可幂等重注册。

具体改动

  • markdown_frontmatter_stringactive_state_metadata.py:27):json.dumps(..., ensure_ascii=False) 后把 U+0085/U+2028/U+2029 转成 \uXXXX,保证单行值语义。
  • markdown_blockquote:35):逐行 > + escape(line, quote=False)
  • active_state_section_text:38):整行标题匹配、按 ## 找段尾、Objective 段落全为引用行时 unescape 解码并把空白折叠。
  • 两个 renderer:bootstrap.pyprojects/registry.py 的 Objective 段落与 frontmatter 改用共享函数。
  • register_project_goalregistry.py:330):接受 legacy 形态(旧 frontmatter 转义 + 裸正文),避免为老文件强制改写。
  • 文档:docs/reference/protocols/active-state-structured-projection-v0.md 增补 Markdown Ownership Boundary 段,明确「改变呈现,不改变 Todo 权威与迁移,不自动修复既有畸形文档」。
  • 测试:tests/cli_commands/test_project_registry.pytests/control_plane/test_todo_next_action_settlement.py 参数化扩展,覆盖围栏(反引号/波浪线)、未闭合注释、行内标题、三种 Unicode 分隔符、HTML 文本、反斜杠、待办示例与围栏区域示例。

对主干的风险

本 head 不能进合并队列,有两项阻塞:

  1. DCO:作者提交 ea0944c1b5d45f5cb6Signed-off-by,远端 Sign-off 检查 fail。
  2. 分支状态:head 51a5a3409 是「Merge branch 'main'」的合并提交,mergeable=CONFLICTING,需要 rebase 到当前 main。

test-shard (3) 的红不是本 PR 引入:tests/control_plane/test_delivery_response.py::test_real_resume_projection_identity_survives_python_transport[resume_at:...-patch3] 在本 head 报 assert 'history_supervision' == 'canonical_todo_wait',而在当前 main 上同一测试文件 12 passed。原因清晰——main 的 #44112c4e35ba3)正好改了这条断言的时钟无关性,而本 head 的基线早于它。rebase 之后这条红会消失。

技术方向的残余风险有两处(均为非阻塞,见下):除 chat server 之外的裸文本消费者(例如直接读文件的展示面)会看到 & 形式的字面量,本 head 未验证;legacy 兼容比较只覆盖「旧转义 + 裸正文」一种历史形态,含反斜杠或引号的旧文件重注册仍可能误报冲突。另外本 PR 与 #4418 覆盖同一个洞,两节点重复交付同一修复。

我的整体评价

REQUEST_CHANGES(阻塞项是交付卫生,不是技术方案)。在两项并行实现中,本 PR 是可取的引擎:编码/解码成对、规则落在正确的边界上下文、既有文件不被改写、~ 与 ``` 围栏、U+2028 类分隔符与 HTML 元字符都有正反用例;repository_reuse=separation_justified、`change_proportionality=proportionate`、`observable_semantics=intentional_change_validated`,并且本 head 的 ratchet 为绿(`chat_server.py` 由 1513 降到 1498 行),而 #4418 恰好在这一项上失败。

非阻塞建议两条:

  1. P2 · 段读取归属:active_state_section_text 是仓库第三份段扫描实现,同包的 active_state_sections 已按 SECTION_HEADING_PATTERN 抽段,建议组合复用而不是再写一份。
  2. P2 · legacy 判定:register_project_goal 的兼容比较用逐字替换推 legacy 文本,建议改成按 frontmatter 值等价比较,并补「旧 frontmatter 含反斜杠」的幂等用例。

合并前的最小修复:rebase 到当前 main(顺带吸收 #4411)+ 为两个作者提交 git commit --amend -s。合并序列上建议本 PR 承担该修复,#4418 收敛关闭,避免同一处边界两节点并行。

验证:head 51a5a3409 独立 worktree 内 pytest tests/cli_commands/test_project_registry.py tests/control_plane/test_todo_next_action_settlement.py -q → 89 passed;pytest tests/canary/test_maintainability_ratchet.py -q → 8 passed;pytest tests/control_plane/test_delivery_response.py -q 在本 head 红、在当前 main 12 passed(定位为过期基线)。远端 checks:Sign-off/pytest/merge-gate/test-shard (3) fail,其余 pass 或 skipping。


English verdict: REQUEST_CHANGES at 51a5a3409a8a29217478263917759e14902e8444 — blocking items are delivery hygiene, not the technical approach. Two author commits (ea0944c1b, 5d45f5cb6) lack Signed-off-by so the remote Sign-off check fails, and the head is a merge commit from main with mergeable=CONFLICTING, so it needs a rebase. The shard-3 red (test_delivery_response expecting canonical_todo_wait) is a stale-base effect: the same file passes 12/12 on current main because #4411 (2c4e35ba3) made that assertion clock-independent; the rebase clears it. Technically this is the better of the two same-boundary fixes: encoding and decoding are paired, the rules live in the goals bounded context beside parse_state_frontmatter, existing unquoted registrations stay idempotent, and the canary ratchet is green at this head (chat_server drops 1513 → 1498 lines) where the parallel #4418 fails it. Non-blocking P2s: active_state_section_text should compose the existing active_state_sections scanner instead of adding a third section reader, and the legacy-registration comparison should compare frontmatter values rather than reconstructing legacy text. Validated at this head: 89 focused tests pass, ratchet 8 passed.

@huangruiteng
huangruiteng force-pushed the codex/fix-fenced-goal-prompt branch 2 times, most recently from 7978bd9 to 0fff026 Compare September 15, 2026 11:42
@huangruiteng huangruiteng changed the title fix(goals): isolate objective Markdown from Todo state fix(goals): isolate Objective presentation and unify legacy readback Sep 15, 2026
ehz0ah and others added 4 commits September 15, 2026 19:49
Keep objective examples from hiding or creating generated Todos while preserving legacy registration and chat readback.

Signed-off-by: Hao Zhe <haozhe4547@gmail.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Move objective serialization and section readback to the existing state metadata owner, restoring dependency boundaries and the chat module budget without changing chat truncation.

Signed-off-by: Hao Zhe <haozhe4547@gmail.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng
huangruiteng force-pushed the codex/fix-fenced-goal-prompt branch from 0fff026 to 6c83dec Compare September 15, 2026 11:49
@huangruiteng

Copy link
Copy Markdown
Collaborator

RFC review frame and prior-comment resolution

This follow-up implements the requested bounded refactor against both RFCs:

RFC boundary What this PR does Qualification boundary retained
TypeScript control-plane migration Consolidates Objective serialization/readback in the existing Goal metadata/section owners and deletes Chat's private scan. The RFC retains Python presentation and legacy-input adapters. No new TS transport or duplicate business decision owner is introduced; no business-authority migration is claimed.
Shared Goal authority Closes a D1 presentation seam. Real canonical Todo reads remain unchanged after Objective replacement and malformed Markdown display. No provider activation, D2/D3 qualification, whole-Goal promotion, or expanded authority/recovery scope. Objective remains independent Goal narrative outside the Todo store.

The two P2 suggestions in the previous review are addressed: section readback composes active_state_sections; registration compares decoded frontmatter values and exact remaining narrative, with legacy backslash/quote/Unicode no-op coverage and drift rejection.

Correction to that review's DCO attribution: the original author commits 5d45f5cb6 and ea0944c1b already contained sign-offs. The failed DCO annotation identified the old merge commit 51a5a3409. The rebuilt branch preserves the original author's signed commits and adds maintainer sign-offs; every current branch commit is signed. The earlier statement blaming the two author commits was incorrect.

中文结论:按两个 RFC 做了展示/旧输入适配层的伴随收敛;保留 TS 业务权威和 canonical Todo 来源边界,未把这项修复扩展为整 Goal 迁移。旧 review 的两个 P2 建议均已落实,DCO 归因也在此更正。

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

详细中文评审

审查 head:6c83dec7147601bd2559565163632db25a66137a;base:b2516b25a37aae37374cdce9754c5ce0e092f7b2。结论:APPROVE,无阻塞 finding。

policy_revision=3 完成 whole-PR 复审和结构化结果校验。旧 review 到本 head 的变化包括:共享段扫描器复用、元数据值比较、JSON 读回补齐、真实入口回归、双语 RFC 边界说明及签名分支重建。下面的结论针对整个当前 PR,不继承旧 head 的技术结论。

动机

Objective 是用户要做什么的叙述,里面的示例不能成为真实待办,也不能把真正的待办藏起来。旧 bootstrap 和 project-register 将它直接插入 Markdown;guided start 又会折叠空白,把一个合法闭合的多行围栏变成同一行的围栏,后续扫描便可能把实际 Agent Todo 当成围栏内容。用户看到初始化成功,连接验证任务却没有进入可执行队列。

这不是只读 diff 推测:同一组真实 CLI 输入在 base/head 对照中,闭合围栏的真实 Todo 数由 0 恢复为 1;未闭合注释由 Chat 空文本恢复为原文;反斜杠、引号和 --- 的元数据准确读回。普通文本保持一致。只给正文加引用还不够:共享元数据读取器原来仍按任意 --- 切分并剥引号,编码与解码不对称,开发时新增的 8 个相关断言曾因此失败。

改动思路

本次采用两个 RFC 允许长期保留的 Python 展示/legacy 输入适配边界:显式 Objective 输入经过同一组编码函数进入两个既有文档生成器;Chat 通过 Goal 的共享段读取器读回叙述。业务决策、canonical Todo 事务与 legacy writer fence 继续由原来的 owner 控制。没有新增 TS RPC、provider、状态字段或一份需要同步的 Objective authority。

我比较了不修、仅包引用、当前共享 codec 收敛及新建 TS 通道四种方案。当前方案在既有 Goal owner 中闭合 writer/readback,删除重复规则,规模与缺陷匹配;专门为转义新增跨语言通道并不能删除业务决策,只会增加维护边界。两条写路径均调用同一 codec;独立 Todo region parser 保留,是因为它负责结构化工作区,不负责 Objective 叙述。

shared-authority 的约束由真实 canonical File 场景验证:替换 Objective 展示、执行 todo project-markdown,再将 Markdown 改成不可读注释,canonical snapshot 都保持不变,真实 CLI todo list 仍返回 todo_active。这是 D1 适配层修正,未宣称完成 D1–D3 资格化或整 Goal cutover。Objective 仍是独立 Goal narrative,不属于 Todo store/recovery。

具体改动

全量差异为 12 文件,+331/-34:生产代码 4 文件 +89/-32,测试 3 文件 +205/-2,协议及双语 RFC 5 文件 +37。没有生成日志、临时探针、私有状态或前端资产进入 diff。

关键代码讲解

  1. render_state_markdownbootstrap.py:469:正文逐行引用并转义 HTML 元字符,frontmatter 使用单行 JSON 字符串。同样规则用于 project-register 的 _state_markdown。围栏、注释、标题和 Todo marker 留在叙述内部,实际 Todo section 不受其影响;原有注册事务和写入 fence 未改动。
  2. active_state_section_textactive_state_metadata.py:41:先分离 frontmatter,再组合既有 active_state_sections;生成的 Objective 引用只解码一次,旧裸正文保留 fallback。Chat 私有扫描器被删除,_compact_text 仍将展示限制为 600 字符。已有标题尾空白也受回归保护。
  3. split_state_frontmatteractive_state_metadata.py:60:只有完整分隔行结束 frontmatter;双引号字符串按 JSON 解码,不能 JSON 解码的历史拼写保留兼容路径。既有 parse_state_frontmatter 成为该函数的薄包装,避免新 writer 与旧 reader 再次不对称。
  4. _registration_state_matchesregistry.py:180:比较解码后的元数据和精确的非 Objective 正文,只接受同一 Objective 的裸文本或生成引用两种表示。重复注册不重写文件;状态和验收内容的实质变化仍进入原冲突路径,而不是通过字符串替换被抹掉。

测试集中到专门的 Objective 回归模块,并扩展注册和 canonical recovery 的既有真实入口测试。协议与两个 RFC 的中英文版本明确记录新增的展示隔离及未扩大的权威范围。旧 review 的两个 P2 均已落实;DCO 的错误归因已在配套评论更正:原作者提交已有签名,旧合并提交缺签名。当前四个提交均有 sign-off。

对主干的风险

主要风险是共享 frontmatter decoder 影响 handoff、alignment、status 等旧消费者,以及兼容比较过宽导致重复注册覆盖不同内容。相邻测试覆盖这些消费者;旧/新格式、反斜杠/引号/Unicode 的等价注册保持原始字节,状态或验收内容被改动时返回冲突,并验证 registry 与 state 均未被写入。Objective 中的假 Todo 不能新增工作,破损展示不能取代 canonical state。

验证包括:437 项测试通过;同一真实 CLI harness 在不可变 base/head 的 4 组输入对照;Ruff 检查 7 个变更 Python 文件;配置内 Mypy 检查 22 个源文件;diff hygiene;精确范围质量凭据 cqr_11d2633d637f3d03a36floopx canary premerge --from-git-diff --git-diff-base b2516b25a(4 项直接检查、18 项选中检查全部通过,0 失败、0 跳过、0 manual hold)。此前等价生产树的 wheel 构建、安装及同一 CLI 场景也通过。最新基线的 UTF-8 subprocess 改动纳入失效检查,因此重新执行完整相邻测试和 CLI 对照,而没有把旧绿灯直接搬过来。

边界说明:没有新的 opt-in/default-off 声明、调度义务、actor 权限或 prose-based 业务分类。正则只处理展示格式的完整标题/分隔行。CLI 与 Chat context 是受影响入口;现有字段仍是文本、600 字符限制不变,无需新的前端控件或资产。现有畸形文件不自动修复,任意第三方 Markdown AST/renderer 的全面一致性也不在本 PR 保证内。

我的整体评价

APPROVE。 该 PR 修复了真实生成路径上的静默丢 Todo,并借同一变更原因消除了 Chat 扫描和注册兼容的重复知识。净增 57 行生产代码在已有 owner 内完成闭合,没有借修复扩张为整 Goal 存储迁移。代码体量、复用、authority naming、默认行为披露和 typed-state 边界均与两个 RFC 的当前阶段一致。

面向后续的收敛已应用:共享 codec/section owner、删除私有扫描器和替换式兼容分支;更大的 TS 业务迁移继续按 RFC 单独推进。当前范围无阻塞残余风险,已有畸形文档的修复仍应走既有显式恢复路径。该结论允许在同一 head 的所有远端检查与最终 merge-readiness 通过后按授权合并;它不豁免任何门禁。


English verdict: APPROVE at 6c83dec7147601bd2559565163632db25a66137a. No blocking finding. Both Objective producers and readback now share the existing Goal presentation boundary; legacy no-op registration preserves bytes and rejects real drift. The companion refactor follows the TS/shared-authority RFCs without adding a TS RPC, provider, duplicate authority, or whole-Goal cutover. Validated with 437 focused/adjacent tests, identical real CLI baseline/head scenarios, canonical File/SQLite recovery coverage, Ruff, configured Mypy, exact-scope quality qualification and risk-based canary. Existing malformed documents are not automatically repaired; merge still requires all current-head remote checks and merge-readiness.

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

动机

两个文档生成入口把 objective 原样插进正文的 ## Objective 段:objective 里如果带 ``` / ~~~ 围栏、<!-- 注释开头、行内 `## ` 标题或 `---` 分隔线,读回时就会被当成文档结构——围栏示例被当成真实任务、Todo 区域被吞掉;frontmatter 一侧在 `bootstrap.py` 还只用 `objective.replace('"','\"')` 手写转义,反斜杠与 U+0085/U+2028/U+2029 会让"写回"和"读回"不对称。上一轮 review 认定本 PR 是这条边界上更好的那个实现,但要求先 rebase 并补 DCO,另外提了两条 P2:段读取应复用已有的 `active_state_sections`,legacy 兼容判定应按 frontmatter 值比较而不是重建旧文本。

当前 head 6c83dec7147601bd2559565163632db25a66137a 已经 rebase(mergeable=MERGEABLE),并把两条 P2 都做掉了。

改动思路

把"编码"和"解码"定义成一对共享规则,放在 goals 边界上下文 loopx/control_plane/goals/active_state_metadata.py(与既有 parse_state_frontmatter 同域):markdown_frontmatter_string 只产生单行 JSON 字符串并转义 Unicode 行分隔符;markdown_blockquote 逐行引用并转义 HTML 元字符;active_state_section_text 复用同包既有的 active_state_sections 抽段,只在该段整体是引用行时解码;split_state_frontmatter 用行锚定正则替代 split('---', 2),并按 JSON 语义解码、对非 JSON 的旧值回落到旧的 strip('"') 形态。两个 renderer 共用编码,chat_server 的私有扫描器被删除并改调共享读回;register_project_goal 的兼容比较改为"解码后的 metadata 相等 + 正文精确相等(新引用形态或旧裸文本形态)",使既有未引用状态无需改写即可幂等重注册,而内容真变了仍然报冲突。展示规则变了,Todo 权威、恢复范围与文档迁移都没有变。

具体改动

  • loopx/control_plane/goals/active_state_metadata.py(+68/-9):新增 markdown_frontmatter_stringmarkdown_blockquoteactive_state_section_textsplit_state_frontmatterparse_state_frontmatter 改为其薄封装。
  • loopx/bootstrap.py(+7/-3)与 loopx/control_plane/projects/registry.py(+27):两个生产的 frontmatter 与 Objective 段都走共享函数;注册新增 _registration_state_matches
  • loopx/chat_server.py(+2/-17):删除私有 _active_state_section,改用共享读回,文件净减 15 行。
  • 文档:docs/reference/protocols/active-state-structured-projection-v0.md 增补 Markdown Ownership Boundary 段,四份 RFC(中英)记录"编码/读回复用 Goal codec、不迁移权威"。
  • 测试:tests/control_plane/test_goal_objective_projection.py(+119,新文件,14 个 objective 形态参数化)、tests/cli_commands/test_project_registry.py(+66)、tests/control_plane/test_todo_projection_recovery.py(+22)。

关键代码讲解

  1. active_state_section_textactive_state_metadata.py:38):先 split_state_frontmatter 去掉 frontmatter,再调用同包的 active_state_sections(body, (heading,), section_heading_pattern=re.compile(r"^## (.+?)[ \t]*$"))——这正是上一轮 P2 要求的复用,仓库里不再多出第三份段扫描;仅当该段所有非空行都以 > 开头时才做 unescape,旧裸文本段落仍按原来的 bullet/注释规则处理。
  2. split_state_frontmatter(:62):\A---[ \t]*\r?\n(.*?)^---[ \t]*(?:\r?\n|\Z) 只认"整行分隔符",字段只以物理 LF 结束,值以 " 开头时按 JSON 解码,解码失败才回落到旧的去引号形态——旧写入器不转义反斜杠,所以这条回落是必要的兼容。
  3. _registration_state_matchesregistry.py:180):metadata 按解码值比较(旧未引用形态与新 JSON 形态解码后相等),正文用 existing_section in (quoted + remainder, objective + remainder) 精确匹配"新引用形态"或"旧裸文本形态",其余一律报冲突,不重写既有文件。

对主干的风险

结论:本 head 没有阻塞项。上一轮的两条交付卫生问题(缺 Signed-off-by、merge commit 冲突)已解决,gh pr view 4402 显示 mergeable=MERGEABLEmergeStateStatus=BLOCKED 只是 required checks 与 review 尚未完成)。我在 head 6c83dec71 上跑了:

  • pytest tests/cli_commands/test_project_registry.py tests/control_plane/test_goal_objective_projection.py tests/control_plane/test_todo_next_action_settlement.py tests/canary/test_maintainability_ratchet.py -q107 passed,14 个 objective 形态(围栏、未闭合注释、行内标题、三种 Unicode 分隔符、HTML、反斜杠、---、Todo 与围栏区域示例)都通过 bootstrap/start_goal/chat 读回。
  • pytest tests/control_plane/test_goal_handoff_mode.py tests/control_plane/test_canonical_handoff_mode.py tests/control_plane/test_shared_goal_alignment.py tests/control_plane/test_shared_goal_alignment_cli.py tests/cli_commands -q201 passed, 4 errors;4 个 error 全是 [sqlite] 的 canonical authority fixture 在本机 Node 25.5.0 / SQLite 3.51.2 未资格化下报错,base aff69fd92 上同一用例失败信息完全一致,属环境而非本 PR。
  • legacy 兼容反事实:我用 base 实现生成旧格式文档(普通/含引号/含反斜杠/含 U+0085/含 HTML),再喂给 head 的 _registration_state_matches 与 head 的新渲染比较,五种形态全部 legacy_accepted=True 且新渲染幂等,说明"旧文档不改写即可重注册"这条要求真的成立。
  • 公开 smoke:examples/loopx-chat-server-smoke.pyexamples/project/project-agent-adoption-smoke.pyexamples/control_plane/todo-cli-smoke.py 在 head 上全部 ok。

次要项(P3,非阻塞):loopx/claude_goal_mode/scripts/goalmode_cmd.py:136 仍用私有正则读 frontmatter 的 objective 并只 strip('"')。对需要 JSON 转义的 objective,它会返回带转义序列的字符串,例如目标 Compare "quoted" text and A<U+0085>B. 时该处返回 Compare \"quoted\" text and A\u0085B.,而同一文档经 parse_state_frontmatter 返回原文——同一份文档出现两种读回结果,正是本 PR 在别处消掉的那类漂移。建议该处改用共享解码器或对以引号开头的值走 json.loads。另外 Objective 正文现在会对 HTML 元字符做转义,除 chat 展示外若有直接打印该段的消费者会看到 &amp;,协议文档已把这条写成展示边界,但未在宿主端逐个复验。

我的整体评价

APPROVE。方案落在正确的边界上下文,编码/解码成对,两个生产入口共用一个 owner,chat_server 的私有扫描器被删除而不是叠加,仓库净结果是更少的段扫描实现。上一轮要求的两条 P2 都已落实:active_state_section_text 复用既有 active_state_sections;legacy 判定按解码后的 metadata 值加正文精确匹配,并且我用 base 生成的旧文档做了五种形态的兼容反事实,全部被接受且新渲染幂等,同时内容变化仍会报冲突。测试覆盖从围栏、行内标题、Unicode 分隔符到 HTML 与反斜杠,且 Todo 侧断言走 parse_todo_source 而非比对渲染文本,因此边界是被行为而非文本钉住的。剩余只有一条 P3:Claude goal-mode 的读取路径尚未复用共享解码器。

English verdict: APPROVE — reviewed exact head 6c83dec. The objective is now encoded by one shared pair (JSON single-line frontmatter string with escaped U+0085/U+2028/U+2029, and per-line blockquote with HTML escaping) and read back by one shared decoder that composes the existing section scanner, so objective prose can no longer open document structure or swallow Todo regions; the private chat scanner is deleted rather than duplicated. The previous review's two P2s are resolved: the section reader reuses active_state_sections, and legacy registration compares decoded metadata values plus the exact narrative, which I verified against base-generated legacy documents for plain, quoted, backslash, U+0085 and HTML objectives (all accepted, new render idempotent, changed content still conflicts). Validation at this head: 107 focused tests passed (14 objective shapes), 201 passed with 4 inherited sqlite/Node-25 environment errors that fail identically at base, and three public smokes ok. One P3: the Claude goal-mode reader still bypasses the shared decoder and can show JSON escape sequences for the same document.

@huangruiteng

Copy link
Copy Markdown
Collaborator

Authorized maintainer self-merge

Exact reviewed head: 6c83dec7147601bd2559565163632db25a66137a. The maintainer explicitly requested direct self-merge after the companion refactor and self-review.

  • All current-head checks are complete and successful (normal skipped publication/presentation jobs are accounted for). No failed or pending checks and no unresolved review threads.
  • Full exact-head review: APPROVE; the policy-revision-3 structured result passed its consistency check.
  • Exact-head validation: 437 tests, real CLI baseline/head counterexamples, configured static checks, quality receipt cqr_11d2633d637f3d03a36f, and canary 4 direct + 18 selected checks, all passed.
  • Current main a0b5bcbbacf0b0a08c7a9debe5981db5b5dc77f8 adds only the separate Turn advisory-owner extraction relative to the reviewed base. The actual combined tree 65090c1cc0c0273f054fce5e7cd4e234fffcb93f was materialized without conflicts and separately passed 437 tests, the same four real CLI cases, quality receipt cqr_0e8a4ca3d37e2ce10d64, and 4 direct + 18 canary checks. No failures, skipped required checks, or manual holds.
  • Changed surfaces: Goal document producers, shared metadata/section presentation, Chat context, registration compatibility, focused regressions and bilingual RFC/protocol notes. No provider/authority transaction, optional activation, frontend asset or permission change. Existing malformed documents remain outside automatic repair.

Governance readback: CLI merge-readiness remains ready=false for GitHub's independent-last-push approval and strict branch-up-to-date policies. The public exact-head approval is valid, but the maintainer also pushed the amended commits. This result is not relabeled green. The maintainer's explicit direct self-merge instruction authorizes admin bypass of those policy conditions; technical checks and the actual current-main integration tree have passed. No repository protection rule is edited.

The merge preserves the original contributor's commits and the maintainer's bounded refactor. All branch commits and the merge body carry DCO sign-offs. Future-facing consolidation is complete at the shared presentation owner; broader TS/whole-Goal authority migration remains separate RFC work.

@huangruiteng
huangruiteng merged commit 6fccb53 into loopx-project:main Sep 15, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Fenced goal text hides generated Todo sections

2 participants