Skip to content

docs(semantics): say what produces every cross_runtime value - #4662

Merged
huangruiteng merged 5 commits into
loopx-project:mainfrom
songoow:codex/cross-runtime-value-notes
Sep 18, 2026
Merged

huangruiteng merged 5 commits into
loopx-project:mainfrom
songoow:codex/cross-runtime-value-notes

Conversation

@songoow

@songoow songoow commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

What this is

Track A of #4447: per-value meaning for the 20 cross_runtime vocabularies.

The kernel tier was documented by #4625 (the four canonical Turn vocabularies) and #4626 (effective_action, lease_action). The cross_runtime tier was not, so its values were bare tokens whose meaning a reader had to recover from the generated rule table.

Coverage: 68/149 values → 149/149. The 81 added here are the whole cross_runtime tier.

A correction to the issue's count

The issue describes this remainder as "117 values". That count predates #4626: 117 is everything #4625 did not cover, which then still included effective_action (32) and lease_action (4) — both kernel-tier and already documented. 149 - 32 = 117, and 81 + 32 + 4 = 117. The work actually outstanding was 81 values across 20 vocabularies. The registry is the measurement, not the issue text.

The bar a note has to meet

A note says which condition produces the value — what has to be true at runtime for the code to choose it.

Not a restatement of the identifier, and not only the disposition that follows. Disposition-only was the failure mode of the three sets of notes that existed at M0, and it is why a reader still had to reconstruct control flow from the rule table. A note that merely rephrases its own name is worse than an empty one, because the coverage count then claims the value is covered.

Values I could not establish a meaning for — 2 of 81

Neither is guessed at; both say so and name the missing evidence, per the RFC's evidence rules.

  • settlement_failure_kind.cancelled — declared in both owner modules (effect_program.py:190, effect_program.ts:116) and admitted by the decoders, but selected by no branch under loopx/. Searching the literal, the enum member form and member-value reads finds only the two definition sites; every other occurrence of the token belongs to an unrelated vocabulary (chat proposal status, subagent execution status, CI conclusions), and the only settlement-shaped uses are tests that fabricate it to check a failure is not erased. It carries no compatibility_only declaration marking it reserved. Missing evidence: a producing branch, or a compatibility_only declaration. Because cross_runtime declares no producers and sits outside F2 liveness, a dead value here is not caught by the drift smoke — whether this is reserved or actually dead is an open question for a maintainer.
  • todo_decision_scope_kind.other — an accepted member with no producer and no fallback: a kind outside the set is rejected, not coerced to other, so it is not a code-level catch-all. Missing evidence: any spec, schema description or authoring rule saying when an author should choose it. The protocol reference lists it in the enum without a definition; the catalogue gloss defines only the other six kinds.

A boundary the notes now state rather than hide

Several cross_runtime values are author-declared and only membership-validated, never selected by a branch: all four goal_amendment_class values, all of todo_decision_scope_kind and todo_decision_scope_granularity, and delivery_outcome.primary_goal_outcome. Their notes name who declares the value, the criterion, where that criterion is normative, and state plainly that no code branch selects it. This is a real property of the tier and the reason it declares no producers and sits outside F1/F2.

The ratchet

New file tests/architecture/test_cross_runtime_value_notes.py — deliberately not appended to the tail of test_semantic_vocabulary_drift.py, where the kernel ratchet lives and where three open PRs already collide; a shared tail is where a same-diff rule gets lost in a merge.

It derives its population from the registry, so a new cross_runtime vocabulary is covered without editing the test. It fails on: a value with no note, an empty/whitespace note, a note carrying no words beyond its own identifier, and an Unresolved: marker that does not name its missing evidence. The unresolved count is pinned at 2 so "unresolved" cannot become the cheap default, and a further test fails if a vocabulary is ever registered under a tier neither ratchet walks.

Both failure paths are exercised directly rather than only asserted green on a clean tree. Mutation-checked: adding an undocumented value fails 2 tests; replacing a note with "The outcome is surface only." fails the restatement test.

What it does not check, stated in the module docstring so a green run is not misread: it catches mechanical restatement, not a fluent disposition-only note, and it cannot verify a stated condition is true or still matches the code. Those remain review obligations.

RFC pair

Appendix A ledger entry and Appendix B decision row dated 2026-09-17 in both semantic-vocabulary-convergence-v0.md and its .zh-CN.md mirror.

Validation

All four run on the final HEAD, working tree clean.

Check Result
python3 examples/semantic-vocabulary-drift-smoke.py semantic-vocabulary-drift-smoke: ok — exit 0
python3 examples/docs-governance-smoke.py docs-governance-smoke ok — exit 0
pytest tests/architecture/ -q 400 passed in 118.54s — exit 0
loopx canary premerge --from-git-diff status: passed, merge_gate_passed: true, selected=11 failures=0 — exit 0

Premerge detail: direct checks 4/4 passed; catalog canaries 2/2 (control-plane-maintainability-ratchet-smoke, semantic-vocabulary-drift-smoke); risk-profile smokes 8/8; public boundary 1/1 over all four changed paths.

One note for anyone reproducing: an earlier premerge run reported failed_tracked_side_effect on two smokes. That was my own concurrent edit to a tracked file while the gate was running, not a defect — the gate detects tracked-file mutation during a run and restores it. Re-run on a quiescent tree, it is clean.

Refs #4447

🤖 Generated with Claude Code

songoow and others added 2 commits September 17, 2026 10:21
The kernel tier gained per-value meaning in loopx-project#4625 and loopx-project#4626; the 20
cross_runtime vocabularies did not, so 81 of 149 registered values were
bare tokens whose meaning a reader had to recover from the generated
rule table. Per-value coverage moves from 68/149 to 149/149.

A note says which condition produces the value: what has to be true at
runtime for the code to choose it. Not a restatement of the identifier,
and not only the disposition that follows -- that was the failure mode of
the three sets of notes M0 started with.

Two values could not be established and say so rather than guess.
settlement_failure_kind.cancelled is declared in both owners and admitted
by the decoders but selected by no branch under loopx/, exercised only by
tests that fabricate it, with no compatibility_only declaration marking it
reserved. todo_decision_scope_kind.other is an accepted member with no
producer and no fallback -- a kind outside the set is rejected, not
coerced to it -- and no documented rule for when an author picks it. Both
name the missing evidence.

The notes also state a boundary the registry previously left implicit:
several cross_runtime values are author-declared and only
membership-validated, never selected by a branch. That is the whole of
goal_amendment_class, todo_decision_scope_kind,
todo_decision_scope_granularity, and delivery_outcome.primary_goal_outcome.
Their notes name who declares the value, the criterion, where that
criterion is normative, and that no code branch selects it.

The ratchet is a new file rather than an addition to the tail of
test_semantic_vocabulary_drift.py, where the kernel ratchet lives and
where open branches already collide. It derives its population from the
registry, so a new cross_runtime vocabulary is covered without editing the
test, and it fails a missing note, an empty note, a note carrying no words
beyond its own identifier, and an unresolved marker that does not name its
missing evidence. The unresolved count is pinned at 2.

The tracking issue called this remainder 117 values; that count predates
loopx-project#4626 and included effective_action (32) and lease_action (4), both
kernel-tier and already documented. The outstanding work was 81.

Refs loopx-project#4447

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: song <22676124+songoow@users.noreply.github.com>
The module docstring named the bar a note must meet and then implied the
restatement test enforces it. It does not: it catches a note built only out
of its own identifier, and cannot catch a fluent disposition-only note or
tell whether a stated condition still matches the code. Say so, so a green
run is not read as certifying the prose.

Refs huangruiteng#4447

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: song <22676124+songoow@users.noreply.github.com>
huangruiteng
huangruiteng previously approved these changes Sep 17, 2026

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

Reviewed exact head: 96c7c4b1d0883048336c3c0c6a07326a3d0ab603 (base main @ 440b002fb, merge base unchanged since 2026-09-17T14:32:02Z).

动机

这是 #4447 Track A 的剩余部分。RFC 的 per-value 覆盖在前两个切片里做到了 kernel 层(#4625 四个 Turn 词表,#4626 effective_action、lease_action),但 cross_runtime 层(20 个词表、81 个值)只是裸 token:读者要理解一个值的含义,只能从生成的规则表倒推控制流。

更实际的问题是这个缺口当时不可见。覆盖率计数停在层边界上,所以"这一层还没写"和"这一层已经写好"在仓库里长得一样;下一次有人给某个 cross_runtime 词表加一个值,没有任何 diff 需要解释它来自哪里。

改动思路

作者把"一个 note 到底要说什么"讲清楚了:哪个运行条件为真时代码会选中这个值。既不是重述标识符,也不是只记录后果。对确实无法从代码建立产生条件的值,允许的诚实答案是 RFC 证据规则里那种写法——Unresolved: … Missing evidence: …,并且把它做成可计数的形式,配一个 pin(UNRESOLVED_BUDGET = 2)防止"未解"变成廉价的默认答案。

然后他把这条义务做成了一个从 registry 推导总体的 ratchet,而不是把 20 个词表名手写进测试——手写清单恰好是这个文件要防的失败模式(新词表落在清单外,整层看起来仍然被覆盖)。文件被刻意放在新位置而不是追加在 kernel ratchet 的尾部,理由写在 diff 里:那条尾部同时被若干开放分支修改,而"同一 diff 里的规则"正是一次合并最容易丢掉的东西。

具体改动

loopx/semantics/vocabulary_v0.json(+141/-20):给 20 个 cross_runtime 词表补上 value_notes,覆盖全部 81 个值。没有新增/删除/改名任何值、owner、tier 或 producer。我逐项复核了计数:26 个词表、149 个值、68 个 kernel(原本已有)、81 个 cross_runtime(本次新增)、未解 2 个(settlement_failure_kind.cancelled、todo_decision_scope_kind.other),与 RFC 账本里的数字逐一对上。

tests/architecture/test_cross_runtime_value_notes.py(新增 252 行):8 个测试。总体从 tier == "cross_runtime" 推导;registry 通过 smoke 自己的 load_registry() 读取(不引入第二个 JSON 读者);检查 note 存在、非空白、不是对自身标识符的重述、Unresolved: 必须带 Missing evidence:,并用 <= 与 slack == 0 双向夹住 UNRESOLVED_BUDGET;另有一条断言没有任何词表落在两个 ratchet 都不走的第三层。文件 docstring 主动写明了这个 ratchet 的边界:它抓得住重述,抓不住"流畅但只写后果"的 note,也不能证明 note 为真。

两份 RFC 镜像(+58 与 +43):附录 A 新增执行账本条目(含 68/149→149/149 的覆盖率、117 与 81 的计数差异说明、未解两项的具体依据、以及"note 只查实质不查真伪"的未解决项),附录 B 增加一行决策记录,写清被拒绝的三个替代方案及理由。

对主干的风险

运行时风险为零:value_notes 是可选注释,没有任何运行时代码读取它做判断。真正的风险是"文档变成不可信的权威",所以我按最坏情况验证:

  1. ratchet 是否真的会在真实 registry 上咬人,而不只是在自己的深拷贝上。我在审阅 worktree 内给 delivery_outcome.values 加了一个没有 note 的 zz_probe_undocumented,test_every_cross_runtime_value_carries_a_note[delivery_outcome] 与 test_a_note_must_not_merely_restate_its_own_value[delivery_outcome] 立刻变红并指名该值,其余 63 条仍绿;随后 git checkout 还原,git status 干净。
  2. prose 里的强事实主张。作者明确写下 settlement_failure_kind.cancelled "declared in both owners and admitted by the decoders, selected by no branch"。我按定义站点做了一次定向搜索:cancelled 只出现在 loopx/control_plane/effect_program.py::SettlementFailureKind.CANCELLED 与 loopx/control_plane/effect_program.ts 的 SETTLEMENT_FAILURE_KINDS 这两处(即 registry 声明的两个 owner),其他同 token 的命中都属于 benchmark 运行状态、Lark 初始化状态、chat proposal 状态、subagent 状态等别的词表。delivery_outcome.primary_goal_outcome 同样只有边界校验、没有选择分支。两条主张都成立。
  3. 回归面。smoke 在改后打印 ok,覆盖率与 formal_domain 与改前逐字相同(只有注释数从 68 变 149);tests/architecture 全量 400 passed(86.36s),新文件 65 passed。

非阻塞的两点:

  • P3:MIN_NOTE_CHARACTERS = 40 / MIN_INFORMATIVE_WORDS = 6 是散文启发式,方向不对称:它可靠地抓住"重述标识符",但一条流畅地只写处置结果的 note 仍然通过(作者已在 docstring 中承认这一点),同时一条合法但极简的 note 可能被字数下限拒绝。误判方向是红不是绿,所以代价是改动噪声而不是放行错误。
  • P3:note 的真伪仍只能靠 review。这一层没有 producer 扫描可以对账,代码移动后 note 可能失真而无人发现;RFC 账本把这条明确列为 "Not addressed here",并与 kernel 层的 F1/F2 域界一起披露。这属于已声明的残留,不是本次要关的缺口。

我的整体评价

APPROVE。这是一个把"覆盖率"从口号变成可执行义务的切片:总体由 registry 推导、未解状态可计数且被 pin 住、边界与局限写在被测文件自己的 docstring 和 RFC 账本里。数值我都独立数过一遍,强事实主张抽检两条全部成立,负向路径在真实 registry 上复现成功。

和同批的 #4661 一样,这是 #4447 声明链上的一个独立切片,不是同形状重复提交。

English verdict: APPROVE - PR #4662 at head 96c7c4b; per-value producing conditions for all 81 cross_runtime values plus a registry-derived ratchet with a pinned unresolved budget (2), validated locally (65 passed for the new file, 400 passed for tests/architecture, drift smoke unchanged) and independently reproduced by adding an undocumented value to the real registry, with two spot-checked factual claims (cancelled, primary_goal_outcome) confirmed against the code.

@huangruiteng

Copy link
Copy Markdown
Collaborator

Merge-readiness qualification — #4662 @ 96c7c4b1d0883048336c3c0c6a07326a3d0ab603

结果:not ready,一项阻塞,且原因已经具体化。

loopx pr-review --repo huangruiteng/loopx --check-merge-readiness 4662@96c7c4b1d0883048336c3c0c6a07326a3d0ab603
→ ready=false
  blocking_reasons: merge_state_requires_update
  merge_state: DIRTY
  review_decision: APPROVED
  checks: 27/27 success(含必需检查 Sign-off、merge-gate)
  authority: grants_merge_authority=false,
             admin_bypass_overrides_this_gate=false

merge_state_requires_update 来自 ruleset protect main 的 strict_required_status_checks_policy: true(head 必须包含 main 的最新提交)。这里它不是"落后几个提交",而是内容冲突,冲突位置可以用本地试合直接看到:

git merge-tree --write-tree origin/main origin/pr-4662
→ CONFLICT (content): docs/architecture/rfcs/semantic-vocabulary-convergence-v0.md
→ CONFLICT (content): docs/architecture/rfcs/semantic-vocabulary-convergence-v0.zh-CN.md

冲突只有这两个文件、且都在同一份 RFC 的附录 A 区域:本 PR 的开单时间是 14:32Z,而 main 在 15:20Z 合入了 #4661——同一个文档、同一段落。代码文件不冲突(loopx/semantics/vocabulary_v0.json 与新增测试都能干净合并)。

需要谁做什么

  1. 由作者(或维护者)把 main 合入/变基到本分支,按当前 main 的附录 A 顺序合并两条账本记录(两条 B0/B5 之外的记录都保留,不要只留一边),并同步两份镜像。
  2. 更新分支会推入新 commit,dismiss_stale_reviews_on_push: true 会废止现有审批,因此需要对新 head 重新评审并重跑合并门;本 head 上的评审结论对旧 head 仍然有效,请勿把它当作新 head 的结论。
  3. 若由维护者推入这次更新,require_last_push_approval: true 会让该次审批不计入(test(manager-context): guard receiver isolation and successive requests #4640 正是这种情形),所以这次更新最好由作者完成。

本轮做了什么、没做什么

  • 读取了该 exact head 的审批状态、检查结论与 review thread 摘要,运行了上面的合并门命令,并用 git merge-tree 定位了冲突文件。
  • 没有合并,也没有使用 admin bypass(门返回 admin_bypass_overrides_this_gate=false)。
  • 对该 head 的代码评审结论(APPROVE,27/27 检查通过)未改变;阻塞只在文档合入这一步。

English verdict: APPROVE - PR #4662 at head 96c7c4b; the review conclusion and all 27 checks are green at this exact head, and merge readiness is blocked only by merge_state_requires_update because the just-merged #4661 edited the same two RFC mirrors (code files merge cleanly), so the author should update the branch and the gate must be re-run at the new head.

@huangruiteng

Copy link
Copy Markdown
Collaborator

Rebase guidance (the conflict is mechanical, no content is in dispute):

git merge-tree against current main conflicts in exactly two files — docs/architecture/rfcs/semantic-vocabulary-convergence-v0.md and its .zh-CN.md mirror. I reproduced the merge locally: both sides insert a new ledger entry at the same anchor, the head of ## Appendix A: Execution ledger (non-normative) (conflict starts at line 1126 on the English side).

Resolution: keep both sections and delete only the markers. Main's entry is ### 2026-09-17 — Formula, role and enforcement claims separated; formal signature mutated; this PR's is ### 2026-09-17 — Per-value meaning for the cross_runtime tier. Neither depends on the other's text, and the ledger is explicitly non-normative, so no check can be affected by the order you pick. Do the same in the zh mirror at its matching anchor and the branch becomes mergeable.

This is the only thing standing between this head and mergeable: the review conclusion on 96c7c4b1d0883048336c3c0c6a07326a3d0ab603 is valid and the only readiness blocker is merge_state_requires_update.

songoow and others added 2 commits September 17, 2026 21:08
…alue-notes

Both conflicts are append clusters at the top of Appendix A with no
overlapping content: this branch's `cross_runtime` per-value ledger entry
and main's B0 formal-signature entry. Both are kept in both mirrors, newest
first, and no evidence row ids are added on either side.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: song <22676124+songoow@users.noreply.github.com>
Review on loopx-project#4662 found the cross_runtime note ratchet enforcing two things
no test can establish from the data, both of which push the next author the
wrong way.

`MIN_NOTE_CHARACTERS`/`MIN_INFORMATIVE_WORDS`, with the `STOPWORDS` set and
`_informative_words()`, claimed to catch a note that only restates its own
identifier. A word count cannot show that a note names the producing
condition; what it reliably changes is to reward padding, and a fluent note
that records only the disposition passed it anyway.

`UNRESOLVED_BUDGET` capped how many values may say the condition is
unresolved. A budget on honesty buys its smaller count by pressuring the next
author to invent a producing condition rather than record that the evidence is
missing, which is the outcome the RFC's evidence rules exist to prevent. The
count is still readable from the registry; it is no longer a gate.

What remains is what the data settles: every registered value has a
`value_notes` entry, a blank entry does not count as one, an `unresolved:`
entry names its missing evidence, the two tier ratchets together cover every
registered vocabulary, and the parametrized population is derived from the
registry. The module docstring now states that bar instead of the old one:
whether a note is true and still matches the code is a review obligation, not
something a green run certifies.

None of the 81 notes change. Both RFC mirrors are updated to describe what is
enforced now, and the two removed gates are recorded in Appendix B as
alternatives rejected under review.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: song <22676124+songoow@users.noreply.github.com>

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

动机

RFC 第 5 节要求 cross_runtime 这一层的每个值都说明"什么条件会产生它"。原有棘轮到 kernel 层就停了,于是这 20 个词表可以新增一个没有任何 diff 解释的值——覆盖面从 68/149 到 149/149 就是这次补上的缺口。

新 head(4d7480a2)在此前审批之后做了两件事:把 main 合进分支解掉 rebase 冲突,并删掉两条"测试判不了"的闸门。这两条删除是这次复审的重点,我按"是否削弱了可执行护栏"逐条核过。

改动思路

  • 补文档:为每个 cross_runtime 值写"产生条件",写进 vocabulary_v0.json 的 value_notes,并新增独立测试文件承载义务——刻意不追加到 kernel 棘轮的尾部,因为已有三个分支在同一处改,同 diff 规则最容易在那种位置被 merge 吃掉。
  • 删闸门:删掉 MIN_NOTE_CHARACTERS + MIN_INFORMATIVE_WORDS(含 STOPWORDS/_informative_words)与 UNRESOLVED_BUDGET。理由站得住:字数与非停用词计数无法证明一条 note 是否说了产生条件,它可靠改变的行为是奖励灌水;而"未解析数量上限"是从另一侧施压,逼下一个作者去编造产生条件而不是老实记录缺证据——正好是 RFC 证据规则要防的结果。
  • 留下能判的:每个登记值有非空 note、空白不算覆盖、Unresolved: 必须点名缺失证据、两层棘轮合起来覆盖所有登记词表、参数化总体来自注册表。

具体改动

关键代码讲解

  • tests/architecture/test_cross_runtime_value_notes.py::test_every_cross_runtime_value_carries_a_note:覆盖面义务本身没变;参数化总体从注册表派生,所以新增词表自动纳入。
  • ...::test_an_unresolved_note_must_name_the_missing_evidence:删掉预算上限后,它成为对 unresolved 的唯一约束——必须点名"缺什么证据",所以删除上限并没有留下"耸肩式"逃生口。实测注册表 149 条 note 里只有 2 条 unresolved(cancelled、other),且都点名了缺失证据。
  • ... 模块 docstring:重写为"这个文件到底强制什么、什么仍属 review 义务",不再声称字数检查能机械识别同义复述。
  • RFC 附录 B(EN/zh-CN 两份同改):把两条被删闸门登记为"review 下被拒绝的替代方案",保留决策痕迹。

对主干的风险

无阻塞发现。一条 P3 记录:上限删掉后,没有地方汇报 unresolved 数量了(现状可从注册表读到 2/149,drift smoke 只报层级边界 cross_runtime_unverified=20/20)。建议可选地在层级边界旁打印 unresolved 计数,让未来的跳变不必打开注册表才看得见。

边界如实说:棘轮不能判定 note 是否真实、是否仍与代码一致,这一条现在写在文件 docstring 和 RFC 里,而不是靠绿灯暗示。删掉的那条字数闸门在删除前的 docstring 里本来就自认"比目标更窄、只能机械抓同义复述",所以这次是收回一个自认不达标的规则,而不是放松已成立的护栏。

验证(本 head 4d7480a2):pytest tests/architecture/test_cross_runtime_value_notes.py -q → 44 passed;examples/semantic-vocabulary-drift-smoke.py 正常打印层级边界;docs-governance-smoke ok;仓库检查 14 项全绿(含 Sign-off、merge-gate、pytest、kernel-static-checks、四个 test-shard、dashboard-acceptance),EN/zh-CN 标题数 46/46 对齐。

我的整体评价

这是"把不可执行的口径换成可执行的口径"的正例:删掉的两条规则一条靠字数、一条靠计数上限,都不能证明它们声称的东西,反而各自诱导错误行为;留下来的是数据能判定的部分,而"note 是否真实"被显式标为 review 义务。文档、commit message、RFC 三处口径一致,删除理由有据可查。可以接受。

English verdict: APPROVE - head 4d7480a documents every cross_runtime value's producing condition (149/149) and drops only the two note gates no test can decide (word-count restatement check, unresolved cap), each recorded as a rejected alternative in RFC Appendix B of both languages; the enforceable bar survives (presence, blank rejection, unresolved must name missing evidence, tier coverage from the registry), validated by 44 passing tests, the drift smoke, docs-governance and 14 green repository checks including all four test shards, with one non-blocking P3 note that the unresolved count is no longer reported anywhere.

@huangruiteng
huangruiteng merged commit 11b857d into loopx-project:main Sep 18, 2026
4 of 5 checks passed
songoow added a commit to songoow/loopx that referenced this pull request Sep 18, 2026
…dence

Both mirrors conflicted on the Appendix A append cluster: this branch's entry
for the two corrected measurements against main's entry for the cross_runtime
value notes (huangruiteng#4662). Disjoint additions, so both are kept, ours first. The only
line this branch removes from main's version of each mirror is the F5 sentence
it deliberately rewrites.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: song <22676124+songoow@users.noreply.github.com>
songoow added a commit to songoow/loopx that referenced this pull request Sep 18, 2026
Both mirrors conflicted on the Appendix A append cluster: this branch's ledger
entry against main's entry for the cross_runtime value notes, which landed with
huangruiteng#4662. The two are disjoint additions, so both are kept, ours first. Nothing
from main's version of either mirror was dropped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: song <22676124+songoow@users.noreply.github.com>
songoow added a commit to songoow/loopx that referenced this pull request Sep 18, 2026
Both mirrors conflicted on the Appendix A append cluster: this branch's ledger
entry against main's entry for the cross_runtime value notes, which landed with
huangruiteng#4662. The two are disjoint additions, so both are kept, ours first. Nothing
from main's version of either mirror was dropped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: song <22676124+songoow@users.noreply.github.com>

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

审阅对象:PR #4662(已合并),exact head c33105fdcf7dfa2df860076a8dac7a9a02a0b260(作者 songoow),2026-09-18T02:53:26Z 合并为 11b857dec2962ca4a7c65e5aa199cbb9b9526637。本文是该 exact head 的 post-merge audit。

动机

loopx/semantics/vocabulary_v0.json 登记了全部词表与取值,但只有 kernel 层(#4625 的四个规范 Turn 词表、#4626 的 effective_action 与 lease_action)写了逐值备注;20 个 cross_runtime 词表、81 个取值是裸 token。读者想知道"什么条件产生这个值",只能回到生成的规则表反推控制流;而任何新增 cross_runtime 取值的 diff 都可以完全不解释自己。按注册表实测,改动前逐值覆盖是 149 个中的 68 个。

改动思路

这是一次只补文档层、不动语义层的改动:给现有 81 个取值逐个写明产生条件(不新增、不删除、不重划任何取值、层级或 owner),把这条义务棘轮化,并在产生条件确实无法确定时如实写明"未解析 + 缺失什么证据",而不是编一个听起来合理的说法。棘轮没有追加到 test_semantic_vocabulary_drift.py 的 kernel 棘轮末尾,而是单独一个文件——RFC 决策表把原因记下来了:那个文件尾部已有多个未合分支在冲突,而"同一 diff 内才有意义"的规则正是合并时最容易丢掉的东西。评审期间初版还带了两道闸门(字符下限+非停用词计数、把 unresolved 数量上限钉在 2),二次修改把它们删掉了:词数无法证明一条备注写出了产生条件,只会奖励灌水;给诚实设上限则会逼下一位作者编造条件。删掉后测试只断言它真能从注册表判定的东西。

具体改动

4 个文件、+430/-20:loopx/semantics/vocabulary_v0.json 为 20 个 cross_runtime 词表补 value_notes(+141/-20,其中两个是 Unresolved: … Missing evidence: …:settlement_failure_kind.cancelled 在第 596 行、todo_decision_scope_kind.other 在第 900 行);新增 tests/architecture/test_cross_runtime_value_notes.py(+174),义务是"每个取值必须有备注、空白备注不算、unresolved 必须点名缺失证据",另有一条测试要求任何词表都不得落在两个棘轮都不走的层级;RFC 中英两版各补账本条目与决策行(英文第 1126 行、中文第 909 行)。

我在 exact head 上做了以下验证:pytest tests/architecture/test_cross_runtime_value_notes.py tests/architecture/test_semantic_vocabulary_drift.py tests/architecture/test_semantic_inventory.py -q → 162 passed;用 drift smoke 自己的 load_registry() 量注册表 → 20 个 cross_runtime 词表 / 81 个取值 / 81 条备注 / 2 条 unresolved,与账本里"68/149 → 149/149"和"117 是 #4626 合并前的旧计数,实际待办 81"的写法一致。备注可被证伪的部分我另外抽验了两条:cancelled 在全树只有两个定义点(loopx/control_plane/effect_program.py:190、effect_program.ts:116),loopx/ 下确实没有任何分支选它,只有测试伪造它——与备注"no branch selects it"一致;budget_rejected 与 quota_spend_rejected 确实只靠自由文本子串区分,effect_program.ts:863 就是 if (reason.toLowerCase().includes("budget")) return "budget_rejected";,与备注的写法逐字对应。棘轮本身的失败路径也在同一测试文件里被直接演练(新增无备注取值、空白备注、unresolved 缺 marker)。

对主干的风险

无运行时、权限、配额、调度或持久状态影响:改的是注册表数据+一个架构测试+双语 RFC 文本,回滚即回退四个文件。真正的残留风险是该改动自己就写明的那一条:备注是散文,仓库里没有任何机制检查它为真、也不检查它在代码移动后是否仍然成立;cross_runtime 层不声明 producers,因此也没有 producer 扫描可比对。其次是两条被如实保留下来的空缺——settlement_failure_kind.cancelled 究竟是"保留值"还是死值,以及 todo_decision_scope_kind.other 何时该被作者选用,二者都缺文档或兼容性声明;它们不是本 PR 引入的问题,本 PR 的价值恰在于把它们写进了注册表而不是掩掉。另一条与本次 diff 无关但需要点名的分类风险:budget_rejected/quota_spend_rejected 仍依赖自由文本子串判定,没有结构化预算信号,该值域在跨运行时层又没有 producer 存活检查。

过程上还有两条观察,一并记下:该 head 上原有的 APPROVED review(id 5243430793)在 capability 自己的校验器里是无效的——review_body_missing_standalone_bilingual_format,正文只绑定了更早的 head 串且只有四个必需标题,所以本文补上该 exact head 的有效记录;该 head 的 Sign-off 检查是 failure,但原因在 head 提交本身:c33105fdc 是维护者本地把 main 合回分支时生成的 merge commit,没有 DCO trailer,而分支上两个 authored commit(4d7480a2f、80d161476)都是签了名的,合入 main 的提交是 11b857dec。其余 26 个 check 在该 head 上均成功。

我的整体评价

结论 APPROVE。这是"把已经登记的语义真正说明白"的一次完整交付:81/81 覆盖、单独棘轮、双语账本与决策行齐全,且在评审中减法优于加法——两道无法判定其所声称内容的闸门被移除,测试退回到只断言它能断言的部分。真正值得保留的是它把两处空缺写成 Unresolved: … Missing evidence: … 而不是编一个产生条件,以及把"作者声明、仅做成员校验"这一层的真实性质写明,而不是让这些值继续看起来像有生产者。改动的边界也画得干净:不新增不变量、不改任何检查结论、value_notes 明确非规范。残留风险只有一条且由 PR 自己披露——备注的真伪与新鲜度仍归评审。

语义与 CI 对齐

这次改动影响的是共享语义契约的文档层,因此按契约记一条对齐结论:判定为 extend_vocabulary(扩展既有词表契约),受影响契约是 loopx/semantics/vocabulary_v0.json 的 cross_runtime 层 value_notes(schema_version、取值集合、层级与 owner 均未变)、新增的 tests/architecture/test_cross_runtime_value_notes.py,以及 RFC 的附录 A/附录 B 两份语言版本(英文 1126 行、中文 909 行)。注册表测量与测试都在 exact head 上取得,量出的 81/81 与账本数据一致;CI 侧该 head 除上述 DCO merge-commit 问题外全部通过,且 kernel-static-checks、merge-gate、pytest 与四个 test shard 均为 success。需要一并转给层级 owner 的两条后继(非本 PR 阻塞项):cancelled 需要给出产生分支或 compatibility_only 声明;结算路径的自由文本 budget 子串判定应换成结构化信号。

English verdict: APPROVE - Audit of merged exact head c33105f of PR #4662 ("docs(semantics): say what produces every cross_runtime value", author songoow, merged as 11b857d). The change documents all 81 values of the 20 cross_runtime vocabularies with the runtime condition that produces each one, ratchets that obligation in a separate architecture test, and states "Unresolved: ... Missing evidence: ..." where no producing condition exists instead of guessing. I measured the registry at the exact head through the drift smoke's own loader (20 vocabularies, 81 values, 81 notes, exactly 2 unresolved) and ran the three architecture modules (162 passed). I independently falsified two sample notes against the code: settlement_failure_kind.cancelled has exactly two definition sites and no selecting branch under loopx/, and budget_rejected vs quota_spend_rejected are separated only by the free-text substring test at effect_program.ts:863, exactly as the notes claim. Two gates the first revision carried (a character floor with a non-stopword word count, and a cap on unresolved values) were removed under review because neither can decide what it claimed, which is the right direction. Risk is confined to prose correctness, which the PR itself discloses as unverifiable in-repository; the two Unresolved values remain named follow-ups for the tier owner. Two process observations: the head's prior APPROVED review fails the capability's own validator (four of five headings, body bound to an earlier head string), so this audit supplies the valid exact-head record; and the head's Sign-off check failed only because c33105f is a maintainer-created merge of main into the branch without a DCO trailer, while both authored commits are signed and the merge into main is 11b857d.

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