Task ID or area
area: semantics / control-plane vocabulary — coin-time decision signal (follow-up to #4447)
Technical direction
Core control-plane hardening; Architecture and research incubator
Intent
Open the question #4447's 2026-09-18 tracker update named but deliberately did not track: "how an agent notices it is coining a new term and decides whether it should". That update states the acceptance test — can an agent coining a term in the unregistered majority get a signal? — and says it needs its own issue rather than another milestone on the convergence tracker. This is that issue. It is a design request for maintainer direction; I am not starting implementation before one.
Credit where the measurement is due: the census numbers below are @songoow's, recomputed on 092a28c4e in that comment. Everything marked measured here I re-ran on current main myself.
Goal and acceptance gap
The apparatus classifies a shared vocabulary after it has already drifted. Nothing asks the question at the moment the term appears.
Measured here on current main:
loopx/semantics/vocabulary_v0.json registers 26 vocabularies, each carrying meaning, tier, status, owners, values, value_notes; coverage_floor records vocabularies: 26, owner_symbols: 51, literal_scan_fields: 1. Only 6 declare producers and 1 declares literal_scan — consistent with the tracker's "6 carry producer evidence (0.9%)" against 664 vocabulary carriers in the tree.
- The disposition taxonomy already exists and is already validated for shape:
formal_model.candidate_decisions = compatibility_only, create_vocabulary, extend_vocabulary, external_input, local_only, reuse_existing, unknown, default unknown. Its own meaning says it is advisory with "no per-candidate storage or runtime enforcement".
- The string
candidate_decision occurs in the registry exactly once — at its own definition. No vocabulary records the disposition it was admitted under.
- The one live consumer is review-time, not coin-time:
loopx/capabilities/pr_review_queue/result_check.py:158 reads candidate_decision, and that capability's README requires it for aligned / new_semantics_justified / advisory / not_yet_proven rows. So the label is asked for when a change is already up for review.
- The instruction surfaces that every agent reads before writing code mention vocabulary governance 0 times:
grep -ci vocabular → AGENTS.md 0, CONTRIBUTING.md 0, docs/development/testing-and-quality.md 1.
- The only firing check is the full-tree scan at commit/premerge/CI time. On a source checkout without
npm ci --ignore-scripts, examples/semantic-vocabulary-drift-smoke.py does not even reach a verdict: it aborts after ~9s inside loopx/semantics/production.py:140 with TypeScript production parser failed. A coin-time signal that inherits that dependency cannot run where agents actually work.
So the gap is not a missing enum, a missing scanner, or a missing document. It is that the only moment the system speaks is after the term exists in code, reviewed by someone else, at full-tree cost — and on some machines not at all.
Proposed scope
Three boundaries, each independently testable, and none of them a fourth scanner revision (#4447 rules further scan precision out of scope; the existing apparatus is already ~4,145 lines of scanner plus ~4,123 of its own tests plus a ~3,506-line bilingual RFC, and it has repaid 7 forked names and 17 duplicate definitions).
- Registration admits a disposition. A vocabulary entry in
vocabulary_v0.json carries which candidate_decisions value it was coined under, validated by the check that already validates that file. This closes "the taxonomy is defined and used zero times" without new machinery, and it keeps coverage_only_grows honest because a new create_vocabulary is then distinguishable from an extend_vocabulary after the fact.
- A diff-scoped probe, not a wider scan. Reuse the on-demand inventory the RFC's Q9 already chose: given changed paths, report newly-appearing classification literals that collide with or duplicate a registered vocabulary's value set, and print the disposition question. Cost proportional to the diff. Explicitly not: a resident watcher, a new store, or a second source of vocabulary truth.
- Say it where agents read. One obligation paragraph in
AGENTS.md (and the matching pointer from CONTRIBUTING.md): coining a state-classification or protocol literal names its disposition and reuses an existing owner or justifies a new one. Whether that is machine-enforced or guidance must be stated as such in the text, per the repository's own guidance-versus-obligation rule — I would start with guidance plus the probe, and only promote to enforced once the probe's false-positive rate is measured.
Decisive acceptance question, in the form the tracker asked for: can an agent coining a term in the unregistered majority get a signal, does it arrive before the commit-time full-tree scan, and what does it cost? A fixture answers the first two; a timed run against a changed-files set answers the third.
Intended base branch
main.
Relevant files or commands
loopx/semantics/vocabulary_v0.json (formal_model.candidate_decisions, coverage_floor, policy)
examples/semantic-vocabulary-drift-smoke.py (registry shape validation today)
scripts/generate_semantic_inventory.py (the on-demand inventory Q9 selected)
docs/architecture/rfcs/semantic-vocabulary-convergence-v0.md (+ .zh-CN), §10 policy record
AGENTS.md, CONTRIBUTING.md, docs/development/testing-and-quality.md
loopx/capabilities/pr_review_queue/result_check.py (existing candidate_decision consumer)
Validation plan
Not executed — this issue proposes, it does not deliver. The plan for whichever slice is admitted:
| Slice |
Decisive validation |
| Registry disposition |
examples/semantic-vocabulary-drift-smoke.py green with the field present, plus a mutation case: a vocabulary whose admitted_as is not one of the seven values fails closed. Existing 26 entries keep passing without rewriting history. |
| Diff-scoped probe |
A synthetic changed-file that coins a term colliding with a registered value set produces the disposition question and exits non-zero; the same file with an explicit reuse_existing justification passes. Timed against a normal-size diff and reported. |
| Instruction surfaces |
examples/docs-governance-smoke.py plus the existing locale-parity check, and the public/private scan over the changed doc paths. |
| Cross-cutting |
tests/architecture/, and one run on a checkout without npm ci so the probe's dependency floor is explicit rather than assumed. |
Public/private boundary
Questions for the owner and @songoow
- Is the registry-disposition field (1) welcome as a standalone first PR, or should it wait for (2) so the value is produced by a real caller rather than back-filled?
- Should the probe live behind
loopx check, behind the existing inventory script, or as a pr_review_queue input — the last option reuses the consumer that already asks for candidate_decision at review time.
- Guidance or enforcement for
AGENTS.md: the review lenses flag prose-only obligations, so I would rather state it as guidance plus a machine-checked probe than write a machine-enforced-sounding sentence that nothing enforces.
Task ID or area
area: semantics / control-plane vocabulary — coin-time decision signal (follow-up to #4447)
Technical direction
Core control-plane hardening; Architecture and research incubator
Intent
Open the question #4447's 2026-09-18 tracker update named but deliberately did not track: "how an agent notices it is coining a new term and decides whether it should". That update states the acceptance test — can an agent coining a term in the unregistered majority get a signal? — and says it needs its own issue rather than another milestone on the convergence tracker. This is that issue. It is a design request for maintainer direction; I am not starting implementation before one.
Credit where the measurement is due: the census numbers below are @songoow's, recomputed on
092a28c4ein that comment. Everything marked measured here I re-ran on currentmainmyself.Goal and acceptance gap
The apparatus classifies a shared vocabulary after it has already drifted. Nothing asks the question at the moment the term appears.
Measured here on current
main:loopx/semantics/vocabulary_v0.jsonregisters 26 vocabularies, each carryingmeaning,tier,status,owners,values,value_notes;coverage_floorrecordsvocabularies: 26,owner_symbols: 51,literal_scan_fields: 1. Only 6 declareproducersand 1 declaresliteral_scan— consistent with the tracker's "6 carry producer evidence (0.9%)" against 664 vocabulary carriers in the tree.formal_model.candidate_decisions=compatibility_only,create_vocabulary,extend_vocabulary,external_input,local_only,reuse_existing,unknown, defaultunknown. Its ownmeaningsays it is advisory with "no per-candidate storage or runtime enforcement".candidate_decisionoccurs in the registry exactly once — at its own definition. No vocabulary records the disposition it was admitted under.loopx/capabilities/pr_review_queue/result_check.py:158readscandidate_decision, and that capability's README requires it foraligned/new_semantics_justified/advisory/not_yet_provenrows. So the label is asked for when a change is already up for review.grep -ci vocabular→AGENTS.md0,CONTRIBUTING.md0,docs/development/testing-and-quality.md1.npm ci --ignore-scripts,examples/semantic-vocabulary-drift-smoke.pydoes not even reach a verdict: it aborts after ~9s insideloopx/semantics/production.py:140withTypeScript production parser failed. A coin-time signal that inherits that dependency cannot run where agents actually work.So the gap is not a missing enum, a missing scanner, or a missing document. It is that the only moment the system speaks is after the term exists in code, reviewed by someone else, at full-tree cost — and on some machines not at all.
Proposed scope
Three boundaries, each independently testable, and none of them a fourth scanner revision (#4447 rules further scan precision out of scope; the existing apparatus is already ~4,145 lines of scanner plus ~4,123 of its own tests plus a ~3,506-line bilingual RFC, and it has repaid 7 forked names and 17 duplicate definitions).
vocabulary_v0.jsoncarries whichcandidate_decisionsvalue it was coined under, validated by the check that already validates that file. This closes "the taxonomy is defined and used zero times" without new machinery, and it keepscoverage_only_growshonest because a newcreate_vocabularyis then distinguishable from anextend_vocabularyafter the fact.AGENTS.md(and the matching pointer fromCONTRIBUTING.md): coining a state-classification or protocol literal names its disposition and reuses an existing owner or justifies a new one. Whether that is machine-enforced or guidance must be stated as such in the text, per the repository's own guidance-versus-obligation rule — I would start with guidance plus the probe, and only promote to enforced once the probe's false-positive rate is measured.Decisive acceptance question, in the form the tracker asked for: can an agent coining a term in the unregistered majority get a signal, does it arrive before the commit-time full-tree scan, and what does it cost? A fixture answers the first two; a timed run against a changed-files set answers the third.
Intended base branch
main.Relevant files or commands
loopx/semantics/vocabulary_v0.json(formal_model.candidate_decisions,coverage_floor,policy)examples/semantic-vocabulary-drift-smoke.py(registry shape validation today)scripts/generate_semantic_inventory.py(the on-demand inventory Q9 selected)docs/architecture/rfcs/semantic-vocabulary-convergence-v0.md(+.zh-CN), §10 policy recordAGENTS.md,CONTRIBUTING.md,docs/development/testing-and-quality.mdloopx/capabilities/pr_review_queue/result_check.py(existingcandidate_decisionconsumer)Validation plan
Not executed — this issue proposes, it does not deliver. The plan for whichever slice is admitted:
examples/semantic-vocabulary-drift-smoke.pygreen with the field present, plus a mutation case: a vocabulary whoseadmitted_asis not one of the seven values fails closed. Existing 26 entries keep passing without rewriting history.reuse_existingjustification passes. Timed against a normal-size diff and reported.examples/docs-governance-smoke.pyplus the existing locale-parity check, and the public/private scan over the changed doc paths.tests/architecture/, and one run on a checkout withoutnpm ciso the probe's dependency floor is explicit rather than assumed.Public/private boundary
Questions for the owner and @songoow
loopx check, behind the existing inventory script, or as apr_review_queueinput — the last option reuses the consumer that already asks forcandidate_decisionat review time.AGENTS.md: the review lenses flag prose-only obligations, so I would rather state it as guidance plus a machine-checked probe than write a machine-enforced-sounding sentence that nothing enforces.