Skip to content

docs(catalog): add IP-032 completed-work archive with durable decision retention - #4438

Merged
huangruiteng merged 1 commit into
loopx-project:mainfrom
YZJF:codex/gh-c37-archive-retention-pattern
Sep 16, 2026
Merged

huangruiteng merged 1 commit into
loopx-project:mainfrom
YZJF:codex/gh-c37-archive-retention-pattern

Conversation

@YZJF

@YZJF YZJF commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

What this adds

GH-C37 asks for one new public-safe catalog case. This adds IP-032
Completed Work Archive With Durable Decision Retention
, a P1 State And
Boundary pattern.

+127/-1 across two files: docs/concepts/interaction-pattern-catalog.md and
examples/interaction-pattern-catalog-smoke.py.

Changes since last review (REQUEST_CHANGES at 81561c0)

  • Renumbered IP-030 → IP-032. The previous head allocated IP-030, which
    already denotes Machine Configuration Preview And Revision-Guarded Apply
    (and main has since taken IP-031 as Manager Context Is Not Turn
    Authority
    ). The entry is now IP-032, the next free id on current main
    (f4ed58de9), updated in all four places: table row, detail heading,
    Pattern-To-Canary matrix row, and the smoke expectation strings.
  • Rebased onto main f4ed58de9. The previous head conflicted with main in
    exactly this file; the branch is now main + one commit, mergeable=CLEAN.
  • Added the requested machine check for catalog structure.
    interaction-pattern-catalog-smoke.py now also verifies, data-driven over
    the catalog: (a) every pattern id owns exactly one | P<n> | IP-0nn | table
    row; (b) every table row has its #### IP-0nn detail heading and vice
    versa; (c) no id is listed under more than one family in the
    Pattern-To-Canary matrix; (d) every matrix id has a pattern row. The
    original IP-030 collision now fails three of these assertions.

Why this is a real gap and not a duplicate

loopx todo archive-completed encodes three interaction rules that no
catalog entry explains
:

  1. Retention — a done todo carrying a durable standing decision is not a
    move candidate. The payload reports retained_standing_decision_count, and
    the decision must still resolve as active standing authority
    (standing_decision_authority_v0) after the move.
  2. Role scope — the archive only touches the section for the requested role.
    --role user must leave Agent Todo untouched. The role defaults to
    agent
    , so a caller who means the user lane has to say so.
  3. Preview — without --execute it is a dry run that must not change the
    state file.

Grepping the catalog for archive, standing decision, or retention returns
only paths under docs/archive/incidents/. No IP owns this behavior.

The entry explicitly separates itself from the nearest neighbors so it does not
become a second source of truth:

  • IP-020 owns claim / supersede / successor lifecycle;
  • IP-014 owns how a decision is written;
  • neither owns what happens to a durable decision once the todo carrying it
    leaves the active window
    . That is the gap.

This is the catalog maintenance rule "a smoke encodes a behavior that is not
yet explained to humans"
: todo-archive-completed-smoke.py and
todo-standing-decision-authority-smoke.py already encode the behavior, but
nothing names it.

Changes

  • Catalog table — IP-032 row under State And Boundary (P1).
  • Pattern details — full entry: Trigger, Expected behavior, Mermaid visual
    model, Bad smell, Validation.
  • Pattern-To-Canary matrix — IP-032 joins the State And Boundary coverage
    list, and completed-work archive joins that family's trigger surfaces, so
    the matrix does not drift the way docs(catalog): align pattern details order with the catalog table #4324 had to fix.
  • Catalog smoke — five snippets pin the new entry, plus the new
    structural id-uniqueness / family-membership / detail-pairing assertions.

Validation

  • python3 examples/interaction-pattern-catalog-smoke.py -> ok (now also
    enforcing the structural assertions above)
  • python3 examples/canary/catalog-planner-smoke.py -> ok
  • python3 examples/docs-governance-smoke.py -> ok
  • loopx check --scan-path docs/concepts/interaction-pattern-catalog.md (the
    validation GH-C37 names) -> ok: True, errors=0, public boundary scan clean
  • py_compile on the touched smoke; git diff --check clean
  • ruff: only the three pre-existing findings on this file (EXE001, I001,
    RUF100), byte-identical on main's version — nothing new introduced

