Skip to content

[Task]: Semantic vocabulary convergence follow-ups after RFC PR #4433 / 语义词表收敛后续任务 #4447

Description

@songoow

Task ID or area

area: semantics / control-plane vocabulary

Technical direction

Core control-plane hardening; Architecture and research incubator

Intent

Tracking issue for bounded semantic-convergence slices and their RFC decisions.

Summary and delivery status

Prevent silent drift in shared control-flow and protocol vocabularies while keeping routine changes reviewable. This tracker covers both repairing existing semantic debt and improving the measurements used to identify it.

Slice Delivery evidence Status at this update
M0: registry, generated inventory, PR-path drift smoke, source/scan boundaries PR #4433, merge 19a69abd6c5cb96988d884f2956a0dca54e2969e Merged
Formal-model signature, Consumer hierarchy, proof-stage metadata, bilingual roadmap PR #4453, merge 83c1f999633b Merged 2026-09-15
M0.5 action domains, scope_declarations (SOURCE_SURFACES and its four CLI owners), production evidence #4494, merge 75fcd5556c3f Merged 2026-09-16
M2 published Turn decision contract: route_projection over 8 routes, 29 controller rules, generated Python/TypeScript bindings #4499, #4571, #4580 Merged 2026-09-16
B2 producer scanner: one bound re-export hop, a recorded reason per unresolved site #4573, #4581 Merged; 19 real effective_action candidate sites remain
Track A repairs: two capability-id slots classified, shadow-findings single-sourced, semantic conflict budget lowered to its measured value #4513, #4517, #4603 Merged
Track A / B1 slices #4606, #4608, #4614, #4617 All merged 2026-09-17. Measured after: same_runtime_forks_semantic 18 -> 11, multi_value_twins 19 -> 13, same_runtime_fork_definitions 58 -> 41
Todo header markers single-sourced: the open counts now classify headings exactly as the Todo region writer does #4643 Merged 2026-09-17. Two copies of the marker tuples disagreed on 15 of 23 realistic headings; three of those were defects that suppressed a projection-gap warning
Per-value meaning for the kernel tier: all 32 Turn kernel values and all 32 effective_action values documented against the code that decides them, with a coverage ratchet #4625, #4626 Merged 2026-09-17
B3 retirement metric: five orthogonal syntactic use facts per module, replacing the substring token count #4651, merge 02cc53bd5 Merged 2026-09-18. Migration surfaces measured; it no longer gates M3
M3 per-field retirement, M1 typed slots Staged coordination below; scope proposal #4789 B3 has shipped; M3 still needs benefit/compatibility judgment. #4777 reconciles stale M1/Q3/Q6 implementation claims

This issue stays open after #4453: that PR provides a design/schema foundation, not completion of M0.5–M4. Follow-up PRs should use Refs #4447 and identify the checklist item they address; they must not close the entire tracker for a partial slice.

The merged program — what this tracker shipped

The thirteen PRs this section used to list as open are all merged. They are
kept as one record because they were reviewed as one program, and because the
merge order below was measured rather than guessed.

Track A — repay measured debt. #4606
single-sourced six status constants, #4608
imported the Todo task-class vocabulary from its owner, and
#4617 single-sourced five
multi-value vocabularies. Together with #4513
and #4517 these removed
7 forked names and 17 duplicate definitions: same_runtime_forks 25 names /
58 definitions to 18 / 41, multi_value_twins 19 to 13.

Track B — make the measurement faithful. #4614
reported the name-keyed divergence a rename hides and measured the limit it does
not close; #4630 filtered the 18
registered owner pairs out of the merge candidates; #4629
locked two ratchets to measured values; #4631
bounded each formal invariant to the domain it verifies; #4628
halved ast.parse calls per run.

Corrections found by reviewing the merged tree. #4680
fixed two measurements that contradicted themselves — reordering a set was
counted as a new fork while the adjacent divergence report correctly said the
value set had not changed, and a registered-but-unimplemented projection still
reported F5:2/2. #4682 and
#4687 closed three producer-scan
answers that were confidently wrong, each a missing value delivered inside a
complete-looking set.

