chore(semantics): lock two inventory ratchets and disclose budget slack - #4629
Conversation
conflicting_values 18->16 and conflicting_definitions 59->55 pin the measured values loopx-project#4499 earned; both sides of each budget move in this one diff so the equality anchor holds. multi_value_twins stays 19 here: the multi-value single-source batch (loopx-project#4617) owns that counter and locks it to 13. The inventory report line now discloses unlocked headroom (slack=key=N). The guard only fails on overflow, so a merge that reverts a tightened budget (registry and anchor move back together, the merge-trap shape) used to pass silently; now the reopened headroom is visible in the smoke output and in the PR diff of any run after it. Signed-off-by: song <liusongstep@gmail.com>
…ratchets Signed-off-by: song <22676124+songoow@users.noreply.github.com>
本 PR 在 #4447 计划中的位置issue #4447 现在有一节统一协调(中英双语),把这 13 个在开 PR 作为一个计划列出:各自修什么、为何必要、以及实测出的合并顺序。 冲突实测:对全部 78 对做了试合并,9 对冲突,分四簇,每一处都是文本相邻,没有一处是语义分歧。
建议顺序(代价从低到高):#4628 → #4625、#4626 → #4627 → #4619、#4621 → #4630 → #4614 → #4631 → #4629 → #4617 → #4606 → #4608。四个棘轮 PR 放最后,因为每落地一个,下一个的数字就从估算变成确定值。 全部 13 个 PR 现已同步到 |
…ratchets loopx-project#4606 and loopx-project#4617 merged while this branch was open, and both sides tightened ratchets in the same two anchored blocks. Resolved by taking the tighter side of each, the only resolution budgets_only_decrease allows: - same_runtime_forks 25 -> 20 and same_runtime_fork_definitions 58 -> 47 from main (loopx-project#4606 single-sourced six status constants). - conflicting_values 18 -> 16 and conflicting_definitions 59 -> 55 from this branch, which is what it exists to lock. multi_value_twins takes main's 13 from loopx-project#4617, which is tighter than the 19 this branch left in place for exactly that reason. Registry and BUDGET_ANCHOR carry the same values, as the equality check requires. Measured after the merge: every counter this branch owns is at budget, conflicting_values=16/16 and conflicting_definitions=55/55. Signed-off-by: song <22676124+songoow@users.noreply.github.com>
exact-head 复核(
|
| 锚点 | 本分支 | main 来源 | 解析 |
|---|---|---|---|
same_runtime_forks |
25 | 20(#4606 单源化六个 status 常量) | 取 20 |
same_runtime_fork_definitions |
58 | 47(同上) | 取 47 |
conflicting_values |
16 | 18 | 取 16(本分支存在的意义) |
conflicting_definitions |
55 | 59 | 取 55 |
multi_value_twins |
19 | 13(#4617) | 取 13 |
最后一行值得说明:本分支当初故意把 multi_value_twins 留在 19,并在 PR 描述里写明"归 #4617 所有,它能降到 13,比本分支能做的更紧"。现在 #4617 已合并,于是按当时的约定取它的 13。
registry 与 BUDGET_ANCHOR 同值(该检查是相等)。合并后实测:本分支负责的两个计数器 conflicting_values=16/16、conflicting_definitions=55/55,均恰好压线。合并提交带 DCO 签名。
…ratchets loopx-project#4608 merged after the previous sync, lowering the same anchored block again. Resolved by taking the tighter side of each, as budgets_only_decrease requires: - same_runtime_forks 20 -> 18 and same_runtime_fork_definitions 47 -> 41 from main. - conflicting_values 16 and conflicting_definitions 55 from this branch, which is what it exists to lock. Measured after the merge: conflicting_values=16/16 and conflicting_definitions=55/55, both exactly at budget. Signed-off-by: song <22676124+songoow@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Reviewed exact head: 0a858ba3c59e56cc59c44ef0e1a0c5c620193daf (codex/lock-inventory-ratchets).
动机
#4447 里两个 inventory ratchet 落在测量值以下四格:conflicting_values 实测 16 却挂着 18 的预算、conflicting_definitions 实测 55 挂着 59。守卫只在超支时失败,所以把预算改回去的那种合并是「静默通过」——而 registry 与 BUDGET_ANCHOR 会一起回退,等值 anchor 依然满足。改动后两个预算锁到实测值,并且报告行会把任何残留余量作为 slack= 打出来。
改动思路
入口是 examples/semantic-vocabulary-drift-smoke.py::check_inventory:预算改动同时落在注册表与代码 anchor 两侧(这是仓库等值 anchor 的既有要求),报告侧只是把「预算 − 实测」这个派生量加进同一行。没有新机制、没有新命令,唯一新增的语义是「余量要被看见,但不构成失败」——这是对的,因为 multi_value_twins 的那 1 格余量属于另一个批次(#4617),把 slack 断言成 0 反而会误伤。
具体改动
3 个文件、+44/-5:BUDGET_ANCHOR 与注册表 inventory_ratchets 各两处(18→16、59→55),check_inventory 约 10 行 slack 汇总,测试约 31 行。
我在这个 head 上跑了 smoke → ok,且 conflicting_values=16/16 conflicting_definitions=55/55(其余计数不变);pytest tests/architecture/test_semantic_vocabulary_drift.py -q → 62 passed。我另外手工复现了 slack 路径:把一个注册表副本的 conflicting_values 抬到 18、同时把 anchor 改成同值(即「两文件一起回退」的合并陷阱形状),报告行确实输出 slack=conflicting_values=2;而在未改动的 head 上输出里没有 slack= 片段。顺带确认新测试的 monkeypatch.setitem(smoke["BUDGET_ANCHOR"], ...) 是有效的(runpy 复制的是 globals 映射,但 dict 对象是共享的,所以 setitem 是活的)。
关键代码讲解
BUDGET_ANCHOR(smoke 147):两个值锁到 16/55;注册表同步,所以等值 anchor 仍成立(smoke 输出即证明)。check_inventory的 slack 段(695 附近):遍历RATCHET_KEYS,budget > measured时累加f"{key}={ratchets[key] - actual}"并在非空时把slack=...追加到报告行;注释明确「守卫只在超支时失败,余量不失败」,所以这是披露而非门禁。test_inventory_report_discloses_budget_slack:钉住两个方向——当前锁定值不产生 slack 片段;两文件同时回退必须产生slack=conflicting_values=2。
对主干的风险
最强回归不是崩溃,而是「锁被合并流程悄悄撤掉」。改动本身把这类回退从「静默」变成「下一轮输出里可见」,方向正确;但它仍是建议性的:忽略这一行的人不会比以前更差,所以真正阻止回退的还是「冲突必须逐行解,不能整块取一侧」这条 reviewer 纪律。
一条 P3(F1,非阻塞):这次 diff 把 loopx/semantics/vocabulary_v0.json 的行尾换行删掉了(diff 里是 -} / +} 加 \ No newline at end of file)。我核过字节:本 head 的文件不以换行结尾,而 merge-base 的同一文件以换行结尾(脚本自身也仍有)。对 json.loads 无影响,但会在此后每次改动这个文件的 diff 里留下噪音,也会被会在末尾补换行的编辑器/格式化工具反复改写。最小修复:补回一个字节。
我的整体评价
结论 APPROVE。改动小但切中真实失效模式:预算未锁 + 等值 anchor 一起回退 = 静默重开债务;现在锁上了,并且把余量披露出来(multi_value_twins 留给 #4617 的那 1 格也因此可见)。我独立复现了 16/16、55/55 与 slack 路径,跑了 62 个测试,并确认没有其他地方仍引用旧预算值。回退成本是一个 commit。
唯一 P3 是文件末尾换行被删,非阻塞。
English verdict: APPROVE - exact head 0a858ba; the two ratchets are locked to their measured values in both copies (smoke prints conflicting_values=16/16 and conflicting_definitions=55/55), the new slack disclosure reproduces when a budget and its anchor are reverted together (I saw slack=conflicting_values=2) and does not appear on the shipped head, no remaining doc cites the old budgets, and 62 architecture tests pass. One non-blocking P3: the diff removes the trailing newline from loopx/semantics/vocabulary_v0.json, which the merge-base copy has.
Same append-at-end cluster as loopx-project#4631: loopx-project#4625 and loopx-project#4626 landed their blocks at the end of test_semantic_vocabulary_drift.py while this branch appends the ratchet-lock fixtures. Both blocks kept, theirs first. The locked values still hold on the integrated tree: conflicting_values 16/16 and conflicting_definitions 55/55, so no anchor moves in this merge. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: song <22676124+songoow@users.noreply.github.com>
|
Head moved: merged Same append-at-end cluster as #4631: #4625 and #4626 landed their blocks at the end of The point worth re-checking is that the locked values still hold on the integrated tree: Revalidated: Per the exact-head rule in |
huangruiteng
left a comment
There was a problem hiding this comment.
Reviewed exact head: 6f06f77bd62e031f268a2e9838a0d3fa365bb47f (codex/lock-inventory-ratchets, re-review after the previous head 0a858ba3c was superseded by a main merge).
动机
未变:conflicting_values 与 conflicting_definitions 两个 inventory ratchet 挂在比实测值高四格的预算上(实测 16 / 55,预算却写 18 / 59),而守卫只在超支时失败。所以「整块取一侧」的冲突解法会把收紧过的锁悄悄撤掉——registry 与 BUDGET_ANCHOR 一起回退,等值 anchor 仍然成立,16 > 18 也不为真,于是 smoke 依旧绿。这个动机在本次 head 上仍然成立。
改动思路
两件事一起做:把两个预算钉到实测值(registry 与 BUDGET_ANCHOR 同步改,等值 anchor 不破),并在既有的报告行构造里加一段条件性 slack 披露——只要某个预算高于实测值就打印 slack=<key>=<delta>。这样「回退锁」这种解不再是静默的,而是在下一次运行的同一行里露出来,不需要新增模块或二级报告。
具体改动
3 个文件、+44/-5(相对当前 main;本次 head 相对上一次 review 只多了 main 合并,内容增量未变):
loopx/semantics/vocabulary_v0.json:conflicting_values18→16、conflicting_definitions59→55。examples/semantic-vocabulary-drift-smoke.py:BUDGET_ANCHOR同步为 16/55;check_inventory的报告行在预算大于实测值时追加slack=...。tests/architecture/test_semantic_vocabulary_drift.py:新增test_inventory_report_discloses_budget_slack,双向断言——钉住的预算不产生 slack;把预算回调 2(merger-trap 形状)必须披露slack=conflicting_values=2。
我复核的关键点(都在这个 head 上自己跑过):
python examples/semantic-vocabulary-drift-smoke.py→ exit 0,报告行conflicting_values=16/16 conflicting_definitions=55/55,本 head 没有 slack 段。pytest -q tests/architecture/test_semantic_vocabulary_drift.py→ 68 passed。- 反向验证(PR 的核心主张):我在 scratch 副本里把 registry 与
BUDGET_ANCHOR的conflicting_values一起改回 18,重跑 smoke 仍是绿的(conflicting_values=16/18),但报告行多出slack=conflicting_values=2。这正面复现了「整块取一侧 → 静默回退」的解法被转成可见信号。探针已还原,git status --short干净。 - 与当前 main 逐键比对:
conflicting_valuesmain 18 / head 16,conflicting_definitionsmain 59 / head 55;multi_value_twins与same_runtime_forks两边一致(13 / 18),说明这个 head 只动了它声明要动的两个键。
遗留问题(非阻塞,P3)
两条,都是文案/字节层面的:
loopx/semantics/vocabulary_v0.json仍缺行尾换行(我上一轮就提过,本次 head 未修)。实测本 head 文件末字节是0x7d(}),而 main 的同文件末字节是0x0a,所以 diff 里仍有\ No newline at end of file。对json.loads无影响,但会让此后每次改这个文件的 diff 都带噪音,也会被补行尾的编辑器反复改写。最小修复:补一个字节。- PR body 里的 slack 例子在当前 head 已不复现。body 说 slack 行只显示「为后续 PR 留的 1 个单位」(
slack=multi_value_twins=1);本 head 的 smoke 完全没有 slack 段——main 后来把那个单位也锁上了(multi_value_twins在 main 与 head 都是 13/13)。披露路径本身没坏:两文件回调后仍能打印slack=conflicting_values=2。这只是引文过期,不是行为缺陷。
对主干的风险
最强回归不是崩溃,而是「锁被合并流程悄悄撤掉」。这次改动把回退从「静默」变成「下一轮可见」,方向正确;但它依旧只是建议性的:整块取一侧的人仍会合并成功,只是输出里多一行。真正硬性的护栏还是「冲突必须逐行解」这条 reviewer 纪律。除此之外:不涉及运行时路径、quota 规则或持久化状态;读侧也没有新增 schema 或键;回退成本是一个 commit。我这次没有只继承上一轮的结论——head 换了(main 合并),所以我重新对当前 main 比对了内容增量、重跑了 smoke 与 68 个测试,并亲手复现了 merger-trap 的反例。
我的整体评价
结论 APPROVE。改动很小但落在对的地方:预算锁到实测值,披露放在已经在做同一比较的那个函数里,双向测试把 merge-trap 形状固定下来。我在新 head 上独立复现了「钉住即无 slack」和「两文件回调即 slack=conflicting_values=2 且仍绿」,并确认相对当前 main 的内容增量与 PR 声明一致。两条 P3 都不阻塞:一个缺行尾换行,一处 body 引文过期。
English verdict: APPROVE - exact head 6f06f77 (re-review after a main merge; content delta versus current main is the same 3 files, +44/-5). The two ratchets are locked to their measured values in both the registry and BUDGET_ANCHOR (16/55), the drift smoke exits 0 and prints conflicting_values=16/16 conflicting_definitions=55/55 with no slack segment at this head, 68 architecture tests pass, and I reproduced the merge-trap case first-hand: reverting both copies to 18 keeps the run green while the new disclosure prints slack=conflicting_values=2. Two non-blocking P3 findings: loopx/semantics/vocabulary_v0.json still lacks its trailing newline, and the body's slack=multi_value_twins=1 example no longer reproduces because main has since closed that last unit.
Five more tracker PRs landed, three of them in files this branch edits. - loopx-project#4629 and loopx-project#4631 both append to `test_semantic_vocabulary_drift.py`; all fifteen of their blocks are kept beside this branch's three. - Appendix A gains loopx-project#4631's invariant-domain entry in the same 2026-09-17 date as this branch's B3 entry, so newest-first keeps both. - Appendix C is a real collision, not textual adjacency: loopx-project#4631 took E21, E22 and E23. This branch's evidence row is renumbered E24 and its baseline SHA refreshed to `001c6daf2`. Remeasured on the integrated tree: every role count is unchanged (`goal_boundary` surface 15 of 30 carriers, `protocol_action_packet` one reader and four writers), `dynamic_mapping_key_sites` stays 1712, and all six migration-surface anchors hold. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: song <22676124+songoow@users.noreply.github.com>
What
Lock two inventory ratchets to their measured values:
conflicting_values18→16,conflicting_definitions59→55. Both sides of each budget (registry andBUDGET_ANCHOR) move in this one diff, so the equality anchor holds. These are the values feat(semantics): generate shared Turn contracts and controller rules (M2) #4499 earned; until now they sat 4 units below their budgets with nothing checking the gap.Disclose budget slack in the inventory report line:
slack=key=Nwheneverbudget > measured. The guard only fails on overflow (measured > budget), so a merge that reverts a tightened budget used to pass silently; now the reopened headroom is visible in the smoke output.multi_value_twinsstays 19 here — the multi-value single-source batch (refactor(semantics): single-source five duplicated multi-value vocabularies #4617) owns that counter and locks it to 13, which is tighter than this branch could.Why the slack line exists (merge-trap reproduction)
Merging two budget-tightening branches straddles the budget hunk:
A whole-hunk resolution in either direction silently reverts one side's lock and the smoke stays green — both files revert together, so the equality anchor stays satisfied, and
16 > 18is false so the overflow check never fires. Reproduced live: take-theirs on this branch merged with #4606 yieldsokwithconflicting_values=16/18. With the slack line, that same resolution printsslack=conflicting_values=2,conflicting_definitions=4in the diff of any post-merge run.Merge-order note for reviewers
This branch textually conflicts with #4617 / #4606 / #4608 on the budget lines. The resolution is line-by-line (take theirs' fork budgets, keep this branch's 16/55), never a whole-hunk take. The slack line added here is what makes a wrong resolution visible.
Validation
python3.11 examples/semantic-vocabulary-drift-smoke.py— green:conflicting_values=16/16 conflicting_definitions=55/55, slack line shows only the 1 unit intentionally left for refactor(semantics): single-source five duplicated multi-value vocabularies #4617 (slack=multi_value_twins=1)python3.11 -m pytest -q tests/architecture/test_semantic_vocabulary_drift.py— 59 passed (58 pre-existing + the new slack-disclosure test)test_inventory_report_discloses_budget_slackcovers both directions: pinned budgets disclose no slack; a two-file budget revert (the merge-trap shape) must discloseslack=conflicting_values=2