Mutation check: duplicating the IP-032 table row, listing IP-032 under a
second family, and renaming the IP-032 detail heading each make the catalog
smoke fail with the corresponding structural assertion message, so the new
checks bind rather than passing vacuously.

Honest gap

Role isolation is currently only proven at helper level. The entry marks the
CLI-level assertion (--role user leaves Agent Todo byte-identical) as
future smoke rather than claiming coverage it does not have — per the
maintenance rule "mark it as a future smoke rather than hiding the gap". A
separate open PR of mine (#4436) proposes that CLI-level assertion; if it lands
first, I will update the Validation section to point at it.

Scope and boundary

@YZJF
YZJF requested a review from huangruiteng as a code owner September 15, 2026 09:32

@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.

动机

GH-C37 要求补一个 public-safe 的 catalog case,而"done todo 被归档之后,它携带的 durable standing decision 归谁管"这件事确实没有任何 catalog 条目解释:claim/supersede/successor 归 IP-020、decision 怎么写归 IP-014,谁都不管"离开活跃窗口之后"。所以新增一个 pattern 的方向是对的,条目正文(retention / role scope / preview 三条,以及和 IP-020、IP-014 的边界说明)我也读不出重复。

但这个 PR 选用的 id 是已经被占用的 IP-030,而且 head 与当前 main 在同一文件冲突,这两件必须先收口。

改动思路

在 catalog 的 State And Boundary 族新增一行 IP-030 Completed Work Archive With Durable Decision Retention,正文补一个完整条目(Trigger / Expected behavior / Mermaid / Bad smell / Validation),Pattern-To-Canary 矩阵里把该 id 加进 State And Boundary 并把 completed-work archive 加进触发面,然后在 examples/interaction-pattern-catalog-smoke.py 的期望列表里补五条字面断言把新条目钉住。

具体改动

  • docs/concepts/interaction-pattern-catalog.md(+86/-1):第 91 行矩阵 State And Boundary 行、第 343 行新增 pattern 行、第 2155 行新增 #### IP-030 … 详情段。
  • examples/interaction-pattern-catalog-smoke.py(+5):新增五条期望字符串(pattern 行文本、Archive is a storage move, not a decision loss.、retained_standing_decision_count、The role defaults to \agent``、owning smoke 路径)。

关键代码讲解

  1. 第 343 行 | P1 | IP-030 | Completed Work Archive With Durable Decision Retention |:这是新分配的 id,但 main 上第 323 行的 IP-030 已经是 Machine Configuration Preview And Revision-Guarded Apply(详情段在第 1192 行),也就是说同一个 id 现在指向两个不同 pattern。
  2. 第 91 行矩阵:State And Boundary 行新增 IP-030,而第 90 行 Human Decision 行本来就含 IP-030(Machine Configuration Preview 属于该族),于是矩阵里同一个 id 同时挂在两个族下——id 的"身份"语义被破坏。
  3. interaction-pattern-catalog-smoke.py:104-110:新增断言全是"子串是否存在",所以它能抓文本漂移(我用把行 id 改成 IP-999 的变异验证过,确实会失败),但抓不到 id 冲突或族归属错误,这正是这次问题静默通过的原因。

对主干的风险

阻塞项 1(P1,pattern id 重复)。我在 head 上跑 git show HEAD:docs/concepts/interaction-pattern-catalog.md | rg -o '^\| P[0-9] \| (IP-0[0-9][0-9]) ' -r '$1' | sort | uniq -d → 输出 IP-030;对照三个版本:merge base 6bb413105 的 id 空间是 IP-001..IP-030(那时 IP-030 就已经被占用,下一个空闲是 IP-031),origin/main 19a69abd6 已经到 IP-001..IP-031(IP-031 = Manager Context Is Not Turn Authority,它的行与详情段也占用了第 343/2155 行附近的位置)。最小修复:把新 pattern 改成下一个空闲 id——按当前 main 是 IP-032——并同步改第 343 行表格、第 2155 行详情标题、第 91 行矩阵行、以及 smoke 里那条 IP-030 | Completed Work Archive … 期望串。

阻塞项 2(P1,head 与 main 冲突)。git merge-tree --write-tree HEAD origin/main 返回 1,冲突就在 docs/concepts/interaction-pattern-catalog.md(mergeable=CONFLICTING、mergeStateStatus=DIRTY,对照 origin/main 19a69abd6)。main 侧新增的 IP-031 行/矩阵项与本次插入位置重叠,所以请 rebase 到当前 main 后再确认一遍 id 分配(rebase 之后 IP-031 也被占,新条目应为 IP-032),并在新 head 上重跑 interaction-pattern-catalog-smoke.py、examples/canary/catalog-planner-smoke.py、examples/docs-governance-smoke.py 与 loopx check --scan-path docs/concepts/interaction-pattern-catalog.md。

P2(catalog 结构没有机器检查)。本 head 的四项验证我都跑过且全绿(catalog smoke ok、catalog-canary-planner-smoke ok、docs-governance-smoke ok、boundary scan clean,变异探测也如 PR 所述会失败),但它们无法表达"id 唯一、且只属于一个族"。建议保留新增的字面断言,另加一条数据驱动检查:遍历 | P<n> | IP-0nn | 行断言 id 唯一、矩阵里每个 id 只出现一次、且每个表格行都有对应详情标题。这条检查在本次 head 上就会失败,正好补上缺口。

我的整体评价

REQUEST_CHANGES。条目本身是这次改动里最有价值的部分:archive-retention 这个语义空白真实存在,正文把 retention / role scope(--role 默认 agent)/ preview 三条讲清楚,并主动与 IP-020、IP-014 划清边界,验证命令我逐条跑过都通过。问题集中在 id 分配这一处:IP-030 在本 PR 的 merge base 上就已经属于 Machine Configuration Preview And Revision-Guarded Apply,选择它会让表格、详情段与 canary 矩阵同时出现"一个 id 两个 pattern、一个 id 两个族";同时本 head 与当前 main 在同一文件冲突(merge-tree 返回 1),而 main 侧的 #4433 已把下一个空闲 id IP-031 也占掉。把新条目改成 rebase 后的下一个空闲 id(当前 main 为 IP-032)、同步四处引用、并给 catalog 结构补一条唯一性断言,然后我按新的 exact head 再做一次复审。

English verdict: REQUEST_CHANGES at 81561c0. The new pattern entry fills a real gap and its three rules (durable decision retention, role scope with the agent default, preview-then-execute) plus its explicit separation from IP-020/IP-014 read correctly; the catalog smoke, the canary planner smoke, the docs governance smoke and the public boundary scan all pass at this head, and the claimed mutation check reproduces. But the entry allocates the id IP-030, which already denotes Machine Configuration Preview And Revision-Guarded Apply at the PR's own merge base (table line 323, detail line 1192), so the catalog now has two IP-030 rows, two IP-030 detail headings, and the canary matrix lists IP-030 under both Human Decision and State And Boundary. That was already true at the base - the next free id there was IP-031 - and current main has since taken IP-031 as well, so after rebasing the new entry should become IP-032. The head is also CONFLICTING/DIRTY against origin/main 19a69ab, with the merge conflict in exactly this file and region. Please rebase, renumber the pattern in all four places (table row, detail heading, canary matrix row, smoke expectations) and add an id-uniqueness assertion so the catalog's own structure is machine-checked; I will re-review the new exact head.

@YZJF
YZJF force-pushed the codex/gh-c37-archive-retention-pattern branch from 81561c0 to 7d21fcd Compare September 16, 2026 06:38
@YZJF YZJF changed the title docs(catalog): add IP-030 completed-work archive with durable decision retention docs(catalog): add IP-032 completed-work archive with durable decision retention Sep 16, 2026
…n retention

`loopx todo archive-completed` encodes three interaction rules that no
catalog entry explains to humans:

1. a done todo carrying a durable standing decision is not a move candidate,
   and the decision must still resolve as active standing authority after
   the move (`retained_standing_decision_count`,
   `standing_decision_authority_v0`);
2. the archive only touches the section for the requested role, so
   `--role user` must leave `Agent Todo` alone while the role defaults to
   `agent`;
3. without `--execute` the command is a preview that must not change the
   state file.

Today `examples/control_plane/todo-archive-completed-smoke.py` and
`examples/control_plane/todo-standing-decision-authority-smoke.py` encode
this behavior but nothing in the catalog names it, which is exactly the
"a smoke encodes a behavior that is not yet explained to humans" case in
the catalog maintenance rules.

The entry explicitly separates itself from IP-020 (claim / supersede /
successor lifecycle) and IP-014 (how a decision is written): neither owns
what happens to a durable decision once the todo carrying it leaves the
active window.

Pattern-To-Canary matrix: IP-032 joins State And Boundary, and
"completed-work archive" joins that family's trigger surfaces.

The catalog smoke also gains a data-driven structural check: pattern ids
own exactly one table row, every row has its detail heading (and vice
versa), and no id is listed under more than one family in the
Pattern-To-Canary matrix, so an id collision like the one this entry
initially shipped cannot pass silently again.

Rebased onto main f4ed58d; the entry is numbered IP-032 because IP-030
(Machine Configuration Preview And Revision-Guarded Apply) and IP-031
(Manager Context Is Not Turn Authority) are already taken on main.

Validation:
- python3 examples/interaction-pattern-catalog-smoke.py -> ok (now also
  enforces id uniqueness / family membership / detail-heading pairing)
- python3 examples/canary/catalog-planner-smoke.py -> ok
- python3 examples/docs-governance-smoke.py -> ok
- loopx check --scan-path docs/concepts/interaction-pattern-catalog.md
  -> ok, errors=0, public boundary scan clean
- mutation check: duplicating an id or listing it under two families now
  fails the new structural assertions

Role isolation is documented as a future CLI-level smoke because it is
still helper-level only; the gap is stated rather than hidden.

Docs-only; no runtime, validation, or benchmark behavior changes.

Signed-off-by: YZJF <195568136+YZJF@users.noreply.github.com>
@YZJF
YZJF force-pushed the codex/gh-c37-archive-retention-pattern branch from 7d21fcd to aa929ac Compare September 16, 2026 06:39
@YZJF

YZJF commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

已按 review 意见完成修复,请按新的 exact head aa929ac39 复审:

  1. 阻塞项 1(id 重复):条目改为 IP-032(rebase 后 main 上 IP-030、IP-031 均已被占用),四处引用同步更新:第 344 行表格行、#### IP-032 详情标题、第 91 行 State And Boundary 矩阵行、smoke 五条期望串。
  2. 阻塞项 2(与 main 冲突):已 rebase 到当前 main 75fcd5556,现在 head = main + 一个提交,mergeable=CLEAN。
  3. P2(结构无机器检查):interaction-pattern-catalog-smoke.py 新增 require_catalog_structure 数据驱动断言:id 唯一、每个表格行有对应详情标题(反之亦然)、矩阵中每个 id 只属于一个族、矩阵 id 必须有表格行。变异验证:复制 IP-032 行、把 IP-032 挂到第二个族、改详情标题,分别被三条断言拦截。

新 head 上重跑全部验证:catalog smoke ok、catalog-canary-planner-smoke ok、docs-governance-smoke ok、loopx check --scan-path ok/errors=0/boundary clean、py_compile + git diff --check 干净;ruff 仅剩 main 上就存在的三条(EXE001/I001/RUF100),本次未新增。

@YZJF

YZJF commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

关于当前 CI 全红的情况,我(作者)逐项核实过,这些失败都不是本 PR 引入的,而是 main 自带的,说明如下:

  1. 本 PR 只改动两个文件:docs/concepts/interaction-pattern-catalog.md 和 examples/interaction-pattern-catalog-smoke.py(git diff 75fcd55 pr4438 确认),loopx/ 内核源码与 base 提交 75fcd55 完全一致。
  2. test-shard (1) 唯一失败的测试是 tests/test_loopx_turn_journal_inspection.py::test_inspect_journal_cli_branches_before_live_or_write_paths,报 loopx.cli_commands.turn 缺少 build_lark_operator_inbox_urgency_projector。我在 base 提交 75fcd55(不含本 PR 改动)上本地复现了完全相同的失败——这是 main 上已经坏了的测试,与本 PR 无关。
  3. kernel-static-checks 是 mypy 报的 1051 个类型错误,全部位于 roundtrip.py、executor.py、dogfood.py 等 PR 未触碰的内核文件。由于 PR 不改任何被检查的源码,该 job 在 base 上也会产生同样结果。
  4. checks / pytest / merge-gate 三个 job 的日志里只有 test "$KERNEL_RESULT" = success 和 test "$SHARDS_RESULT" = success,是上游门禁因 2、3 失败而连带失败,并非独立失败。

另外 main 分支自己最近的 CI 也有 failure 记录(67c8c6c 的 run 失败、75fcd55 的 run 被 cancel),说明主干 CI 目前本身不健康。

本 PR 自身的验证在 head aa929ac39 上全部通过:catalog smoke、catalog-canary-planner-smoke、docs-governance-smoke 均 ok,目录无重复 id(IP-032 在 main 上仍空闲),与最新 origin/main merge-tree 无冲突(GitHub 显示 BEHIND 只是 main 又前进了,不是冲突)。建议在主干侧修复 build_lark_operator_inbox_urgency_projector 缺失和 mypy 错误后重跑 CI,本 PR 无需为这些红做任何改动。

@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.

动机

上一轮我在 81561c00 上给了 REQUEST_CHANGES,三个问题都在这一版收口了:id 重复、与 main 冲突、catalog 结构没有机器检查。

条目本身要解决的空白是真实的:loopx todo archive-completed 已经带着一套明确语义(durable standing decision 的保留、--role 的作用域、preview-then-execute),但 catalog 里没有条目认领它——IP-020 管 claim/supersede/successor,IP-014 管决策怎么写,谁都不管"承载决策的 todo 离开活跃窗口之后"。缺少这条,agent 整理活跃 lane 时很容易把已完成工作当成可丢弃历史,于是两个 turn 之后重新去问一个用户已经回答过、或者重新翻烧一条已批准的策略。

这一版把新条目放在 State And Boundary 族,并明确写出它与 IP-020、IP-014 的边界,方向和我上一轮的判断一致。

改动思路

三处修复分别是:条目改号为 IP-032(当前 main 的 catalog id 空间到 IP-031,IP-032 是下一个空闲号);head 重基于 75fcd5556,与当前 origin/main(36c6d8df0)合并干净;interaction-pattern-catalog-smoke.py 里新增数据驱动的结构断言,把"id 唯一、一个 id 只属于一个族、表格行与详情标题配对"从人工 review 变成会失败的检查。

条目正文保持上一版的四段结构(Trigger / Expected behavior / Visual Model / Bad smell / Validation),把 retention、role scope、preview 三条规则逐条绑定到实际命令与 payload 字段,并保留对下游 smoke 的归属。

具体改动

  • docs/concepts/interaction-pattern-catalog.md(+86/-1):第 91 行 State And Boundary 矩阵行加入 IP-032,触发面补 completed-work archive;第 344 行新增 pattern 行;第 2259 行起新增 #### IP-032 详情段(84 行,含 mermaid 流程与 Validation 归属)。
  • examples/interaction-pattern-catalog-smoke.py(+41):新增 require_catalog_structure(第 34 行),第 206 行调用;第 141 行起补五条字面断言(pattern 行文本、Archive is a storage move, not a decision loss.、retained_standing_decision_count、The role defaults to `agent`、owning smoke 路径)。

关键代码讲解

  1. docs/concepts/interaction-pattern-catalog.md:344 — | P1 | IP-032 | Completed Work Archive With Durable Decision Retention | Archive selector plus controller | no interruption; preview-then-execute readback | ... |:表格行的 id、owner、中断语义与一句话规则齐全,IP-032 在当前 main 上确实是空闲号(我按 rg -o '^\| P[0-9] \| (IP-[0-9]{3}) \|' 在 origin/main 上取到的最大号是 IP-031)。
  2. docs/concepts/interaction-pattern-catalog.md:91 — State And Boundary 行现在同时把 IP-032 放进族覆盖和触发面(completed-work archive),因此该 pattern 会进入该族的 project/boundary canary 覆盖,而不再只存在于详情段里。
  3. docs/concepts/interaction-pattern-catalog.md:2259 — #### IP-032 Completed Work Archive With Durable Decision Retention:详情段把三条规则写成可核对的行为承诺,并且逐条能对上实现:--role 在 CLI 帮助里写明 archive-completed 默认 agent(loopx/cli_commands/todo_registration.py:57)、retained_standing_decision_count 由 loopx/control_plane/todos/completed_archive.py 产生并在 examples/control_plane/todo-archive-completed-smoke.py:202 被断言、<!-- loopx:todo role={role} --> 标记在 loopx/control_plane/todos/completed_archive.py:151。最后一段还写了 IP-020/IP-014 的边界。
  4. examples/interaction-pattern-catalog-smoke.py:34 — require_catalog_structure:用四条断言把结构规则机器化——表格 id 不可重复、每个表格行都要有详情标题、详情标题不能是孤儿、矩阵里每个 id 只能挂在一个族下且必须存在于表格中。它不是格式检查的堆砌:loopx/canary/planner.py 的 _catalog_pattern_rows 会把重复 id 直接喂进 coverage audit(同一 id 两行会被重复计数而不是报错),所以这条规则此前确实没有 owner。
  5. examples/interaction-pattern-catalog-smoke.py:206 — require_catalog_structure(catalog, source=CATALOG):挂在这个已有的 catalog smoke 上,该 smoke 被 examples/run-smokes.py 收录进 .github/workflows/full-public-smokes.yml 的每日全量 public smoke 扫(含 main push),并由 smoke-fleet-health 汇总 receipt,因此这条断言会持续跑而不是一次性脚本。

对主干的风险

我上一轮提的两个阻塞项都已关闭,且我独立复验过。 id 唯一性:head 上 rg 表格行 id 无重复,id 空间为 IP-001..IP-032;合并冲突:git merge-tree --write-tree HEAD origin/main 退出码 0(对照 origin/main 36c6d8df0),head 的 merge base 是 75fcd5556,即一个可 fast-forward 语义的增补分支。

P2(非阻断,文档准确性):第 2339 行 - Future smoke: role isolation is currently proven at helper level; a CLI-level assertion that --role user leaves Agent Todo byte-identical is proposed and not yet landed. 与本 head 的事实相反。这条 CLI 级断言已经落地:examples/control_plane/todo-archive-completed-smoke.py:147 的 assert_user_role_archive_retains_standing_decision(在 :469 被调用)用 --role user 跑真实 CLI,断言普通 done gate 被归档、todo_user_standing_approve 保留,并在 :219-227 明确检查 "compacting the user section must not move Agent Todo work"(todo_agent_completed 仍在、done_count == 1、位置在 ## Completed Work Archive 之前)。该断言随 #4436 进入 main,而本 head 基于其之后的 75fcd5556,所以这句话在同一个 head 上是自相矛盾的。风险不是运行时,而是 catalog 作为权威指引会把读者引向重复劳动(再开一个 smoke PR),并错报当前覆盖。最小修复是一行:改成引用 examples/control_plane/todo-archive-completed-smoke.py 的该断言作为 role isolation 的 owner,或删掉这条 bullet。这是 P2,不阻断合并;若作者选择在同一 PR 内修掉,就会产生新 head 并触发一次完整复审,这个成本留给作者判断。

P3(非阻断,新断言的一个盲点):require_catalog_structure 的族矩阵 cell 解析用的是 ^\| [^|]+ \| ((?:IP-\d{3}, )*IP-\d{3}) \|,要求 cell 恰好是逗号分隔的 id 列表。只要有人在 id 后面加注释(IP-032 (archived-work retention)),整行的 id 会被静默跳过而不是报错。我复现了:把 IP-032 (archived-work retention) 加进 Human Decision 行,smoke 输出 interaction-pattern-catalog-smoke: ok;而不带注释的同一重复会按设计失败(pattern ids listed under more than one family: ['IP-032'])。也就是说这条新规则的保证是"针对当前格式"而非"针对该语义"。最小修复是把 cell 解析换成 re.findall(r'IP-\d{3}', cell) 并额外断言计数一致,这样带注释的 cell 会被报告出来。同一次验证里我还确认另外三种变异都会失败:表格 id 重复、详情标题改名(孤儿+缺标题)、矩阵里出现不存在的 id,说明这条断言不是空转。

验证面(全部在 aa929ac39 上跑):interaction-pattern-catalog-smoke ok、canary/catalog-planner-smoke ok、docs-governance-smoke ok、条目引用的 control_plane/todo-archive-completed-smoke ok 与 control_plane/todo-standing-decision-authority-smoke ok、loopx check --scan-path docs/concepts/interaction-pattern-catalog.md 报 public boundary scan clean: 1 files。按本 lane 的 review 配置我不会去拉取或等待 GitHub CI,因此上述结论只基于本地仓库验证;本地必跑项没有失败或跳过。作者在同一 head 之外声明的"CI 全红与本 PR 无关"我未复核,也不作为我的结论依据。

我的整体评价

APPROVE。这一版把上一轮的两个 P1 和一个 P2 都真正处理掉了:IP-032 在当前 main 上是空闲号且与 main 无冲突,新增的结构断言对四种结构破坏有实际杀伤力(我逐条做过变异验证),并且挂在每日全量 public smoke 上而不是一次性脚本。条目正文我没有只读一遍就放过,而是把三条规则逐条对回实现:--role 默认 agent 有 CLI 帮助背书,retained_standing_decision_count 有 payload 字段与 owning smoke 断言背书,role marker 与 Completed Work Archive 节名有代码常量背书;IP-020/IP-014 的边界划分与"archive 是存储迁移、不是决策丢失"的核心表述也都读得通。剩下的两个问题都不阻断:P2 是新增 bullet 与本 head 事实相反(一行即可修正),P3 是新断言对带注释 cell 静默跳过。二者都不改变这条 pattern 对读者的价值判断,所以我给 APPROVE,并建议经手时顺手收掉 P2。

English verdict: APPROVE — exact head aa929ac39f16bfcb31237e963c3c23cb7a362d63 of #4438. The rebased head renumbers the new pattern to IP-032 (current main tops out at IP-031), merges cleanly with origin/main 36c6d8d (git merge-tree exits 0), and adds a data-driven require_catalog_structure assertion to examples/interaction-pattern-catalog-smoke.py:34 that I verified has teeth: duplicate table id, cross-family duplicate, renamed detail heading and unknown matrix id each fail with the expected assertion, while the unmutated head passes. Independent validation at this head: catalog smoke ok, canary catalog-planner smoke ok, docs-governance-smoke ok, and the two smokes the entry cites as owners (todo-archive-completed-smoke, todo-standing-decision-authority-smoke) both ok, with loopx check --scan-path docs/concepts/interaction-pattern-catalog.md reporting a clean boundary scan. Two non-blocking findings: (P2) the new Validation bullet at docs/concepts/interaction-pattern-catalog.md:2339 still says the CLI-level --role user role-isolation assertion is "proposed and not yet landed", but that assertion already exists in the same head via #4436 (examples/control_plane/todo-archive-completed-smoke.py:147, incl. the Agent Todo must-not-move checks at :219-227); (P3) the matrix-cell regex silently skips annotated cells, so IP-032 (archived-work retention) listed under a second family passes the new check rather than failing it.

@huangruiteng
huangruiteng merged commit 822ab6d into loopx-project:main Sep 16, 2026
19 of 24 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.

2 participants