Merge order, for the record. Trial-merging all 78 pairs found nine conflicts in
four clusters, every one textual adjacency rather than semantic disagreement: the
ratchet anchors (#4606/#4608/#4617/#4629), the drift test file's append cluster
(#4626/#4629/#4631), the RFC Appendix B rows (#4614/#4627/#4631), and the inventory
generator (#4614/#4630). The append-cluster conflicts recurred often enough that
#4691 removed the cause: each
ledger entry is now its own file under docs/architecture/rfcs/ledger/<rfc-slug>/.

Governed scope — the kernel tier, stated as a boundary

Measured on 092a28c4e: the tree defines 664 vocabulary carriers (107 Python
enums, 504 named closed sets, 8 Literal aliases, 45 TypeScript as const
arrays). The registry governs 26 of them — 3.9% — and 6 carry producer
evidence — 0.9%.

This tracker governs the kernel tier. It does not claim the rest, and widening
the count is not one of its goals.
Two consequences follow, both boundaries
rather than backlog:

  • A vocabulary outside the registered 26 receives no signal from this guard —
    not at commit time, and not at the moment it is coined. The guard runs as a
    full-tree scan in pytest/premerge/CI; nothing fires while a value is being
    introduced.
  • Excluding merge commits, all 23 edits to vocabulary_v0.json are by one
    author
    . No contributor has yet had to register a vocabulary because this
    check stopped them. That is consistent with a 3.9% scope, and it is why the
    remaining work below is cut rather than extended.

The separate question the maintainer raised on 2026-09-15
— how an agent notices it is coining a new term, and how it decides whether it
should — is not tracked here. It was answered in prose
and never built: AGENTS.md does not mention vocabulary governance, no skill
covers it, and the candidate_decision taxonomy the registry schema validates
(reuse_existing, extend_vocabulary, create_vocabulary, …) is used zero
times
in the registry. That work needs its own issue with its own acceptance
test; it is not a milestone of this one.

Staged delivery coordination — proposed acceptance revision, 2026-09-20

The issue stays open. PR #4789 proposes the bilingual RFC scope revision below. Until maintainers accept it, this section is a delivery proposal, not a waiver of the existing M3/F1/F2 acceptance. The previous closeout contract required a first-field retirement plus wider production evidence; the proposed contract replaces mandatory deletion with verified maintenance reduction and explicit source closure. No runtime budget or compatibility gate is relaxed.

Purpose: make changes to registered control-plane semantics fail visibly when they drift, reduce repeated maintenance in real execution paths, and make the evidence boundary honest enough for future contributors to use. PR counts, unknown counts and field-name counts are not completion metrics.

Completed foundation

Stage 1 — accept integrated guard and production-path outcomes

Owner boundaries: semantic guard/reporting, quota live composition, settlement/replay, and work-item admission. Reuse the existing PRs; do not open replacements for the same slices.

Work Observable acceptance Current delivery / gate
Honest evidence reports and RFC facts Report walked evidence rather than tautological ratios; distinguish implementation from future milestones #4772 and #4777 open; #4777 has passing checks, #4772 current-head checks pending
PR-04 live construction One final packet rendering when read hooks and capability intent both apply; complete payload/signature parity #4775 open, approved and checks passed; final integration still required
PR-07 settled replay Same settled work is not selected, constructed or spent again; identity rejection and independent capability effects remain valid #4783 open; current-head CI/review pending
PR-08 unadmitted selection Rejected/deferred choices never construct executable settlement; qualified workspace repair, exact argv and receipt identity stay valid #4788 now open; current-head CI/review pending
PR-10 inbox construction One common permission construction; reply-first ordering, distinct source action/reason and orchestration boundaries preserved #4786 open; current-head CI/review pending

Integration order: assess the correctness contract in #4764 first; its current head has failing CI, so old approval/green evidence is not merge readiness. This is an overlapping correctness dependency, not permission to stall independent work. #4772, #4777 and #4786 can proceed independently. Reconcile the shared construction chain in PR-04 → PR-07 → PR-08 order (#4775 → #4783 → #4788), incorporating #4764 only at a validated head, or explicitly proving the chosen baseline without it. Re-run affected cases after every integration. The local composition evidence already reported on #4788 is useful but does not certify an eventual merged revision.

Exit: selected changes are merged and verified together, or an unneeded slice is explicitly withdrawn with the intended invariant still satisfied. No new broad scanner work is required by this stage.

Stage 2 — close sources for the registered set in three bounded batches

Owner: the existing semantic evidence boundary together with each named runtime/decoder owner. The first runnable action is tracing the settlement/receipt batch against real producers and decoders; tracing and characterization can proceed while #4789 is reviewed. A new source-evidence schema or enforcement policy needs its own reviewed implementation.

Order Remaining entries Required result
2a — settlement and receipt (4) settlement_step_kind, settlement_failure_kind, receipt_bound_monitor_phase, receipt_bound_replay_phase Reuse the #4747 pilot shape where valid; identify actual creation/input boundaries and exercise normal, rejected and replay/identity cases
2b — workspace and Todo (7) delivery_workspace_kind, delivery_workspace_identity_kind, delivery_workspace_requirement, todo_completion_continuation, todo_completion_recovery, todo_decision_scope_kind, todo_decision_scope_granularity Preserve workspace-repair admission and Todo authority; prove source classification from actual callers rather than names
2c — remaining owners (8) Three goal_amendment_* entries, two scheduler_*_transition entries, handoff_mode, delivery_outcome, delivery_continuity_preemption Close the remaining source rows without treating generic input vocabularies as internally produced states

For every row, record the owner/slot, source classification, exact evidence, compatibility boundary and unresolved limitations. Runtime production needs a real witness; external input needs decoder positive/negative evidence; compatibility-only needs retained scope and exit conditions; local-only needs proof that it does not cross the boundary. Mixed sources must retain all obligations rather than selecting the easiest label. Labels, declaration counts and enum iteration alone are insufficient. Source closure must remain a separate claim from F1/F2 producer verification; its count must not inflate the existing production domain.

Exit: all 26 registered entries have evidence-backed source treatment, with no implicit unknown. Any exception must be named and separately accepted with an owner and concrete reason; neither missing evidence nor the existing pilot can silently stand for the whole set. Budgets and scan roots remain unchanged unless separately justified and reviewed.

Conditional migration — PR-05 / M3

protocol_action_packet retirement is proposed as conditional, not a mandatory first deletion. The trigger is demonstrated removal of duplicate authority or unnecessary consumer maintenance, plus a target version, consumer scope, historical-format/signature coverage and rollback window. Until then, retain the writer and protocol_action_packet_fields() projection. PR-04 can remove repeated rendering without removing the compatibility field. A useful derived projection is not semantic debt merely because its name is old. This does not authorize retirement of the other five fields.

Stage 3 — accept one integrated revision and close

  • Maintainers accept the revised tracker scope through docs(semantics): stage tracker acceptance around verified outcomes #4789 and reconcile docs(semantics): reconcile RFC milestones with shipped contracts #4777's factual corrections.
  • Stage 1 evidence is read back on the actual integrated revision: guards reject counterexamples; settled/rejected/qualified/inbox paths retain their intended behavior and replaced maintenance points are gone.
  • Stage 2 source treatment is reviewed for the registered set; production verification and other evidence classes are reported separately.
  • Real CLI/TypeScript bridge and isolated backend checks relevant to the integrated changes pass; failed and untested cases remain explicit. A feature/configuration change would also require its affected frontend/Lark companion validation.
  • The final issue record names the revision, commands/results, retained compatibility fields, approved exceptions and any concrete successor. Then close this tracker as the accepted stage, without claiming all long-range RFC milestones or whole-program proof.

Whole-repository vocabulary governance, stable identity for every rename, zero twins, zero unknown scanner sites, all six field deletions and general F6 persistence proof are not new closure targets. Create a successor only for a concrete required outcome; do not multiply ceremonial issues or monitors.

阶段说明(中文): 先验收现有守卫与四条生产路径的实际减负,再按 4/7/8 三批完成剩余来源证据,最后在同一集成版本验收关闭。M3 改为收益与兼容方案驱动的条件迁移;该修订由 #4789 提请评审,当前 issue 不关闭。协调复用本 issue;PR 状态由一个分组监控更新,仅在合并、失败、阻塞或需要维护者决定等实质变化时通知。

Source of truth. The merged English RFC and Chinese mirror own the design contract. #4453 merged into that pair, so the proof-stage model and the four enforcement lanes are already part of the contract on main. This issue owns delivery status, dependencies and follow-up links. Refinements below that differ from the RFC remain proposals until incorporated into both language versions; they are not maintainer approvals.

Execution strength and proof boundary

The four lanes describe different levels of evidence. In #4453, enforcement_policy is validated metadata; changing it does not implement or activate a producer/consumer analyzer.

Lane Scope What it means now
blocking_now Existing owner-set/parity checks, the registered executable projection, inventory freshness, source boundaries and anchored budgets M0 checks within their declared scan scope. F5 is the current member of this lane among the six formal obligations; the other existing checks remain active.
blocking_next F1 producer closedness, F2 producer-evidence obligation, F4 scope separation Planned bounded checks, starting with the four Turn kernel vocabularies; not implemented merely by registering these names.
advisory F3 consumer-domain analysis, interpreter/pass-through discovery and merge candidates Future evidence reports. Current --report only ranks modules mentioning symbols; it does not classify roles or prove data flow.
unproved F6 persisted-reader compatibility, complete producer discovery and behavioral equivalence Explicit evidence gaps. They cannot be reported as passed.

Roles. Owner defines the vocabulary; Producer introduces a value at a particular output/slot; Consumer reads or accepts it. Interpreter and Pass-through are Consumer subroles, not an exhaustive or mutually exclusive partition of whole modules. A transformer can consume one vocabulary and produce another. Persistence is an additional property: even a pass-through may need serializer, reader and version checks. Merely referring to an enum member is not evidence of production at a protocol boundary.

Mathematical limits to preserve in implementation:

  • Distinguish admitted values S_v from actual/runtime and observed values. Define production over an ambient value domain, then check Produced(v) ⊆ S_v; defining production as already restricted to S_v would make this obligation tautological.
  • A fixed syntax scan is evidence about recognized forms. No recognized producer means unresolved, not automatically dead. A dead-value or compatibility-only decision also needs dynamic, external-input and historical-reader evidence.
  • A partial consumer handles a subset of S_v; this is not an exemption permitting unregistered outputs. External inputs must be validated/translated or have an explicitly open contract.
  • Count equality with editable anchors is a current-snapshot constraint, not proof of historical monotonicity. Scope alone does not make name-based counts invariant under renaming.
  • Tagged slots can share strings: (slot, value) identifies the case. Distinct field paths may already provide that context; pairwise-disjoint raw strings are not required.
  • Identifier occurrence counts improve substring metrics but do not prove zero semantic readers. Candidate value-set equality does not prove same_concept behavior.
  • Inventory generation can become stale across merges; the original 8/20 sample is historical evidence, not a universal probability of failure. Recompute and validate the integrated tree.

Historical census — retained, not current acceptance targets

The original issue labeled the following census with baseline 1dc6ad8d8. Keep it as historical context; refresh counts and source SHA with the current generator before selecting repairs. Parser changes and reclassification are not debt repayment.

Carrier or observation Historical count
Python string enums 102
Named closed sets 489
TypeScript as const arrays 40 (21 equal a Python set)
*_SCHEMA_VERSION names 754
Same-runtime string forks 25 names / 58 definitions; semantic subset: 18 names
Conflicting string values 18 names; semantic subset: 2
Multi-value forks / twins 4 / 19; SOURCE_SURFACES is a known context-classification case
Distinct names sharing a value set 32 candidate groups
Control-plane same-basename Python/TypeScript pairs 43

Proposed scope and dependencies

Two tracks can proceed locally in isolated worktrees. Runtime, authority and compatibility changes still follow normal repository review rules; a cleanup label does not waive them.

M0 merged + #4453 design/schema follow-up
  |-- Track A: classify -> bounded repairs + parity evidence
  `-- Track B: B0 model precision -> B1 scope -> B2 kernel producer pilot
                             `---- B3 reader metrics (can run in parallel)
        Q9 ---------------------- B4 merge-order policy
B1/B2 + Q3/Q6 -> M1 typed slots
M1 + Q2/Q7/Q10 -> M2 published decision contract
B3 + per-field compatibility evidence -> M3 retirement
TypeScript migration cutovers -> M4 twin reduction

M3 need not wait for unrelated M2 work if its own readers/migration evidence is sufficient. Track A need not reach zero before M1. Local prototypes and fixtures can proceed while a decision is pending; policy activation and incompatible product changes wait for the specific decision.

Track B — bounded measurement improvements

  • B0 — align formulas, roles and enforcement claims. Reconcile RFC I2/I11–I14 with the limits above; distinguish schema validation, implementation stage, evidence status and actual blocking behavior. Add focused malformed/duplicate/missing-entry regressions for the formal signature and hierarchy. Exit: bilingual contract is internally consistent; metadata cannot be presented as an executed proof. 已交付 —— #4661:签名/层级的畸形与重复负例回归,并把 schema 校验、实施阶段、证据状态、实际阻塞行为四种声明在 RFC 中分开陈述。
  • B1 — scope and stable attribution. Specify global/bounded_context, context IDs, owner symbols and relevant slots; use SOURCE_SURFACES and its four CLI owners as the first case. Preserve raw counts; report classified semantic conflicts separately. If claiming rename invariance, add stable semantic identity or an explicit rename mapping. Exit: legal context reuse is distinguished, undeclared new collisions remain visible, and an identifier rename alone receives no debt-repayment credit. Implement the data shape before adding rows to the closed registry schema. Status 2026-09-17: the scope half is delivered - scope_declarations with SOURCE_SURFACES and its four CLI owners merged in #4494; raw multi_value_forks stays 4 while multi_value_forks_semantic is 3. Rename invariance is not closed: #4614 measured every case instead of assuming one. Only a declared name fails closed, because the declaration names every defining module. An undeclared one-sided rename, and renaming every side at once, both lower the budget with nothing reporting it; that residue is recorded in RFC Appendix B rather than left implied. The new divergent_value_sets advisory is a fork-visibility companion, not a rename detector.
  • B2 — producer pilot for four Turn kernel vocabularies. Start with turn_result_kind, turn_route, loop_disposition, effective_action. Bind a recognized write/return to its vocabulary and slot using bounded AST analysis; report dynamic/alias/external paths as unresolved. Definite unregistered writes fail; missing producer evidence is investigated before removing values or granting a reasoned compatibility exception. Recheck skip, replay values and both quota_action_selection_* codes. Exit: positive/negative fixtures cover both runtimes and slot attribution; unknown paths are visible; ordinary consumer edits need no new registry entries. Pilot before enabling additional blockers. Status 2026-09-17: partially delivered - action-domain separation and production evidence (#4494), one bound re-export hop in the Python producer scanner (#4573), and a recorded reason per unresolved site (#4581). The recheck is finished: skip, observe_replay, block_replay and both quota_action_selection_* codes are verified absent from all 26 registered vocabularies. Remaining: the 19 real effective_action candidate sites - 34 total minus the 15 unprovable by design (10 same-name keyword arguments, 5 pure type annotations). 已交付 —— #4573 / #4581 / #4682:有界 producer 绑定与 blocker 分类;当前 40 个未解析站点各带具体理由,其中 15 个在设计上无法成为证据。该残留已于 2026-09-18 由 #4687 修复,连同另外两处同类漏报:** 展开重放了被下标改写前的陈旧初始值,以及 TypeScript 扫描器没有作用域模型、把被遮蔽的 String/undefined 当作内建。三处都是漏报——一个看起来完整的值集里少了一个值,而 F1 证明的是 Produced_scan(v) ⊆ S(v),漏报会让未注册值通过门禁,多报只会误警。反例套件在 main 上先跑出 16/20,四条失败中的三条是真漏报。
  • B3 — retirement metric. Replace substring matching with an explicit syntactic-use metric, including string-key access (obj["field"], get("field")), attributes and unresolved computed keys. Distinguish reads/writes/mentions. Compare old/new counts and reconcile all six anchors in one reviewed diff without claiming remeasurement as cleanup. Delivered 2026-09-18 — #4651, merge 02cc53bd5. Five orthogonal roles (reader/writer/binding/unresolved/mention) per module, asserted to partition the token count per field and per runtime, so the smaller number is provably a reclassification of one population rather than a smaller sample. Both budgets are pinned in the same diff; retiring the token budget is Q11's call. dynamic_mapping_key_sites=1739 and typescript_dynamic_member_sites=410 are printed, so "zero lexical count alone cannot authorize deletion" is a number rather than a caveat in prose.
    One correction to this item's own exit condition. It named goal_boundary_repair not being a reader of goal_boundary as the test. Measured, the old token metric already passed that: _token_pattern matches standalone tokens, so a module containing only goal_boundary_repair scored zero under both metrics. The defect the old metric really had is the one B3 fixes — it cannot tell a bare mention from a read at all. That is where the gap lives: goal_boundary has 30 token-matching modules but a surface of 16, because 14 of them are prompt prose and module-path imports. The exit condition was aimed at a problem the metric did not have.
  • B4 — inventory freshness / Q9. Prepare an isolated two-branch integration fixture and document a reproducible regenerate/check sequence. Closed by the decision itself, not by the fixture. The exit condition was "chosen policy is recorded in RFC §10"; Q9 selected on-demand inventory and §10 now records it: the committed census is removed, checks evaluate G(f(T), R) over the full tracked tree on every run, and the extra condition I_committed = f(T) is gone. The two-branch fixture was scoped against the committed-snapshot policy — it tested a staleness that can no longer occur — so it is withdrawn rather than carried. The obligation that survives is already in §10 prose and unchanged: validate the combined tree normally; never replace the full-tree scan with a diff-only scan.
  • B5 — optional consumer report. Extend the existing report only after concrete producer/slot identities are available; distinguish read/interpret/pass-through/unknown with location, source SHA, domain and limitations. Exit: evidence report works on representative paths with no blanket consumer-registration or global merge gate. This is not an M1 blocker. 已交付 —— #4663:仅覆盖声明了 literal_scan.field 的词表(当前 1/26),其余 25 个报告为 missing_slot_identity 而非猜测;建议性输出,不设门禁。覆盖率只能由后续迁移声明槽位身份来提升,改代码无法提升。

Track A — classify and repair existing debt

Each item requires current-source confirmation. Resolve scope mistakes through B1; prioritize verified duplicate authority or incompatible meanings over reducing totals.

  • AGENT_TODO_HEADER_MARKERS, USER_TODO_HEADER_MARKERS — unified in #4643, merged 2026-09-17. Both parsed the same active-state document into the same role vocabulary, so they were one contract with two implementations, and the copies disagreed on 15 of 23 realistic headings: archives counted as live, the writer-created Codex Todo heading was invisible to the counter, and bare owner matched prose Ownership sections. The fix deletes both copies and delegates to the writer's classifier (todo_role_for_heading), un-silencing state_projection_gap_warning. - [ ] RAW_MATERIAL_KEY_HINTS remains open, measured by #4614 as genuinely different value sets (body/chat/credential/dm vs credential/local_path/log/raw), so it stays classification work, not a direct single-sourcing.
  • Resolve DECISION_CONTEXT_CAPABILITY_ID hyphen/underscore and MCP_REQUIREMENT pin/range differences after checking actual callers and packaging boundaries. Done: #4513 merged - the two spellings were classified as two slots rather than one conflict (the hyphen is the extension/directory namespace, the underscore is the packet contract, and no consumer joins them), the kunluncode MCP pin was single-sourced, and a regression test pins the classification.
  • Classify the 19 historical multi-value twins and 18 semantic string forks; retain justified independent contracts. Example to inspect: SOURCE_REGISTRY_SHADOW_FINDINGS in the status/projection modules. Status 2026-09-17: open. The named example was single-sourced in #4517 - it now has one definition in loopx/control_plane/status/registry_health_projection.py that loopx/status.py imports. Ratchets after the four 2026-09-17 merges (refactor(status): single-source six duplicated status vocabulary constants #4606, refactor(todos): import the Todo task-class vocabulary from its owner #4608, feat(semantics): report the name-keyed value-set divergence a rename hides #4614, refactor(semantics): single-source five duplicated multi-value vocabularies #4617): same_runtime_forks_semantic 11, conflicting_values_semantic 0, multi_value_twins 13, multi_value_forks_semantic 1; fix(state): count Todo headings the way the region writer classifies them #4643 merged and took multi_value_forks_semantic to 1 by retiring the two Todo marker forks; measured 2026-09-18 on 092a28c4e it is still 1.
  • Per-value meaning for registered vocabularies. 2026-09-18 实测 149/149(2026-09-17 尚为 13/149):kernel 68 个值由 #4625 / #4626 补齐,cross_runtime 81 个值由 #4662 补齐;其中 2 条无法从代码确立产生条件的,如实标为 unresolved 并写明缺什么证据。覆盖不等于验证:这是文档覆盖,与 F1/F2 的生产验证(6/26)是两件事。
  • Classify the 32 historical same-value candidates as same_semantics, same_values_different_semantics, same_semantics_different_scope, or unrelated_collision. Record review evidence; agree a supported representation before adding classification fields to the registry. Only confirmed same_semantics groups become merge work. CONFIDENCE_LEVELS and EDGE_CASE_COMPLEXITIES illustrate why equal sets are insufficient. Status 2026-09-17: open; remeasured at 38 groups, not the historical 32.

M1 — typed effective_action (Q3 + Q6; after the relevant B1/B2 evidence)

  • Choose a canonical definition and update producers/consumers to use it.
  • Separate decision, frontier and replay contracts by typed field path or discriminated union, preserving needed compatibility. Exit: consumers can unambiguously determine the slot; raw string sets need not be disjoint.
  • Resolve skip, move observe_replay / block_replay out of decision semantics, and keep quota_action_selection_* errors out of the verdict slot where source/reader evidence supports that change. Exit: status/should-run parity and migration checks pass; no arbitrary “28 values” gate. Done: #4494 separated the action domains against production evidence; all five values are verified absent from the registry, and the drift smoke is green on main. The typed owner and the slot split (the other two boxes here) still wait on Q3 and Q6.

M2 — published Turn decision contract (Q2 + Q7 + Q10)

  • Publish route→disposition and the owning decide_loop_disposition rules through a shared contract and generated bindings. Define relevant input partitions, priority and rejection paths first. Additional hops must include required context; do not invent a context-free result→route function if behavior is not one. Done: #4499 merged turn_contract_generated.py / .ts carrying TURN_CONTROLLER_CONTRACT with route_projection over all 8 routes and the 29 decide_loop_disposition rules; #4580 pinned the rule id order and proved it load-bearing, so a reordering cannot silently change first-match semantics.
  • Make settlement.ts and transaction.py consume the shared result-kind definition. Exit: generation freshness, boundary cases and behavior/parity evidence pass; copying a table through a generator alone is not proof of the full function. Done: #4571 - transaction.py imports LoopXTurnResultKind from turn_contract_generated, and settlement.ts imports TURN_RESULT_KINDS / TurnResultKind from turn_contract_generated.ts. Neither file keeps its own copy of the set.
  • Decide whether to reuse the existing maintainability exception lifecycle; avoid another speculative framework.

M3 — retire legacy fields one at a time

Gate: B3 evidence plus writer, reader, external-consumer and persisted-format compatibility review. B3 landed 2026-09-18, so the counts below are measured surfaces, not module mentions. Each row keeps its historical count and its token count beside the surface, because the three answer different questions and the gap between them is the point. Remeasure on the current tree before ordering work; these were taken on 092a28c4e.

  • protocol_action_packet (historical 7 Python / 2 TypeScript; token count 5 / 2; measured 2026-09-18 on 092a28c4e by B3: surface 5 py / 2 ts — reader 1, writer 4, binding 0, unresolved 0, mention 0. The cheapest first removal and the only field with no unknown use.)
  • external_evidence_observation (historical 11 / 1; token count 8 / 1; measured 2026-09-18 on 092a28c4e by B3: surface 7 py / 1 ts — reader 4, writer 1, binding 1, unresolved 1, mention 1.)
  • heartbeat_recommendation (historical 18 / 1; token count 17 / 1; measured 2026-09-18 on 092a28c4e by B3: surface 13 py / 1 ts — reader 8, writer 4, binding 1, unresolved 0, mention 4.)
  • execution_obligation (historical 21 / 1; token count 20 / 1; measured 2026-09-18 on 092a28c4e by B3: surface 15 py / 1 ts — reader 8, writer 7, binding 0, unresolved 0, mention 5.)
  • work_lane_contract (historical 32 / 3; token count 29 / 3; measured 2026-09-18 on 092a28c4e by B3: surface 29 py / 3 ts — reader 11, writer 8, binding 9, unresolved 1, mention 0. The most expensive field; its token count and surface coincide because it carries almost no bare mentions.)
  • goal_boundary (historical 35 / 2; token count 30 / 2; measured 2026-09-18 on 092a28c4e by B3: surface 16 py / 1 ts — reader 8, writer 4, binding 3, unresolved 1, mention 14. The token count nearly doubles the real surface: 14 of its 30 modules are prompt prose and module-path imports.)

Exit per field: producer/reader migration evidence, focused negative/parity tests, rollback path and required schema-reduction decision. Keep retirement evidence after removal rather than requiring an empty ledger.

M4 — runtime migration

  • Reduce Python/TypeScript twins with the existing TypeScript migration RFC. A same-basename pair is a candidate, not proof of duplicate authority. Each cutover needs real-path parity and its own migration evidence.

Decisions — proposals, not assigned commitments

Record approved outcomes in RFC Appendix B; link the implementing PR here. “Before” identifies the dependent milestone, not a new calendar deadline. Owner roles below do not assign GitHub users.

Decision Responsible role Needed before
Q9 integrated-tree freshness: up-to-date/queue validation, reviewed regeneration recovery, or unmaterialized inventory repository maintainers activating B4 policy; local fixture work can proceed
Q3 canonical EffectiveAction owner kernel maintainers M1 implementation contract
Q6 typed field paths vs tagged union and compatibility Turn Envelope owner M1 protocol changes
Q2 keep route/disposition separate; establish persistence through actual write/read paths Turn driver owner M2 projection decision
Q10 Turn end state and any information-preserving migration Turn driver owner M2 closure
Q7 exception lifecycle reuse canary maintainers M2 exception work
Q11 revised retirement metric/anchors kernel maintainers B3 metric activation, first M3 removal
Q1 registry location kernel maintainers M1 ownership closure
Q4 generated glossary docs maintainers glossary slice, if selected
Q5 term-family review rule kernel/docs maintainers adopting that review rule
Q8 promotion from inventory to curated scope kernel maintainers expanding mandatory coverage beyond the pilot

Target state and closure

The original RFC's numerical targets are retained as historical direction, not universal gates. Propose synchronizing these refined acceptance criteria into the RFC before milestone closure.

Surface Historical baseline Measured 2026-09-17 Acceptance target
effective_action 33 values, 3 slots; earlier target about 28 32 values in one owner enum; 5 retired (skip, both replay codes, both quota_action_selection_*); still one slot and merge_candidate, so the M1 split is outstanding Typed owner(s), unambiguous slots, producer/reader compatibility; count follows justified semantics
Turn vocabularies 3 sets, 28 value slots, 21 spellings 3 sets, 28 value slots, 21 spellings, unchanged; route_projection and the 29 controller rules generated and checked Preserve required distinctions; checked contextual projections; merger only if Q2/Q10 approve
Forks/conflicts/twins 18 / 2 semantic names; 4 / 19 multi-value cases 18 / 0 semantic names; 4 / 19 multi-value cases; py/ts twins 43 Zero unreviewed confirmed duplication/conflict; legitimate independent contracts remain documented
Six legacy fields 124 Python / 10 TypeScript module mentions 6 fields, 109 Python / 10 TypeScript module mentions by identifier counting; below the historical number at every field Per-field safe removal or explicit retained-compatibility decision with follow-up
Merge candidates 32 unclassified 38 raw groups, of which 18 are the registered Python/TypeScript owner pairs of one vocabulary; the real backlog is 20, below the historical 32 All selected candidates classified; evidence-backed same-semantics repairs completed
py/ts twins 43 43, unchanged Follow migration RFC acceptance, not a standalone zero-count target

The Measured column is dated and non-normative: it records what the tree
measured on 2026-09-17 so work can be ordered against current numbers rather
than the historical baseline, as the sentence below already requires. A later
measurement replaces it; it does not amend the acceptance target. The RFC's
Section 11 target table carries the same column.

Keep this issue open until selected milestones have linked merged PRs and evidence, and unresolved/deferred items have explicit dispositions and linked follow-ups. Scope changes require a recorded decision; merging #4453 alone is insufficient.

Intended base branch

main in huangruiteng/loopx; use the latest actual upstream base for each new PR, not a stale fork ref.

Relevant files and commands

  • RFC English/Chinese pair: Sections 2, 5, 9–12 and Appendix B.
  • loopx/semantics/vocabulary_v0.json, inventory_v0.json, inventory.py.
  • examples/semantic-vocabulary-drift-smoke.py, tests/architecture/test_semantic_inventory.py, tests/architecture/test_semantic_vocabulary_drift.py.
  • python3.11 scripts/generate_semantic_inventory.py --report: symbol-mention ranking only. Merge candidates are available via merge_candidate_groups; a dedicated CLI report is follow-up work.

Validation and contribution contract

Use the project's supported Python (>=3.11), with python3 on PATH resolving to that environment for canary commands. Explicitly stage any new public source paths before regenerating because the scanner uses Git-index paths and working-tree content. Private notes/raw evidence stay excluded.

python3.11 examples/semantic-vocabulary-drift-smoke.py
python3.11 scripts/generate_semantic_inventory.py --check
python3.11 examples/docs-governance-smoke.py
python3.11 -m pytest -q tests/architecture
loopx canary premerge --from-git-diff --git-diff-base upstream/main
  • Track A: show the specific authority/conflict repaired and caller parity; update a budget only when its measured debt actually changes.
  • Track B: show a meaningful counterexample, corrected classification, unknown handling and protected negative tests. No requirement to lower a count or remove an inventory row.
  • M1–M4: validate affected production entrypoints and compatibility, not just generated-set equality. Persisted data changes need reader/migration evidence.
  • Report exact base/head, commands, failures/skips, boundaries and rollback. Historical mutation totals are not a whole-program guarantee. Synchronize normative English/Chinese changes.
  • Follow AGENTS.md for decisions; do not turn routine budget reductions into an extra approval gate. Every PR-range commit, including inherited/cherry-picked commits, needs Signed-off-by. Use git commit -s; repair each affected commit with git commit --amend --no-edit -s, then check the entire PR range. Published-history rewrites need explicit authorization and a guarded lease.

Outside this tracker: the separate maintainability RFC_MODULE_BUDGETS anchor question should be triaged under its own RFC; this issue does not alter it. M0/M0.5 do not change runtime/wire behavior. M1–M4 may make scoped changes after their decisions and compatibility work; no bulk unification, global consumer-registration mandate or claimed whole-program proof.

Public/private boundary

  • This issue contains no private benchmark traces, verifier output, credentials, internal links, raw agent sessions or local runtime state.
  • Maintainer-owned benchmark cases are not run or duplicated without a separately scoped public task.

中文说明

当前完成度与关联

RFC 是设计契约,issue 是状态与依赖清单。这里对验收口径的修正属于提案,应同步到 RFC 中英双版后才成为规范;不代表维护者已经批准。

门禁强度与角色

层级 内容 真实状态
当前阻断 M0 owner 集合、双运行时 parity、已登记投影、清单新鲜度、源码与预算边界 仅在声明的扫描范围内生效;F1–F6 中当前配置为此层的是 F5
后续阻断 F1 生产闭包、F2 来源证据义务、F4 作用域 从四个 Turn 内核词表试点,分析与回归证据充分后再启用
建议性报告 F3 消费者定义域、解释/透传关系、合并候选 关系分析待实现;当前 --report 仅按符号提及数排名
未证明 F6 历史读者兼容、完整数据流与行为等价 保留证据缺口,不能宣称通过

enforcement_policy 目前是被校验的元数据,不会因为改了分组就自动实现或启用分析器。

Owner 定义词表,Producer 在具体输出/槽位引入值,Consumer 读取或接受值。Interpreter 与 Pass-through 是消费者子角色,不是互斥、穷尽的模块分类。 转换器可以既消费又生产;持久化另需版本、写入、读取与迁移证据。枚举成员出现在源码里,不等于它被写入协议。

保留以下数理边界:

  • 区分注册集、运行时值集与扫描观测集;先在完整值域上定义生产,再检查是否属于注册集,避免把结论预先写进定义。
  • 未扫描到生产者是“来源未解析”,不能直接判死值;需核查动态来源、外部输入及兼容读者。skip 要调查后再决定删除或兼容保留。
  • 部分消费者接受注册集的子集,不意味着允许随意产生未注册值。
  • 作用域字段不能单独保证改名不变性;锚点相等不能证明跨提交历史单调性。
  • 带标签的 (slot, value) 可以重复使用字符串;不要求各槽位原始字符串两两不交。
  • 标识符计数不等于真实读者计数;同值集合不等于同一概念。8/20 只是历史样本,不能当成固定的未来故障概率。

两条轨道与可本地推进的任务

轨道 A:分类、确认、修复已有债务。 保留原清单:三个 marker/hint 多值分叉、DECISION_CONTEXT_CAPABILITY_ID 与 MCP_REQUIREMENT 差异、19 个多值孪生、18 个语义分叉、32 组同值候选。先核对当前调用者与作用域,再修真正的重复权威或冲突;合法独立契约可以保留。四类候选标签见英文任务表;不能自动合并或仅改名消数字。2026-09-17 实测进展:DECISION_CONTEXT_CAPABILITY_ID 与 MCP_REQUIREMENT 已结案(#4513,判为两个槽位而非一个冲突);SOURCE_REGISTRY_SHADOW_FINDINGS 已单源化(#4517);marker/hint 分叉中 AGENT_TODO_HEADER_MARKERS 与 USER_TODO_HEADER_MARKERS 已由 #4643 单源化(已合并)——两者解析同一份 active-state 文档、分到同一套角色取值,属一份契约两处实现;RAW_MATERIAL_KEY_HINTS 仍待分类(#4614 实测值集确实不同)。同值候选组重测为 38 组(原记 32;#4630 已合并,指出其中 18 组是已注册词表的 py/ts owner 符号对,属扫描器伪影而非债务)。

轨道 B:先让度量可靠。 英文 B0–B5 是主任务清单:

任务 本地可做 退出证据与限制
B0 模型精度 修正 RFC 公式、角色、I2/I11–I14 与阶段声明;补签名/hierarchy 的负例 中英文自洽,结构校验不冒充语义证明
B1 作用域 设计 context/owner/slot,以四处 SOURCE_SURFACES 为首例 原始计数保留;合法复用与未登记冲突可区分;若承诺改名不变,必须有稳定身份或改名映射
B2 生产者试点 四个 Turn 内核词表的有界 AST 分析、槽位归属、双运行时正反例 确定的非法写入失败;动态/别名/外部来源显式 unresolved;无来源先调查;普通消费者不用逐次登记
B3 退休度量 区分读/写/提及;覆盖属性、字符串 key 与未知计算 key;新旧计数对照 复合名字不误计、真实 key 读取不漏计;六个锚点按新口径评审调整,不把口径变化当消债;零计数不是删除许可
B4 合并序 两分支集成 fixture、重生成与检查流程 Q9 选择后同步 RFC;验证集成后的源码树;平台配置待维护者决定,恢复仍走签名 PR
B5 消费者报告(可选) 有具体词表/槽位身份后补读取、解释、透传、未知报告 不引入全仓库消费者登记或阻断,不阻塞 M1

本地 fixture 和设计可以在决策待定时推进;阻断启用、协议不兼容修改和平台配置等待对应决策。轨道 A 不必先归零才能做 M1;B3 可以与生产者试点并行。

后续里程碑

  • M1(B1/B2 相关证据 + Q3/Q6):明确 owner,按类型化字段路径或标签区分 decision/frontier/replay;处理 skip、replay 值和 quota 错误码,验证真实调用与旧格式兼容,不强求恰好 28 值。
  • M2(Q2/Q7/Q10):发布 route→disposition 和承重决策规则;先定义输入分区、优先级和拒绝路径,再生成 Python/TypeScript 绑定。额外投影需要上下文时必须保留;不虚构无上下文的 result→route 函数。生成器自身不能证明行为。
  • M3(B3 + 每字段兼容证据):逐个处理 protocol_action_packet、external_evidence_observation、heartbeat_recommendation、execution_obligation、work_lane_contract、goal_boundary。核实写方、读方、外部消费者、持久化与迁移,再删除;保留退休证据,不要求账本清空。无需等待无关 M2 工作。
  • M4:跟随既有 TypeScript 迁移 RFC,按真实路径 parity 与迁移证据减少孪生;同文件名不是重复权威的证明。

关闭条件(2026-09-18 提出)

本 issue 目前 26 个复选框、11 个 Q 决策,没有"做完"的定义,只有"全部勾上"——而
边际收益已经明显递减。提出一个可验收的关闭条件,供维护者确认:

满足以下三条即可关闭:

  1. 每个跨运行时边界的词表都有 producers 声明。 2026-09-18 实测 F1/F2 覆盖
    6/26,20 个 cross_runtime 词表没有任何生产验证——它们完全靠人不犯错。这是
    当前最大的防护缺口,而且扩大它不需要写新代码,机器已经造好,缺的是注册表
    里的声明。
  2. 同运行时分叉降到个位数。 实测 18 个(41 处定义)。棘轮历史显示这类修复
    每个约 20 行(refactor(semantics): single-source five duplicated multi-value vocabularies #4617 是 13 增 16 删、refactor(todos): import the Todo task-class vocabulary from its owner #4608 是 20 增 12 删),位置与修法都已知。
  3. 六个旧字段退休完成。 消掉约 85 个模块的迁移面,是唯一让代码库真正变简单
    的工作;其余都是让它更可测。

以下明确标为"已测量、已接受",不再作为关闭前提:

  • F3 消费者定义域(0/26,advisory)——B5 已交付并证明:在注册表为更多词表
    声明槽位身份之前,覆盖率无法靠改代码提升。
  • F6 持久化读者兼容(0/0,unproved)——证据缺口如实保留,不宣称通过。
  • 合并候选全部分类(20 组真实待分类)——分类本身不消除重复权威,应由真实
    迁移需求拉动,而不是先分类完再等着。

理由:截至 2026-09-18,最后一次真实降债是 #4608(09-17,分叉 20→18)。此后合并的
每一个 #4447 PR 都是度量修正——它们修的都是真问题(F5 拿声明当证据、扫描器
给自信的错答案、等价写法能伪造退休进度),但四个健全性反例现在全部安全、
149/149 个值有产生条件说明,度量阶段已经结束。继续打磨尺子没有空间了,应该
开始用它。

决策与完成标准

11 个 Q 保留独立决策表:Q9 对应 B4;Q11 对应 B3/首次删除;Q3/Q6 对应 M1;Q2/Q7/Q10 对应 M2;Q1/Q4/Q5/Q8 分别涉及位置、术语表、评审规则和扩展覆盖。责任角色不等于指派某个贡献者,建议的里程碑期限不等于维护者承诺。

已合并的计划 —— 本追踪交付了什么

此前列为「13 个在开 PR」的那一批已全部合并。它们作为一个计划被评审,因此保留为一条记录;
下面的合并顺序是实测的,不是估计的。

轨道 A —— 偿还已计量的债务。 #4606 单源化六个 status 常量,
#4608 让 Todo task-class 词表从 owner 导入,
#4617 单源化五个多值词表。连同 #4513
与 #4517,这批真实删除了 7 个分叉名字、17 处重复定义:
same_runtime_forks 25 名 / 58 定义 → 18 / 41,multi_value_twins 19 → 13。

轨道 B —— 让测量忠实。 #4614 报告改名会隐藏的按名分歧,
并实测了它未闭合的边界;#4630 把 18 组已注册 owner 对从合并候选中滤出;
#4629 把两个棘轮锁到实测值;
#4631 把每条形式不变量限定到它真正验证的域;
#4628 把每次运行的 ast.parse 调用减半。

评审合并后的树才发现的更正。 #4680 修了两处自相矛盾的度量——
仅重排 set 被算成新分叉,而旁边的分歧报告正确地说值集没变;以及注册但未实现的投影仍报 F5:2/2。
#4682 与 #4687
修掉三处 producer 扫描的漏报——一个看起来完整的值集里少了一个值。方向很重要:F1 证明的是
Produced_scan(v) ⊆ S(v),漏报会让未注册值通过门禁,多报只会误警。

合并顺序,存档。 试合全部 78 对,发现 9 处冲突、4 个簇,全部是文本相邻而非语义分歧:棘轮锚点
(#4606/#4608/#4617/#4629)、drift 测试文件的追加簇(#4626/#4629/#4631)、RFC Appendix B 行
(#4614/#4627/#4631)、inventory 生成器(#4614/#4630)。追加簇的冲突复发频繁到
#4691 直接消除了成因:每条账本条目现在是
docs/architecture/rfcs/ledger/<rfc-slug>/ 下的独立文件。

治理范围 —— kernel 层,这是边界不是目标

在 092a28c4e 上实测:树中定义了 664 个词表载体(107 个 Python enum、504 个具名闭集、
8 个 Literal 别名、45 个 TypeScript as const 数组)。注册表治理其中 26 个(3.9%),
**6 个(0.9%)**带生产证据。

本追踪治理 kernel 层,不主张其余部分,扩大这个数字也不是它的目标。 两条推论,都是边界而非待办:

  • 26 个之外的词表得不到这个守卫的任何信号——提交时没有,造词的那一刻也没有。
    守卫以全树扫描的方式跑在 pytest/premerge/CI 里;一个值被引入的过程中没有任何东西触发。
  • 排除 merge 提交后,vocabulary_v0.json 的 23 次编辑全部出自同一个作者。
    至今没有任何贡献者因为这个检查而不得不去注册一个词表。这与 3.9% 的范围是一致的,
    也正是下面把剩余工作砍掉而不是扩大的理由。

维护者在 2026-09-15 提出的
另一个问题——Agent 如何意识到自己在造新词、如何判断该不该造——不由本追踪治理。
它当时以散文形式作答,
之后从未被实现:AGENTS.md 没有一处提到词表治理,没有对应 skill,
注册表 schema 校验的 candidate_decision 分类(reuse_existing、extend_vocabulary、create_vocabulary 等)
在注册表里被使用 0 次。那件事需要自己的 issue 和自己的验收判据,它不是本追踪的里程碑。

进度实测(2026-09-18)

树的规模:跟踪源码 1215 个文件(1066 py / 149 ts、约 17 MiB),多值载体 611 个
(107 枚举 + 496 闭集 + 8 个 Literal 别名)与 2130 个具名字符串常量。漂移守卫
单次耗时约 39 秒(3 次中位数)。

表面 历史基线 2026-09-18 实测 验收目标
effective_action 33 个取值、3 个槽位;早先目标约 28 32 个取值、单枚举 owner;仍是单槽位,状态仍为 merge_candidate,M1 拆槽未开始(卡 Q3/Q6) 有类型的 owner、槽位无歧义、生产者/读者兼容
Turn 词表 3 套、28 个取值槽、21 个拼法 未变;route_projection 与 29 条 controller 规则已生成校验,并被 settlement.ts 与 transaction.py 真实消费 保留必要区分;上下文投影经过校验
逐值含义 — 149/149(2026-09-17 还是 13/149):kernel 68 由 #4625/#4626,cross_runtime 81 由 #4662;其中 2 条如实标 unresolved 并写明缺什么证据 每个注册值写明产生条件,而非复述标识符
分叉/冲突/孪生 语义名字 18 / 2;多值情形 4 / 19 同运行时分叉 18(41 处定义)、冲突值 16(55 处定义)、多值分叉 2、py/ts 孪生 43 独立维护 + 1 生成校验 没有未经评审且已确认的重复/冲突
债务趋势 — 分叉 25 → 18(−28%)、冲突值 18 → 16(−11%),三天内由 #4517/#4606/#4608/#4617 等单源化 PR 消化 持续下降,每次下调与棘轮同一 diff
强制覆盖面 — F1/F2 6/26、F3 0/26(advisory,走查为零)、F4 4/4、F5 1/1、F6 0/0(unproved);声明 producers 的 6/26,声明 literal_scan.field 的 1/26 扩大到更多词表——20 个 cross_runtime 词表目前没有任何生产验证,这是当前最大的缺口
六个旧字段 124 py / 10 ts #4651 已落地:按 token 计数 109 py / 10 ts,按迁移面计为 85 py / 9 ts,差额 24 py 是纯提及与模块导入。逐字段迁移面:protocol_action_packet 5/2(unresolved 0)、external_evidence_observation 7/1、heartbeat_recommendation 13/1、execution_obligation 15/1、goal_boundary 16/1(token 30,差额 14 全是提示词散文与模块路径)、work_lane_contract 29/3 逐字段安全移除,或显式保留兼容决定
producer 未解析站点 — 40 个,其中 15 个"再宽的扫描也无法成为证据";blocker 分类:call_result 14、argument_name_only 10、attribute_read 7、annotation_only 5、unstable_local 3、other 1 缩小可缩小的部分;不可证的保持 unresolved
合并候选 32 组未分类 沿用 2026-09-17 的 38 组原始 / 20 组真实待分类,本次未重测 所选候选全部完成分类

该残留已修复。 #4687 关掉了 global
重绑定这一处,连同另外两处同类漏报:** 展开重放被下标改写前的陈旧初始值,以及
TypeScript 扫描器没有作用域模型、把被遮蔽的 String/undefined 当作内建。
遮蔽判定按文件粒度——比按作用域粗,且是刻意的:文件粒度只可能扣下一个内建读法,
不可能凭空造出一个。

实测 列带日期且非规范:它记录当天树上的实测值,使工作可以按当前数字而非
历史基线排序。后续测量替换它,它不改动验收目标。RFC 第 11 节的目标态表带有同一列。

基线数字是原 issue 的历史记录,启动具体任务前按明确 SHA 重算。目标是没有未经评审且已确认的语义冲突/重复,各槽位清楚,历史兼容有证据;不把所有同名、孪生和合法独立词表都强制归零。待办未做完时保持 issue 开放;保留或延后必须有理由和跟进链接。

验证与贡献方式

复用上方命令,固定受支持的 Python,并记录准确 base/head。新源码路径须显式暂存后再生成清单;命令 --report 仅提供符号提及排行,候选组目前由 merge_candidate_groups 函数提供。

  • 轨道 A 证明修了哪个重复权威/冲突,并验证调用者行为。
  • 轨道 B 证明原先的反例被正确处理、未知可见,无需强制降低预算或删除清单行。
  • 协议和持久化改动另跑生产入口与读者/迁移验证;不能以源码符号零出现代替兼容性证明。
  • 规范变更同步 RFC 中英双版;routine 预算收紧按 AGENTS.md,不增加额外审批。
  • PR 范围内全部 commit(包括继承和 cherry-pick)均须 DCO:git commit -s;缺签时逐个 git commit --amend --no-edit -s,再检查完整范围。已发布历史重写需显式授权与 lease 保护。

本 issue 不另行修改 RFC_MODULE_BUDGETS 的可维护性规则,不包含私有日志、会话、凭据、本地运行状态或未经授权的 benchmark 任务。

Activity

  1. huangruiteng commented on Sep 15, 2026

    @huangruiteng
    Collaborator

    这个 RFC 挺有意思的,我想知道当 agent 决定将一个新词加入词表时,它的开发过程如何意识到自己在造新词,需要考虑哪些因素,如何评估自己是否该造

  2. songoow commented on Sep 15, 2026

    @songoow
    CollaboratorAuthor

    这个问题可以用 RFC 里的形式模型回答,但公式的作用不是让 Agent 做形式证明,而是让它在造新词之前先完成一套可检查的分类和反例测试。

    1. Agent 如何意识到自己可能在造新词

    Agent 不需要把所有字符串都当成语义词。只有当一个新字符串满足下面至少一个条件时,才进入“新词候选”流程:

    • 被写入跨函数、跨模块或跨运行时传递的字段;
    • 被写入 journal、receipt、数据库或其他持久化载体;
    • 被 if、match、switch、映射表或路由函数解释;
    • 出现在一个已经登记的闭集字段或协议槽位中;
    • 需要被另一个模块、另一个运行时或后续 Turn 读取。

    局部变量、日志文本、界面文案和只用于测试说明的字符串,不自动进入词表治理。

    可以把候选写成一个带上下文的对象:

    candidate = (value, field, slot, scope, producer, consumer, persistence)
    

    因此 "repair" 这个字符串本身没有足够信息。真正需要判断的是“它在哪个字段、哪个槽位、哪个作用域中,由谁产生、由谁解释,以及是否会被持久化”。

    2. 先判断是复用旧词、增加旧词表的值,还是建立新词表

    设已有词表为 V,其允许值为 Val(V),候选的语义契约为 K(c)。

    Agent 应先执行复用检查:

    Reuse(c, x) iff
      x ∈ Val(V)
      ∧ same_slot(c, x)
      ∧ compatible_scope(c, x)
      ∧ equivalent_contract(K(c), K(x))
    

    如果存在满足条件的旧值,默认复用旧值。不能仅因为新名字“更清楚”或“更符合当前 PR”就增加一个同义值。

    如果没有可复用的旧值,但候选仍属于已有词表的定义域,并且不增加这个值就会丢失一个真实状态,则是“增加已有词表的值”。

    如果候选不属于任何已有词表的定义域,或者它有独立的生命周期、owner、持久化版本和投影关系,才考虑建立新词表。

    这三个动作要分开:

    复用已有值       → 不扩宽词表
    增加已有词表的值 → 扩宽一个已知定义域
    建立新词表       → 引入一个新的语义维度或协议对象
    

    3. 什么叫“确实需要新词”

    最有用的反例标准是“如果复用旧词,是否会把两个本来应该不同的状态压成同一个状态”。

    如果存在两个状态 s1、s2,满足:

    encode_with_old_vocabulary(s1) = encode_with_old_vocabulary(s2)
    

    但它们在合法的消费者、路由、持久化或恢复行为上应该不同,那么旧词表表达能力不足,新增值或新增槽位有理由:

    ∃ s1, s2:
      same_old_encoding(s1, s2)
      ∧ required_behavior(s1) ≠ required_behavior(s2)
    

    反过来,如果两个候选只是在命名上不同,而它们的:

    • 生产条件;
    • 消费者行为;
    • 状态转换;
    • projection;
    • 持久化格式;
    • 兼容性要求;

    都相同,那么新增词只是在增加同义词,应复用旧值或建立显式别名/projection。

    这也是为什么 repair、repair_required 不能仅凭字符串相似度自动合并或自动拆分:要看它们在 route、result、controller 和持久化边界上的行为。

    4. Agent 在提交前应执行的最小流程

    A. 发现候选

    由 diff、AST 和字段使用位置发现:这是普通字符串,还是协议/控制流/持久化边界上的值。

    B. 查找已有定义

    检查 registry、owner symbol、同字段其他槽位、跨运行时定义、projection 和已有兼容值。

    C. 判断角色

    按 RFC 的模型标记:

    Owner       定义闭集
    Producer    产生或写入值
    Consumer    读取或接受值
    Interpreter Consumer 的分支/映射子类
    Pass-through Consumer 的序列化/转发子类
    

    一个模块中出现字符串,不等于它是 Producer,也不等于它拥有这个词。

    D. 形成证据

    若要新增值,至少提供:

    1. 一个明确的 producer 位点;
    2. 该值所属的 field/slot/scope;
    3. 主要 consumer 的接受域;
    4. 与现有值不可复用的反例;
    5. 所有已登记 projection 的处理方式;
    6. 如果会持久化,旧 reader 或 migration 方案;
    7. 正例、负例和未知动态路径说明。

    E. 选择执行强度

    • Turn kernel 和持久化协议:新增值进入阻断检查;
    • 跨模块但尚未完成 producer 分析的值:先要求结构化证据;
    • Consumer 只读取已有值:通常不需要修改 registry;
    • 动态来源无法静态解析:标记 unknown,不能当作“没有问题”;
    • 纯局部实现字符串:不进入全局词表。

    5. 提交时给 Agent 的实际问题

    每次准备写一个新词时,Agent 可以强制回答这六个问题:

    1. 我是在已有 field/slot 中写值,还是创建了新的语义维度?
    2. registry 和 owner 中是否已经有表达相同含义的值?
    3. 如果复用旧值,哪个合法状态会被错误合并?
    4. 谁产生这个值,谁消费这个值,谁解释这个值?
    5. 这个值是否跨模块、跨运行时或持久化?
    6. 我提交的是新值、新词表、projection,还是只是一段局部文本?
    

    如果第 2 个问题有答案,默认不造新词;如果第 3 个问题答不出来,通常也不应该造新词;如果第 4~5 个问题答不出来,只能提交为 unknown 的分析结果,不能把它登记成已经证明的协议语义。

    因此,RFC 的数理模型最适合被用作 Agent 的“新词决策框架”:它约束候选的定义域、生产关系、消费关系、作用域、投影和持久化边界;它不要求每个普通 PR 都维护一张全程序证明图。新词的默认成本应当是增加一个可验证的 producer、consumer/domain、projection 和兼容性负担,只有能给出“复用会丢失真实语义”的反例时,新增才值得。

  3. YZJF commented on Sep 16, 2026

    @YZJF
    Contributor

    Claiming one bounded Track A sub-item (not the whole tracker): classify and merge the SOURCE_REGISTRY_SHADOW_FINDINGS fork from the "19 multi-value twins / 18 semantic string forks" checklist row.

    Findings on current main (a28562e97): the name has four definitions, two in active code and two under deprecate/benchmark-legacy/. The active pair — loopx/status.py:289 and loopx/control_plane/status/registry_health_projection.py:28 — carry identical values ({source_registry_missing, stale_source_registry}) and feed the same downstream parameter (source_registry_shadow_findings of the attention-queue read model, consumed at work_items/attention_queue.py:77). Same slot, same consumer, same values: same_semantics.

    Plan: keep one definition in the control_plane projection module and have status.py import it, preserving the public status.SOURCE_REGISTRY_SHADOW_FINDINGS name because examples/control_plane/attention-queue-readmodel-smoke.py reads it. Dependency direction stays outer -> control_plane. The deprecate/ copies are left alone; they are outside the active scan scope.

    Will open a Refs #4447 PR that identifies this checklist row and does not close the tracker.

  4. songoow commented on Sep 17, 2026

    @songoow
    CollaboratorAuthor

    归一化视角:缺的不是理论,是一个键

    有人问这个项目是否需要引入"归一化"的概念。核对下来结论是:它已经有了,而且是规范的;真正缺的是一个键。以下测量都基于 main 9060ddc91。

    1. formal_model 已经是一份词表的范式理论

    它的结构与关系模型逐项对应:

    关系模型 formal_model
    论域 universes: {vocabularies, values, sites, scopes, roles}
    依赖 relations: defines / produces / consumes / interprets / passes_through / projects / persists
    类型层级 roles + role_hierarchy(consumer 为伞角色,interpreter 与 pass_through 是子角色)
    范式律 invariants F1–F6

    其中三条就是范式条款:

    • F1 Produced(v) ⊆ S(v) ⊆ U(v) —— 值域封闭。
    • F2 Canonical(v) ⊆ Produced(v) ∪ CompatibilityOnly(v) —— 无孤儿值,例外必须显式声明。
    • F4 "A name collision is a semantic conflict only when its declared scopes overlap" —— 同名 ≠ 冲突,且 "scope is never inferred from spelling"。

    所以该问的不是"要不要引入归一化",而是它离范式还差哪一步。

    2. 差的一步:身份键是名字,不是元组

    今天的键是名字。但名字并不由 (value, scope, owner, role) 决定,因此只改键、不改元组时,记账会跟着变。

    B1 的退出条件其实已经点名了修法:

    If claiming rename invariance, add stable semantic identity or an explicit rename mapping.

    这一个缺键,表现为三个看起来无关的症状:

    症状 实测
    改名洗白冲突 单侧改名使语义 fork 计数下降,无任何检查失败
    合并候选报告看不见分叉 三个未声明 fork 全部 in merge_candidate_groups: False
    M3 无法证明读者已消失 count_identifier_modules 仍是词法度量(B3 未做)

    三者是同一个缺失的推论:没有稳定身份,就无法说"这还是同一个东西"。

    3. F4 的执法目前是单向的

    check_scope_declarations 的判定是:

    undeclared = set(forks) - set(declarations)
    return len(undeclared)

    它能表达"已声明 ⇒ 不是冲突",却不能计算"作用域实际不重叠 ⇒ 不是冲突"。也就是说今天"冲突"的判据是缺少声明,而不是算出来的重叠。

    Track A 剩下的三个 fork 恰好全部落在这个空档里:

    AGENT_TODO_HEADER_MARKERS
      active_state_metadata.py -> [agent todo, codex todo, project agent todo]
      state_projection.py      -> [agent action, agent backlog, agent todo, agent 待办, 项目 agent]
      交集 = {agent todo}(1 项)
    
    USER_TODO_HEADER_MARKERS
      active_state_metadata.py -> [owner reading queue, owner review reading queue, user todo]
      state_projection.py      -> [owner, owner review, owner todo, user action, user todo, 人工, 用户]
      交集 = {user todo}(1 项)
    
    RAW_MATERIAL_KEY_HINTS
      content_ops/surface.py           -> [body, chat, credential, dm, local_path, log, message, raw, secret, token, transcript]
      goals/goal_channel_projection.py -> [credential, local_path, log, raw, secret, stderr, stdout, token, trace, transcript]
      交集 = 7 项;一侧另有 body/chat/dm/message,另一侧另有 stderr/stdout/trace
    

    三组都是部分重叠、互不包含。所以它们既不是 SOURCE_REGISTRY_SHADOW_FINDINGS(#4517)那种同值可直接单源化的情形,也不是同名不同义的硬冲突,而正是 F4 想区分、当前实现却算不出来的中间地带。

    RAW_MATERIAL_KEY_HINTS 尤其清楚:一侧是会话面(chat / dm / message / body),另一侧是进程 IO(stderr / stdout / trace),共享 7 个通用键。这更像两个有界上下文共用一个核心集合,而不是一次漂移。

    结论:这三项的正确形态是补 scope_declarations(让 F4 可适用),而不是合并。

    4. 建议不要做的两件事

    不要新增一层"归一化框架"。 RFC 第 5 节已把这类东西列为禁止:

    Forbidden alternate authorities: a second registry, a per-module list that restates registered values, or a prose table that claims to be normative for a registered vocabulary.

    formal_model 已经是那份理论,再加一层只会多一个需要同步的权威。M2 第 3 项的 "avoid another speculative framework" 是同一条。

    不要把键换成值集。 仓库里有现成反例:

    CONFIDENCE_LEVELS       reward_memory/candidate_review.py:26      {low, medium, high}
    EDGE_CASE_COMPLEXITIES  reward_memory/architecture.py:20          {low, medium, high}
    _CONFIDENCE_LEVELS      benchmark_toolkit/study_projection.py:54  {low, medium, high}
    

    值集全等而含义不同,所以值集做键会立刻错——这也正是 merge_candidate_groups 只能是 advisory 的原因。

    5. 对应到剩余清单

    • Track A 三个 fork → 补 scope 声明,使 F4 可适用。就绪,无前置。
    • B1 的稳定身份 / 改名映射 → 关闭改名洗白。feat(semantics): report the name-keyed value-set divergence a rename hides #4614(未合并)目前只做到如实记录边界并留测试哨兵,未闭合。
    • B3 → 补读侧依赖边,是 M3 六个字段的唯一门禁。
    • B0 → 文档一致性核对,可并行。

    Track A 三项与 B3 互不依赖,可并行推进。

  5. 27 remaining items

  6. songoow commented on Sep 18, 2026

    @songoow
    CollaboratorAuthor

    Tracker updated and scoped down — 2026-09-18, measured on 092a28c4e

    The body was materially out of date in five places, each of which would have
    misled someone picking this up. All five are corrected, and the remaining work is
    cut to two items. Rewriting a tracker body silently would be the wrong thing to
    do, so here is what changed and why.

    The five stale claims

    Claim in the body Reality on main
    B3 "Not started. B3 gates every M3 field" Delivered — #4651, merge 02cc53bd5. It no longer gates anything
    M3 six rows: "still a lexical metric until B3 lands" (×6) B3 landed; surfaces measured and now recorded per field
    "Thirteen PRs are open against this tracker" All thirteen merged. Zero open PRs remain under this tracker
    B2 residual: "global-rebound helper reports definite values only" Fixed by #4687, along with two more under-reports of the same class
    B4: "Exit: chosen policy is recorded in RFC §10" §10 already records it — Q9 chose on-demand inventory

    B4 is closed by the decision rather than by the deliverable. Its two-branch
    fixture was scoped against the committed-snapshot policy; it tested a staleness
    that can no longer occur, so it is withdrawn rather than carried. The obligation
    that survives is already §10 prose: validate the combined tree; never substitute a
    diff-only scan.

    One correction to B3's own exit condition

    B3's exit named goal_boundary_repair not being a reader of goal_boundary.
    Measured, the old token metric already passed that test — _token_pattern
    matches standalone tokens, so a module containing only goal_boundary_repair
    scored zero under both metrics:

    python_module_scan("goal_boundary_repair = 1; y = repair_goal_boundary_thing")
      -> {}                    # no role assigned
    _token_pattern("goal_boundary").search(same source)
      -> None                  # old metric also rejects it
    

    The defect the old metric really had is the one B3 fixes: it cannot tell a bare
    mention from a read at all. That is where the gap lives — goal_boundary has 30
    token-matching modules and a surface of 16, because 14 of them are prompt prose
    and module-path imports. The exit condition was aimed at a problem the metric did
    not have, and the body now says so.

    Governed scope, stated as a boundary

    Measured: the tree defines 664 vocabulary carriers; the registry governs 26
    (3.9%), and 6 carry producer evidence (0.9%).

    This tracker governs the kernel tier and does not claim the rest. Two facts follow,
    and both are boundaries rather than backlog:

    • A vocabulary outside the 26 gets no signal — not at commit time, and not at the
      moment it is coined
      . The guard is a full-tree scan in pytest/premerge/CI.
    • Excluding merge commits, all 23 edits to vocabulary_v0.json are by one
      author
      . No contributor has yet had to register a vocabulary because this check
      stopped them. That is consistent with a 3.9% scope, and it is why the remaining
      work is cut rather than extended.

    Remaining work: two items, both of which change production code

    1. M3 — retire protocol_action_packet. Surface 5 py / 2 ts, reader 1,
      writer 4, binding 0, unresolved 0. The only one of the six with no unknown
      use. Until a field is actually deleted, every number on this tracker is only a
      number.
    2. F1/F2 — producer evidence from 6/26. The 20 cross_runtime vocabularies
      have per-value documentation (149/149) and zero production verification.
      Those are different claims; conflating them is the failure mode this tracker
      exists to prevent.

    Further precision on the existing scan is explicitly out of scope. The
    apparatus is 4,145 lines of scanner + 4,123 lines of its own tests + a 3,506-line
    bilingual RFC, costs ~49s per run, and the debt it has actually repaid is 7
    forked names and 17 duplicate definitions
    . A fourth scanner revision does not
    remove a line of duplication.

    Not tracked here, and it should be

    @huangruiteng — your first question on this issue
    was how an agent notices it is coining a new term and decides whether it should.
    I answered it in prose
    and it was never built:

    • AGENTS.md (542 lines, read by every agent): 0 mentions of vocabulary governance
    • no skill covers it
    • the candidate_decision taxonomy the registry schema validates
      (reuse_existing, extend_vocabulary, create_vocabulary, …) is used 0 times
      in the registry
    • nothing fires at coin time; the only check is a full-tree scan at commit time

    That is a different piece of work with a different acceptance test — can an agent
    coining a term in the unregistered 96% get a signal?
    — and it needs its own issue
    rather than another milestone here. I have not opened one; say the word and I will
    draft it for your review.

    Verification

    semantic-vocabulary-drift-smoke ok · tests/architecture/ 619 passed ·
    F5 mutation-probed (injecting an owner-less projection fails closed) ·
    every number above recomputed on a quiet tree, since a concurrent suite inflates
    these counts and still prints ok.

  7. karenchuu commented on Sep 27, 2026

    @karenchuu
    Contributor

    Refs this track from outside the repo: PR #5195 single-sources fifteen module-level carriers that loopx/status.py restated with identical values, so it is a Track A increment in the shape 7f69d2d30 / #5165 / #5168 already used.

    Measured at the branch base, from the generated inventory (registry policy and the smoke's BUDGET_ANCHOR move to the same numbers in that one diff): multi_value_twins 11 → 8, same_runtime_forks 15 → 12, same_runtime_fork_definitions 35 → 28, schema_version_same_runtime_forks 5 → 2. conflicting_values and both multi-value fork counters are untouched, because no pair with different values was folded.

    Two things that need your judgement rather than a PR, and #5195 only records them instead of resolving them:

    • LIFECYCLE_PRIORITY is the one counted twin in loopx/status.py this change deliberately left in two definitions. No repository caller reaches it through the facade, so registering it as an identity alias would add a _PUBLIC_COMPAT_REEXPORTS entry that test_public_facade_compatibility_entries_have_contract_evidence rejects for want of a consumer, while dropping the facade attribute would be a public removal. It is also the example this RFC uses for order-sensitive identity, so retiring the pair edits documented text as well as code.
    • Three names lose their facade copy but are still restated by modules outside the facade: AGENT_LANE_PROGRESS_SCOPE (4 declarers left), SECTION_HEADING_PATTERN (2) and STATUS_CONTRACT_SIGNAL_LIMIT (2). refactor(status): single-source the carriers the facade restated #5195 pins those exact paths in a test so a further copy fails rather than blending in.
  8. huangruiteng commented on Sep 27, 2026

    @huangruiteng
    Collaborator

    The task-issue format used here is now being reused across the accepted RFC portfolio: 39-RFC task map, with 17 new RFC-level tasks and 22 existing records reused.

    This does not widen #4447 into an all-RFC governance task. It retains its existing convergence/source-evidence and compatibility scope; #4743 retains coin-time decisions, and #5136 retains private-text policy ownership. Contributors can choose another RFC’s linked task without duplicating this program or the active TS/shared-authority migrations.

  9. Duang777 commented on Sep 29, 2026

    @Duang777
    Collaborator

    Claiming one bounded Track A successor from #5195, not the whole tracker.

    Baseline checked: current main at ee1ea64b0. I also checked the open PR file sets; none currently touches the files in this slice.

    Scope:

    • Single-source MONITOR_SIGNAL_WAITING_ON in loopx/control_plane/status/monitor_display_projection.py. attention_projection.py and goal_attention_projection.py pass the same value into the same status/read-model contract and will import the owner instead of declaring it again.
    • Single-source SECTION_HEADING_PATTERN in loopx/control_plane/status/active_state_projection.py, matching the owner already recorded by test_status_facade_vocabulary_owners.py; loopx/state_projection.py will import it.
    • Single-source STATUS_CONTRACT_SIGNAL_LIMIT in loopx/control_plane/status/contract_projection.py, also matching the recorded owner; loopx/diagnose.py will import it for the same contract error/warning truncation rule.

    The expected code result is four fewer module-level declarations. The string-carrier inventory should move same_runtime_forks 12 to 11, same_runtime_fork_definitions 28 to 25, and same_runtime_forks_semantic 10 to 9. The regex and integer carriers are outside that string inventory, so their exact declarer sets remain enforced by the focused ownership test rather than being presented as inventory reductions.

    Validation will cover the focused owner/declarer test, the attention/goal-attention/monitor-display and active-state/status-contract read-model smokes, the semantic vocabulary drift smoke, and relevant status/diagnose pytest cases. No public schema value, CLI behavior, persistence format, or new module is planned.

    Out of scope: AGENT_LANE_PROGRESS_SCOPE while #5280 and #5117 touch two of its declarers; LIFECYCLE_PRIORITY; M3 field retirement; scanner changes; and any TypeScript migration.

    Refs #4447 Track A and the explicit remaining-carrier record in #5195. If either recorded owner should change, please flag that before implementation; otherwise I will proceed with this bounded slice.

  10. Duang777 commented on Sep 29, 2026

    @Duang777
    Collaborator

    Implementation is now open as #5285 at exact head e4d055289114ae41ce74a33f67a0ce373f0b65f6.

    The bounded slice removes the four duplicate declarations described above. Focused ownership and import-boundary tests, 598 status-neighborhood tests, 139 semantic architecture tests, five real read-model smokes, Ruff, Mypy, the semantic vocabulary smoke, and the 18-check premerge gate all pass. The PR does not include AGENT_LANE_PROGRESS_SCOPE, LIFECYCLE_PRIORITY, M3 retirement, scanner changes, or TypeScript migration.

  11. Duang777 commented on Sep 29, 2026

    @Duang777
    Collaborator

    PR #5285 now points to exact head 8274afe2f7a9a46c1d456a7dc92e1f63da3f4413. Self-review found and fixed one latent same-owner gap: project_asset.py retained differently named monitor defaults. Those defaults are removed, production builders now receive the monitor signal and stop condition from monitor_display_projection.py, and a red-green mutation test proves the values propagate through the real goal-attention project-asset path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions