diff --git a/docs/architecture/rfcs/README.md b/docs/architecture/rfcs/README.md index 958b97e401..8fb5f4d8f2 100644 --- a/docs/architecture/rfcs/README.md +++ b/docs/architecture/rfcs/README.md @@ -70,6 +70,19 @@ changes. - **Current boundary:** Stage 1 and 2A are complete. Stage 2B is cutting over whole semantic transactions and retiring Python facades under parity and differential gates. +- [Semantic Vocabulary Convergence and Commit-Time Drift Checks v0](semantic-vocabulary-convergence-v0.md) + ([中文版](semantic-vocabulary-convergence-v0.zh-CN.md)) + - **RFC status:** Draft. + - **Delivery on `main`:** M0 registry, generated inventory, and drift smoke + shipped with the RFC. + - **Current boundary:** Repository-wide. A curated registry names 26 kernel + and cross-runtime vocabularies with `module::Symbol` owners, relations, + the route-to-disposition projection, the Turn Envelope schema owner, and + ratchets for legacy should-run fields, py/ts twins, and constant forks; a + generated inventory maps every other closed-set carrier under `loopx/`; a + public smoke fails closed on drift in either runtime and on any narrowing + of the registry itself. No enum merge, slot split, field removal, or code + generation is approved yet. - [Shared-goal Online Authority and Pluggable Coordination Provider v0](shared-goal-authority-state-provider-v0.md) ([中文版](shared-goal-authority-state-provider-v0.zh-CN.md), [validation boundary](shared-goal-authority-state-provider-v0-evidence.zh-CN.md)) diff --git a/docs/architecture/rfcs/semantic-vocabulary-convergence-v0.md b/docs/architecture/rfcs/semantic-vocabulary-convergence-v0.md new file mode 100644 index 0000000000..17a18ab371 --- /dev/null +++ b/docs/architecture/rfcs/semantic-vocabulary-convergence-v0.md @@ -0,0 +1,664 @@ +# RFC: Semantic Vocabulary Convergence and Commit-Time Drift Checks (v0) + +- **RFC status:** Draft +- **Delivery maturity:** Partial (M0 registry, generated inventory, and drift smoke ship with this RFC) +- **Authors / owners:** LoopX contributors; control-plane kernel maintainers own approval +- **Created:** 2026-09-15 +- **Last normative revision:** 2026-09-15 +- **Implementation baseline:** `1dc6ad8d8` +- **Related contracts:** `loopx/semantics/vocabulary_v0.json`, + `loopx/semantics/inventory_v0.json`, + `loopx/control_plane/turn_transaction_contract.json`, + `loopx/control_plane/coordination/coordination_state_contract_v0.json`, + [Turn Envelope v0](../../reference/protocols/turn-envelope-v0.md), + [Turn Loop Controller v0](../../reference/protocols/turn-loop-controller-v0.md), + [TypeScript Control-Plane Migration v0](typescript-control-plane-migration-v0.md) +- **Language mirror:** [中文版](https://github.com/huangruiteng/loopx/blob/main/docs/architecture/rfcs/semantic-vocabulary-convergence-v0.zh-CN.md) + +## Document map and maintenance contract + +This RFC ships an English document and a `semantic-vocabulary-convergence-v0.zh-CN.md` +semantic mirror; both carry a language link and must be revised together when a +normative section changes. + +- Sections 1-10 are the durable design and acceptance contract. +- Section 11 is the normative delivery plan. +- Section 12 contains unresolved decisions; proposed answers are not approval. +- Appendices hold the non-normative execution ledger, decision log, evidence + registry, and rejected alternatives. + +RFC maturity and delivery maturity are independent. Dated progress entries do +not amend normative sections. + +--- + +## 1. Decision summary + +1. **What becomes authoritative.** Two files under `loopx/semantics/`. The + curated registry `vocabulary_v0.json` names each kernel and cross-runtime + vocabulary, the exact `module::Symbol` allowed to define it, the relations + between vocabularies (same concept, shared field name, subset), the total + projections, and the budgets the repository ratchets down. The generated + inventory `inventory_v0.json` maps every closed-set carrier under `loopx/`: + string enums, `Literal` aliases, named closed sets, TypeScript `as const` + arrays, and every constant name defined in more than one module. A public + smoke, `examples/semantic-vocabulary-drift-smoke.py`, checks the code against + both on every premerge and full-public run. A change that widens a + vocabulary, forks a constant, adds a carrier, or weakens the registry must + edit the registry or regenerate the inventory in the same diff, so the + reviewer sees the semantic change as a change. +2. **What remains unchanged.** Runtime behavior, wire formats, and the enum + classes themselves. Each enum keeps living in its owner module; the registry + is checked against code by AST and text scan, it does not generate code and + product code never imports it. +3. **Default and opt-in boundary.** The check is always on for the repository. + It has no runtime flag because it never runs inside the product. +4. **Principal constraint.** Fail closed, deterministic, and not weakenable by + a data edit alone. An unregistered literal in either runtime, a second + defining module, a budget overrun, a registry value no module carries, a + stale inventory, an owner declared without a symbol, or a coverage count + below the recorded floor each fails the smoke. The dispatch forms the scan + recognises live in the smoke, not in the registry. The smoke reads only + tracked sources and prints no private data. +5. **Not approved by this RFC.** Merging the three Turn outcome enums into one, + splitting the three `effective_action` slots, deleting any legacy should-run + field, deleting any Python twin module, or renaming any existing value. + Those are later milestones with their own gates under the schema-reduction + rule in `AGENTS.md`. + +## 2. Problem and motivation + +LoopX has grown by many small agent-driven PRs. Each PR added the vocabulary it +needed where it needed it. The result is not wrong behavior but drift: the same +concept spelled several ways, the same constant defined in several files, the +same field name carrying different vocabularies, and open string sets that any +module may widen without anyone noticing. Reviewers cannot tell from a diff +whether a new literal is a new state or a typo, and documentation cannot stay +in step with a set nobody enumerates. + +The semantic surface is repository-wide, not a Turn-kernel problem. Measured on +the baseline by the inventory generator over 1169 source files under `loopx/`: + +| Carrier | Count | Notes | +| --- | --- | --- | +| Python string enums | 102 | 29 in the control plane, 17 in capabilities, 6 in extensions | +| Named closed sets (`NAME = frozenset/tuple` of strings) | 490 | 66 are field lists, 31 kinds, 31 states, 29 statuses | +| `Literal[...]` aliases | 8 | | +| TypeScript `as const` arrays | 40 | 21 have an equal Python set; 14 have none | +| Named string constants | 2002 | 754 are `*_SCHEMA_VERSION` | +| Same name, same value, two runtimes | 166 | legitimate py/ts twins | +| Same name, same value, one runtime | 25 names / 58 definitions | forks; 7 are schema versions | +| Same name, different values | 18 names / 59 definitions | see below | + +Concrete failures audited on the baseline: + +- `TURN_ENVELOPE_SCHEMA_VERSION` was defined three times: + `loopx/control_plane/quota/turn_envelope.py:16`, + `loopx/control_plane/quota/turn_envelope.ts:13`, and a private copy in + `loopx/control_plane/turn_driver/driver.py:31`. M0 removes the copy. +- `HANDOFF_MODES` was defined by the TypeScript owner and again as a literal + tuple in `control_plane/testing/authority_e2e_fixtures.py:33`. M0 derives the + fixture tuple from the `HandoffMode` enum. +- The same value set carries two names across runtimes: + `MATERIAL_DELIVERY_OUTCOMES` in `work_items/delivery_outcome.ts` equals + `VISION_OUTCOME_CHECKPOINT_MATERIAL_OUTCOMES` in + `goals/goal_frontier/outcome_continuity.py`. Both equal `DeliveryOutcome` + minus `surface_only`; nothing said so. +- Conflicting definitions with the same name: `DECISION_CONTEXT_CAPABILITY_ID` + is `decision_context` in `capabilities/decision_context/packets.py:18` and + `decision-context` in `extension_provider.py:24`; `MCP_REQUIREMENT` is + `mcp==1.28.1` in `kunluncode_goal_mode/cli.py:28` and `mcp<2` in + `claude_goal_mode/scripts/install.py:83`. Sixteen further names are generic + module-local constants (`SCHEMA_VERSION`, `COMMAND`, `CAPABILITY_ID`) whose + collision is harmless today and invisible tomorrow. +- The Turn result kinds exist twice by hand: `LoopXTurnResultKind` in + `transaction.py:28` and `TURN_RESULT_KINDS` in `settlement.ts:49`. They + match; no test asserted it. The same holds for eleven other py/ts pairs + (settlement step, binding and failure kinds, receipt-bound phases, scheduler + transitions, Todo completion continuation and recovery, delivery outcome, + delivery workspace kinds, Goal amendment classes, Todo decision scopes). +- `effective_action` is an open string set with no enum on either runtime. + Thirty-one distinct literals are dispatched on by string comparison in + Python and TypeScript. Two of them (`observe_replay`, `block_replay`) are + written by `turn_journal.ts:656` into the replay observation slot of the + Turn Envelope and are not should-run verdicts at all. Two more + (`quota_action_selection_deferred`, `quota_action_selection_rejected`) are + quota error codes that `cli_commands/quota.py:279` copies into the slot. + `AgentScopeFrontierAction` values are written into the + `agent_scope_frontier.effective_action` slot of the same envelope. One field + name, three vocabularies. `user_gate.py:162` compares the slot against + `skip`, which no producer writes. +- Three near-isomorphic Turn outcome vocabularies coexist: + `LoopXTurnResultKind` (12), `LoopXTurnRoute` (8), `LoopDisposition` (8), + with `repair`/`repair_required` and `replan`/`replan_required` as different + spellings of one verdict. The route-to-disposition projection is a private + dictionary in `loop_controller.py:126`; nothing declared that it is total. + The load-bearing table in `decide_loop_disposition` (result kind, retryable, + attempt budget, decision user action, durable no-follow-up) exists only as + prose in the controller protocol document. +- Six should-run decision fields the documentation already calls legacy are + still mentioned by 7 to 35 Python modules each, with no ratchet stopping new + consumers. +- 43 same-basename `.py`/`.ts` module pairs exist under `loopx/control_plane` + while the migration RFC is replacement-first. The count had no guard. +- The repository already runs an AST-backed control-plane debt ratchet + (`loopx/canary/maintainability_ratchet.py`) with a reviewed exception + lifecycle, but it measures module metrics and dependency direction, not + vocabulary shape. Vocabulary drift had no ratchet. + +The current owners cannot solve this locally because every fix is +cross-module by definition: the Turn driver, quota, todos, capabilities, and +the TypeScript runtime each own one spelling of the same idea. + +### Invariants + +- **I1 Single owner.** Every registered vocabulary or constant has exactly the + defining modules the registry lists, and the registered symbol name is + defined nowhere else under `loopx/`. Everyone else imports. +- **I2 Closed sets.** Every value a registered vocabulary may carry is listed. + The code carries no unregistered value in either runtime and the registry + lists no value the code does not carry. +- **I3 Cross-runtime parity.** When a vocabulary has a Python and a TypeScript + owner, both carry the identical set. +- **I4 Total projections.** A registered projection names every source value + exactly once, either mapping it or declaring it rejected. +- **I5 Ratchets only fall.** Retirement, twin, and inventory budgets may be + lowered in any PR. Each budget is additionally pinned by a `BUDGET_ANCHOR` + (or `RETIREMENT_ANCHOR`) literal inside the smoke, and each floor by a + `COVERAGE_ANCHOR`, following the `RFC_MODULE_BUDGETS` anchor pattern in + `tests/control_plane/test_m6_quality_gates.py`, with one deliberate + difference: the registry value must **equal** the anchor. The precedent + compares with `<=`, which lets a budget tightened below the anchor be raised + back to the anchor later without any code edit. Equality makes every + tightening a two-file diff and every loosening a code edit a reviewer sees. +- **I6 Same-diff visibility.** A semantic change and its registry edit or + inventory regeneration land in one reviewable diff. +- **I7 Deterministic and public-safe.** The check reads tracked sources only, + needs no network or credentials, and its failure text names files and + values, never private data. +- **I8 Coverage only grows.** The number of registered vocabularies, owner + symbols, projections, relations, schema versions, and scanned suffixes is + recorded as a floor. An owner is `module::Symbol` or `null`; a bare module + path is rejected, and a null owner requires a literal scan. The dispatch + forms the scan recognises are fixed in the smoke. A registry edit therefore + cannot silently narrow what the guard sees. +- **I9 Both carrier shapes are measured.** A vocabulary reaches the code either + as a string constant (`NAME = "value"`) or as a multi-value carrier (an enum, + a named closed set, a `Literal` alias, a TypeScript `as const` array). Both + get the same collision rule: one name defined in two modules with identical + values is a twin, with different values a fork. Collision budgets count the + shared-vocabulary subset only; module-local convention names such as + `SCHEMA_VERSION`, `COMMAND`, or `*_LABEL` stay visible in the inventory totals + but are not drift. +- **I10 On the pull-request path.** The drift smoke runs inside the default + `pytest` sweep through `tests/architecture/test_semantic_vocabulary_drift.py`, + so it fails closed on every pull request that runs the Python tests. Fleet + discovery under `examples/` and the `repo-architecture-budget` premerge + profile are additional surfaces, not the obligation: the fleet runs after + merge and on a schedule, and premerge selects by changed-path tokens. + +## 3. Scope and non-goals + +### In scope + +- The registry file, its schema, and the ownership rule for editing it. +- The generated inventory, its generator with `--check`, and its unit test. +- The drift smoke and its placement in the premerge and full-public fleets. +- The vocabularies registered at M0: the four Turn-kernel sets + (`turn_result_kind`, `turn_route`, `loop_disposition`, `effective_action`), + `agent_scope_frontier_action` and `lease_action`, and twenty cross-runtime + sets whose Python and TypeScript owners carry equal values on the baseline; + the route-to-disposition projection; nine relations; the Turn Envelope schema + version; the six legacy should-run fields; the control-plane twin count; and + the inventory fork and conflict budgets. +- The later milestones that turn `effective_action` into a typed enum, split + its three slots, publish the projection through the contract, and retire + legacy fields and twins under existing repository rules. + +### Non-goals + +- Changing any runtime decision, payload shape, or wire format. +- Curating every closed set by hand. The inventory maps all of them; only + vocabularies that cross a module or runtime boundary and are dispatched on + are curated with owners, values, and relations. +- Replacing `turn_transaction_contract.json` or + `coordination_state_contract_v0.json`. Those remain the owners of their + phases and records; this registry may reference them, not restate them. +- Replacing `maintainability_ratchet.py`. It owns module metrics and dependency + direction; this registry owns vocabulary shape. Whether their exception + lifecycles merge is Section 12, Q7. +- A prose glossary as the enforcement mechanism. A glossary is a useful + companion and is tracked in Section 12, but it cannot fail a build. + +## 4. Current-system contract + +Facts on baseline `1dc6ad8d8`: + +- `turn_transaction_contract.json` is the one contract read by both runtimes: + `effect_program.py:160-166` loads the phase tuple and + `turn_journal.ts:1` imports the JSON. This is the template the registry + follows for a shared source of truth. +- `coordination_state_contract_v0.json` goes further and generates + `coordination_state_contract_generated.py` and + `coordination_state_contract.generated.ts` through + `scripts/generate_coordination_state_contract.py --check`, guarded by + `tests/control_plane/test_coordination_state_contract.py`. This is the + template the inventory generator follows now and the generation stage + proposed in M2 follows later. +- The canary runner discovers every tracked `examples/**/*-smoke.py` + (`loopx/canary/runner.py:392`), so a smoke at `examples/` needs no + registration in `planner.py` or `premerge.py`. +- `loopx/canary/maintainability_ratchet.py` is the existing AST-backed + control-plane debt ratchet. It carries reviewed exceptions with a + `retirement_plan` and detects stale exception ids. Its subject is module + size, `Any` density, decision-point counts, and forbidden dependency + direction; it does not read enum or constant values. +- `AGENTS.md` already requires typed enums for state classification, forbids a + second source of truth in Python for control-plane authority, requires a + scope-fit review before adding a module, and requires maintainer approval for + any schema reduction. This RFC adds the check that makes those rules + observable in a diff; it does not change them. +- Package data for `loopx.control_plane` already ships `*.json`; + `pyproject.toml` gains one line so `loopx.semantics` ships its two JSON files + the same way. + +## 5. Proposed architecture + +### Ownership and authority + +The registry is owned by the control-plane kernel maintainers. Any contributor +may lower a budget or add a value together with the code that carries it. Only +a maintainer may approve raising a budget, removing a value, or moving an owner +module, and the approval is recorded in Appendix B. + +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. + +### State model and schema + +`loopx/semantics/vocabulary_v0.json`, `schema_version` +`loopx_semantic_vocabulary_v0`. The key set is closed; an unknown top-level or +vocabulary key fails the smoke. + +| Key | Content | Check | +| --- | --- | --- | +| `coverage_floor` | counts of vocabularies, owner symbols, literal-scan fields, projections, relations, schema versions; the scanned suffix set | Actual counts are at or above the floor, declared suffixes cover the floor set, and each floor equals its `COVERAGE_ANCHOR` (I8) | +| `vocabularies..owners` | `python` and `typescript`, each `path::Symbol` or `null` | Enum members, closed-set members, `Literal` alias, or `as const` array equal `values`; the symbol is defined only in owner modules (I1, I2, I3) | +| `vocabularies..tier`, `status` | `kernel`, `cross_runtime`, `cross_module`; `canonical`, `legacy`, `merge_candidate` | Closed enumerations | +| `vocabularies..literal_scan` | `field`, roots, suffixes | Every literal the fixed dispatch forms capture is registered; every registered value is captured or variable-sourced (I2) | +| `vocabularies..variable_sourced_values` | value to producer module | The producer still contains the quoted value | +| `vocabularies..value_notes`, `deprecated_values` | per-value review notes; values slated for removal | Names must be registered values | +| `relations.same_concept` | groups of `vocabulary.value` members | Every member resolves | +| `relations.shared_field_names` | one field name, its slots and the vocabulary or values each carries | Every slot resolves | +| `relations.subsets` | superset vocabulary, excluded values, owners of the subset symbol | Owner symbols equal superset minus excluded | +| `projections..mapping` | source value to target value or `null` | Keys equal the source vocabulary; mapped values match the owner function; `null` routes raise (I4) | +| `schema_versions.` | constant name, value, owner modules | The only defining modules are the listed owners and all carry the value (I1) | +| `retirement_ledger..fields` | per-field Python and TypeScript module budgets | Actual module counts are at or below budget, and the field set and every budget match `RETIREMENT_ANCHOR` (I5) | +| `dual_runtime_twins` | root and module budget | Tracked same-basename `.py`/`.ts` pair count is at or below budget; root and budget equal their code anchors (I5) | +| `inventory_ratchets` | budgets for same-runtime fork names and definitions, conflicting names and definitions, schema-version forks, multi-value twins and forks, and the shared-vocabulary conflict and fork subsets | Inventory summary counts are at or below budget, and each budget equals its `BUDGET_ANCHOR` entry (I5, I9) | + +`loopx/semantics/inventory_v0.json`, `schema_version` +`loopx_semantic_inventory_v0`, is generated by +`scripts/generate_semantic_inventory.py` and must equal a fresh build. It +lists Python enums, closed sets, `Literal` aliases, TypeScript `as const` +arrays, and duplicate definitions split into cross-runtime twins, same-runtime +forks, conflicting values, and multi-value twins and forks, one entry per line. +Every multi-value collision carries each defining module and its value set, so +the divergence itself is reviewable rather than only its count. Consumer counts are printed by `--report`; merge-candidate groups are available +through `merge_candidate_groups` and not committed, so an +ordinary consumer edit does not touch the file; merge candidates are advisory +because an equal value set is not proof of one concept. Single-module string +constants are counted, not listed. + +Values are additive. Removing a value, a field, an owner, or a relation is a +schema reduction and follows the `AGENTS.md` rule: enumerate the affected +surfaces, research producers and readers, lower the floor in the same diff, and +record maintainer approval. + +### Command or event lifecycle + +The check has one command: run the smoke. It is idempotent and has no side +effects. Failure text names the vocabulary, the offending files, and the values +so the fix is mechanical: register the value, import the constant, or lower the +scope of the change. + +### Provider or extension contract + +New vocabularies are added by a PR that adds the registry entry, raises the +coverage floor, and, where a TypeScript owner exists, names its `as const` +array. A vocabulary qualifies for curation when it is dispatched on by more +than one module or crosses the Python/TypeScript boundary; everything else is +mapped by the inventory without curation. Adding any carrier regenerates the +inventory in the same PR. + +## 6. Alternatives and design choices + +| Alternative | Why not now | +| --- | --- | +| Unify the three Turn enums into one in a single PR | Breaks I5 style incrementalism; the three enums have different owners and change reasons (settlement, route, controller). Register and project first, then merge only where a projection proves identity (Section 12, Q2). | +| Rely on `mypy` `Literal` types | Does not cover TypeScript, JSON payloads, or the CLI; the drift here lives at exactly those boundaries. | +| Documentation glossary only | Cannot fail a build; the repository already has eleven documents calling themselves a mental model and no glossary, which is the symptom. | +| Generate bindings from the registry immediately | Premature until owners are settled. Generation is M2 and follows the coordination contract precedent. | +| Grep-based lint in CI without a registry | Encodes the allowed set in the linter, which becomes a second registry with no review trail. | +| Extend `maintainability_ratchet.py` instead of a new registry | Its subject is module metrics and dependency direction with per-module ceilings; vocabulary shape needs values, owners, and relations. The two share the ratchet idea, not the data model. Merging exception lifecycles is Q7. | +| Put the scan regex in the registry | A regex in data can be narrowed in the same edit that widens a vocabulary; the M0 review showed the first pattern missed every TypeScript `===` site. Forms are fixed in the smoke and the suffix set is floored. | +| Commit consumer counts in the inventory | Every consumer edit would churn the file and make the freshness check noise. Counts stay advisory via `--report`. | + +## 7. Safety, privacy, and compatibility + +- No runtime path imports the registry at M0; product behavior is unchanged + with the check present or absent. +- The scanner uses `git ls-files --cached -z` and reads the indexed source paths + from the working tree. Untracked and ignored files are excluded; stage a new + source path before regenerating the inventory. Tracked symlinks and invalid + Python syntax fail closed. A checkout with Git metadata is required. +- Literal and TypeScript carrier scans recognize both single and double quotes. + They remain structural text scans, not complete parsers or data-flow analysis. +- Literal-scan roots and suffixes, and the twin root and budget, are anchored in + code. JSON alone cannot narrow these scopes or raise the twin budget. +- Failure text uses repository-relative source paths and registered identifiers. +- Legacy readers and writers are untouched. Budgets freeze their current spread + without removing a single reference. +- Mixed versions are not a concern for a build-time check. When M2 introduces + generated bindings, the generator's `--check` mode and the smoke both run so + a stale generated file cannot merge. + +## 8. Migration and rollback + +- **Admission.** M0 lands with the registry and inventory matching the + baseline exactly, plus two behavior-preserving edits so the owner check is + green: the duplicate `TURN_ENVELOPE_SCHEMA_VERSION` in `driver.py` becomes an + import, and the `HANDOFF_MODES` tuple in the authority e2e fixtures is + derived from the `HandoffMode` enum. +- **Rollback.** Deleting the smoke, the `loopx/semantics/` package, the + generator, its test, and the `pyproject.toml` line restores the previous + state with no runtime effect. Later milestones each carry their own rollback + in Section 11. +- **Point of no return.** None in M0. M3 field removals are the first + irreversible step and are gated individually. + +## 9. Validation and acceptance + +| Claim | Test or evidence | Required result | Boundary / exclusions | +| --- | --- | --- | --- | +| Registry and inventory match the code at baseline | `python3.11 examples/semantic-vocabulary-drift-smoke.py` | `ok` with coverage, ratchet, budget, and twin report | Proves parity for registered vocabularies and mapped carriers only | +| Inventory is fresh | `python3.11 scripts/generate_semantic_inventory.py --check` | exit 0 | Structural map only | +| Scanner classification rules | `pytest tests/architecture/test_semantic_inventory.py` | pass | Fixture repository; rules from this RFC, not from output | +| A widened `effective_action` set fails closed in Python | Add an unregistered literal via `==`, membership, or conditional expression | Failure names the value and file | Mutation exercise; not a committed test | +| A widened `effective_action` set fails closed in TypeScript | Add an unregistered literal via `===` or a ternary | Same | Same | +| A forked constant fails closed | Redefine `TURN_ENVELOPE_SCHEMA_VERSION` or `HANDOFF_MODES` in a non-owner module, regenerate the inventory | Failure lists the extra defining module or the fork budget | Same | +| Python and TypeScript owners cannot diverge | Remove one entry from a registered `as const` array, or widen a registered enum | Failure names the missing or unregistered value | Same | +| The registry cannot be weakened by data alone | Declare a bare-module owner; drop an owner; narrow suffixes to `.py`; rename a vocabulary another relation references; add an unknown key | Each fails naming the rule | Same | +| A new carrier is visible | Add an enum without regenerating | Failure says the inventory is stale | Same | +| Conflicting spellings cannot grow | Add a third value for an already-conflicting name, regenerate | Failure names the definitions budget | Same | +| A multi-value collision cannot grow | Define one closed-set name in two modules with divergent values, or with equal values, and regenerate | `multi_value_forks` or `multi_value_twins` fails naming the new name | Mutation exercise; not a committed test | +| The registry cannot relax its own ratchet | Lower any `coverage_floor` count, raise any `inventory_ratchets` budget, or raise a retirement budget, in the same diff that removes the coverage it counts | `COVERAGE_ANCHOR`, `BUDGET_ANCHOR`, or `RETIREMENT_ANCHOR` fails naming the anchored value | Mutation exercise; moving an anchor is a code edit a reviewer sees | +| A tightened budget cannot drift back to a stale anchor | Lower a registry budget without touching the anchor | Failure says the registry value and the anchor differ | Equality, not `<=`; the fix is to lower the anchor in the same diff | +| The smoke is on the pull-request path | `pytest tests/architecture/test_semantic_vocabulary_drift.py` | pass; the test is collected by the default `pytest -q` sweep in `python-tests.yml` | The fleet and premerge surfaces are not the obligation (I10) | +| Premerge selects the smoke for a `loopx/` diff | `loopx canary premerge --changed-file loopx/control_plane/turn_driver/loop_controller.py` | the plan lists `examples/semantic-vocabulary-drift-smoke.py` under `repo-architecture-budget` | Selection is by trigger hint; the pytest wrapper is the guarantee | +| Measurement covers both carrier shapes and filters local naming | `pytest tests/architecture/test_semantic_inventory.py` | pass, including the collision and module-local-convention fixtures | Rules come from this RFC, not from scanner output | +| No behavior change from the two owner fixes | `pytest tests/test_loopx_turn_transaction.py tests/test_loop_turn_loop_controller.py tests/test_turn_loop_disposition.py tests/test_loopx_turn_managed_step.py tests/control_plane -k authority` and `loopx canary premerge --from-git-diff` | pass | Environment failures already present on `main` are excluded when reproduced on a clean tree | +| Docs governance accepts the RFC pair | `python3 examples/docs-governance-smoke.py` | pass | Checks mirror, links, index | + +Known limits, stated so the check is not over-trusted: + +- **Renames launder a collision.** Collisions are keyed by name, so renaming one + side of a fork lowers the count without removing the drift. The advisory merge + report is the review aid here; value-set equality cannot be a hard budget + because `CONFIDENCE_LEVELS` and `EDGE_CASE_COMPLEXITIES` share `high/low/medium` + while meaning different things. +- **Single-element carriers are invisible.** A closed set with one string member + is not a vocabulary, so reducing a two-value set to one removes it from the + inventory entirely. +- **The literal scan can misread unrelated comparisons on the same line.** A form + such as `log("effective_action", kind === "repair_required")` is captured as an + `effective_action` value. Registering the reported value to clear the failure + would widen the vocabulary, so the correct fix is to register the field name + and the literal together or restructure the line; the failure text names the + file so this is visible in review. +- **Anchors are code, not history.** A PR can still move an anchor; it cannot do + so without editing a named literal next to the registry change. Because the + check is equality, a stale anchor is impossible, but the anchor also carries + no memory of the lowest value ever reached; that history is the git log. + +## 10. Operational contract + +The standard premerge catalog limit increases from 9 to 10 checks so the new +vocabulary check does not displace the existing heartbeat/quota coverage. Quick +and deep tier limits are unchanged. + +The check cannot affect a running system: it executes only in tests, premerge, +and CI. Its operator surface is the failure text. No observability, capacity, +or on-call contract applies. + +Where it runs, and which surface is the obligation: + +| Surface | Trigger | Selection | Role | +| --- | --- | --- | --- | +| `pytest` sweep, `python-tests.yml` | every pull request whose classification runs the Python tests | always collected via `tests/architecture/test_semantic_vocabulary_drift.py` | **The commit-time obligation (I10)** | +| `loopx canary premerge` | local, before opening a PR | `repo-architecture-budget` profile, trigger hints include `loopx/`, `examples/`, `scripts/`, `refactor` | Early local signal | +| Full public smoke fleet | push to `main`, daily schedule, manual dispatch | `examples/**/*-smoke.py` discovery | Post-merge confirmation; not a PR-required check by design | + +Before this table existed the RFC said the smoke ran "in premerge and CI". On +the baseline that was true only after merge: premerge did not select the smoke +for a diff touching `loopx/control_plane/` alone, and the fleet workflow is +deliberately not a PR-required check. A fleet-discovered smoke is not a +commit-time check until a required PR job collects it. + +## 11. Normative delivery plan + +| Milestone | Shipped behavior | Entry gate | Exit evidence | Rollback | +| --- | --- | --- | --- | --- | +| M0 | Registry with 26 vocabularies and 9 relations, generated inventory with `--check`, drift smoke with fixed dispatch forms and coverage floor, two owner forks removed, RFC index entry | This RFC opened | Section 9 rows green; 20 mutation classes fail closed | Delete the smoke, `loopx/semantics/`, the generator, and its test | +| M1 | `EffectiveAction` typed enum in one owner module; the replay observation and frontier slots split off (Q6); producers and consumers import it; registry `literal_scan` tightened to the enum | M0 merged; owner module chosen (Q3); slot split decided (Q6) | Smoke green; zero bare `effective_action` literals outside the owner; parity fixtures for status/should-run unchanged | Revert to literals; registry keeps the set | +| M2 | Route-to-disposition projection, the `decide_loop_disposition` decision table, and the cross-runtime sets published through a shared contract with generated Python and TypeScript bindings, following the coordination contract generator | M1 merged; Q2 and Q7 decided | Generator `--check` and smoke green; `settlement.ts` and `transaction.py` read the generated set | Regenerate from prior contract | +| M3 | Per-field retirement of legacy should-run fields, one field per PR, budgets lowered to zero and the field removed | Field has zero external readers proven by producer/reader research | Schema-reduction record per `AGENTS.md`; Appendix B entry | Restore field from the last writer | +| M4 | Twin budget lowered with each replacement-first cutover from the migration RFC | Each cutover PR | Budget edit in the same diff | None needed; budget follows code | + +## 12. Open decisions + +1. **Registry location.** Owner: kernel maintainers. M0 implements + `loopx/semantics/` because the scope is repository-wide and neither + `loopx/control_plane/` nor `docs/reference/` is; the package holds only the + two JSON files and the scanner and is imported by no product code. This is + a proposal until recorded in Appendix B. Needed before M1. +2. **Merge `LoopXTurnRoute` and `LoopDisposition`?** Owner: Turn driver owner. + The projection is total but not injective (`blocked` and `wait` both map to + `wait`), and `stop`, `terminal`, `contract_error` exist on one side only. + The `same_concept` relations record the four shared verdicts. + Recommendation: keep both, publish the projection in M2, revisit after the + managed-step consumer matures. Needed before M2. +3. **Owner module for `EffectiveAction`.** The registry declares no owner + today because no symbol exists; the literal scan is the only check. + Options: `quota/should_run_packet.py` (largest producer), a new + `quota/effective_action.py`, or the TypeScript `turn_envelope.ts` with a + Python import per the migration RFC. Recommendation: TypeScript owner with + generated Python binding only if M2 lands first; otherwise + `quota/effective_action.py`. Needed before M1. +4. **Companion glossary.** Whether to add `docs/reference/glossary.md` + generated from the registry `meaning` fields and the inventory. Owner: docs + maintainers. Recommendation: yes, in M1, generated so it cannot drift. +5. **Term-family naming rule.** Whether new identifiers in the `gate`, + `scope`, `packet`, `handoff`, `settlement` families must cite a glossary row + in review. This is a review rule, not a smoke; recommendation is to adopt it + in the first-review roster once the glossary exists. +6. **Split the three `effective_action` slots.** The decision slot, the + `agent_scope_frontier` slot, and the replay observation slot share one field + name in one Turn Envelope and carry three vocabularies; `skip` is compared + but never produced. Options: rename the observation and frontier slots, + or keep one field with a registered union. Owner: Turn Envelope owner. + Recommendation: rename in M1 so the enum in Q3 has one meaning. Needed + before M1. +7. **Relation to `maintainability_ratchet.py`.** Whether the inventory + ratchets adopt its reviewed exception lifecycle (`retirement_plan`, stale + exception detection) or stay plain budgets. Recommendation: adopt it in M2 + when generation lands, so a fork with a documented reason can be excepted + instead of budgeted. Owner: canary maintainers. +8. **Promotion rule from inventory to registry.** Whether a mapped carrier + with three or more external consumer modules or a cross-runtime twin must be + curated. Recommendation: yes as a review rule now, enforced by the smoke + only after a quarter of inventory history exists. Owner: kernel maintainers. + +## Appendix A: Execution ledger (non-normative) + +### 2026-09-15 — M0 opened with the RFC + +- **Baseline:** `1dc6ad8d8` +- **Delivered:** registry with four vocabularies, one projection, one schema + version, six legacy-field budgets, one twin budget; drift smoke; duplicate + `TURN_ENVELOPE_SCHEMA_VERSION` in `driver.py` replaced by an import. +- **Evidence:** Section 9 rows; see Appendix C. +- **Known gaps:** the projection check imports the private + `_route_to_disposition` until M2 publishes it. +- **Effect on normative design:** none. + +### 2026-09-15 — M0 revised after review; scope made repository-wide + +- **Baseline:** `1dc6ad8d8` +- **Trigger:** a review found the first literal scan blind to TypeScript + (`===` never matched), two unregistered values already on the baseline + (`observe_replay`, `block_replay`), and an owner check that silently skipped + any owner written without a symbol. +- **Delivered:** registry moved to `loopx/semantics/vocabulary_v0.json` and + widened to 26 vocabularies, 46 owner symbols, 9 relations, and a coverage + floor; generated inventory `inventory_v0.json` with generator `--check` and + unit test; smoke rewritten with fixed dispatch forms (comparison, assignment, + ternary, membership, conditional expression), AST-based owner resolution, + owner exclusivity, inventory freshness and fork/conflict budgets; the + `HANDOFF_MODES` fixture fork derived from the enum. +- **Evidence:** Appendix C, E6 to E10. +- **Known gaps:** the load-bearing `decide_loop_disposition` table is still + prose only (M2); the literal scan cannot attribute a literal to one of the + three `effective_action` slots (Q6); the scan cannot follow values through + variables, so two quota error codes are registered as variable-sourced with + a producer check rather than proven. +- **Effect on normative design:** Sections 1 to 5, 8, 9, 11, 12 revised; + I8 added. Recorded as the same-day revision of an unmerged draft. + +### 2026-09-15 — M0 measurement repaired after a second review + +- **Baseline:** `1dc6ad8d8` +- **Trigger:** a second review ran 14 attacks against the smoke. Seven escaped: + lowering `coverage_floor` (individually or all at once), raising + `inventory_ratchets` or a retirement budget, and — decisively — dropping an + owner *and* lowering the matching floor in one diff. The floor lived in the + same file it guarded and was compared with `>=`, so the registry could relax + its own ratchet. I5 and I8 were prose, not machine-enforced. +- **Also found:** collision detection ran only over string constants, so the 599 + multi-value carriers were listed but never compared. Four same-name forks were + already on the baseline, including `SOURCE_SURFACES` defined four times with + four different value sets, plus 19 invisible twins. Separately, 16 of the 18 + `conflicting_values` names were module-local conventions (`SCHEMA_VERSION` + sixteen times, `COMMAND`, `REQUEST_SCHEMA`, `SURFACE`), so the budget was + mostly measuring local naming. +- **Delivered:** anchors `COVERAGE_ANCHOR`, `COVERAGE_SUFFIX_ANCHOR`, + `BUDGET_ANCHOR`, `RETIREMENT_ANCHOR` in the smoke, closing all seven escapes; + `multi_value_name_collisions` giving enums, closed sets, `Literal` aliases, and + `as const` arrays the string-constant collision rule, with the four forks and + 19 twins budgeted at today's count; `MODULE_LOCAL_CONVENTION` keeping + module-local names in the visible totals but out of the semantic budgets + (`conflicting_values_semantic` 2, `same_runtime_forks_semantic` 18); advisory + merge-candidate report over the 32 groups of distinct names sharing a value + set; two scanner tests on a dedicated collision fixture; I9 added and the + Section 9 limits stated. +- **Evidence:** Appendix C, E11 to E13. +- **Known gaps:** collisions are keyed by name, so a rename still launders one; + single-element carriers are invisible; the literal scan can misread an + unrelated comparison sharing a line. +- **Effect on normative design:** I5 and I8 restated as enforced rather than + intended; I9 added; the Section 5 table and Section 9 rows updated. Moving an + anchor is now the only way to relax a budget, and it is a code edit. +- **Open question sharpened:** Q7 may now collapse from "adopt the + `maintainability_ratchet` exception lifecycle" to "share its anchor pattern", + because this smoke already uses that pattern. + +### 2026-09-15 — M0 placed on the pull-request path after a third review + +- **Baseline:** `1dc6ad8d8` +- **Trigger:** a third review asked where the smoke actually runs. A premerge + plan for a diff touching only `loop_controller.py` and `turn_envelope.ts` + listed 32 commands and not this smoke; `full-public-smokes.yml` triggers on + push to `main` and a daily schedule and is documented as intentionally not a + PR-required check. The only surface that runs on every pull request is the + `pytest` sweep, and the committed test covered the scanner on fixtures only. + The RFC's "commit-time" claim therefore held only after merge. +- **Also found:** every anchor compared with `<=` (or `>=` for floors), copied + faithfully from the `RFC_MODULE_BUDGETS` precedent. A budget tightened below + its anchor in one PR could be raised back to the anchor in a later PR with no + code edit, so the ratchet stalled at whatever value the anchor last held. +- **Delivered:** `tests/architecture/test_semantic_vocabulary_drift.py` runs + the smoke as a subprocess inside the default sweep; the smoke is added to the + `repo-architecture-budget` premerge profile beside the maintainability + ratchet; all three anchor comparisons become equality; I10 added; Section 10 + gains the surface table. +- **Evidence:** Appendix C, E14 to E16. +- **Known gaps:** the pytest wrapper costs about three seconds per sweep; + premerge selection still depends on a trigger hint matching the changed path. +- **Effect on normative design:** I5 restated as equality with the reason for + departing from the precedent; I10 added; Section 9 gains three rows; Section + 10 rewritten from one sentence to a surface table. + +## Appendix B: Decision log + +| Date | Decision | Owner / approval | Alternatives | Normative sections changed | +| --- | --- | --- | --- | --- | +| — | none recorded | — | — | — | + +## Appendix C: Evidence registry + +| Evidence id | Claim | Baseline / environment | Artifact or command | Result | Privacy / validity boundary | +| --- | --- | --- | --- | --- | --- | +| E1 | Three definitions of the envelope schema constant | `1dc6ad8d8` | `rg -n 'TURN_ENVELOPE_SCHEMA_VERSION\s*=' loopx` | 3 files | Source only | +| E2 | 28 distinct `effective_action` literals across `loopx/` | `1dc6ad8d8` | the smoke's `literal_scan` | 28 | Pattern-bound; prose mentions excluded | +| E3 | 43 py/ts twins under the control plane | `1dc6ad8d8` | smoke twin report | 43 | Same-basename rule only | +| E4 | Legacy field spread | `1dc6ad8d8` | smoke budget report | see registry | Module mentions, not call sites | +| E6 | Global census of closed-set carriers | `1dc6ad8d8` | `python3.11 scripts/generate_semantic_inventory.py` summary | 102 enums, 490 closed sets, 8 aliases, 40 arrays, 2002 named constants, 166 twins, 25/58 forks, 18/59 conflicts | AST and `as const` text scan; module-level only | +| E7 | First scan pattern captured zero TypeScript sites | `1dc6ad8d8` | pattern applied to every `.ts` line containing `effective_action` | 0 of 7 dispatching files matched; `===` always failed | Pattern-bound | +| E8 | Two `effective_action` values unregistered on baseline while the first smoke was green | `1dc6ad8d8` | `turn_journal.ts:656` ternary | `observe_replay`, `block_replay` | Same | +| E9 | Owner check skipped a bare-module owner | `1dc6ad8d8` | first smoke's `if "::" in python_owner` | `effective_action` owner never checked | Code reading plus mutation | +| E10 | Twenty drift mutations fail closed (TS `===`, TS ternary, Python membership, Python `==` through `or ""`, bare owner, dropped owner, narrowed suffixes, renamed vocabulary, forked symbol, TS value removed, enum widened, projection changed, legacy field regrown, stale inventory, third conflicting spelling, dead value, lost variable producer, broken subset, forked schema version, unknown registry key) | `1dc6ad8d8` + local edit, inventory regenerated where the edit adds a carrier, restored after each run | temporary edit then the smoke with `python3 -B` | 20/20 exit 1 naming the rule, value, or file | Local exercise, not a committed test | +| E5 | Nine drift mutations fail closed (unregistered literal with and without digits, forked constant, TS kind removed, Python enum widened, projection changed, legacy field regrown, dead registry value, new py/ts twin) | `1dc6ad8d8` + local edit, restored after each run | temporary edit then the smoke, run with `python3 -B` | 9/9 exit 1 with the offending value or file named | Local exercise, not a committed test; a same-size same-second edit needs `-B` to defeat stale bytecode | +| E11 | The registry could relax its own ratchet in one diff | `1dc6ad8d8` + local edit | fourteen registry mutations: lower one floor, lower all floors, lower a floor while dropping the owner it counts, raise every `inventory_ratchets` entry, raise one entry, raise a retirement budget | 7 escaped before the anchors, 0 escape after; each caught failure names the anchored value | Local exercise, not a committed test | +| E12 | 599 multi-value carriers were listed but never compared | `1dc6ad8d8` | collision rule applied to enums, closed sets, `Literal` aliases, and `as const` arrays | 4 same-name forks (10 definitions) and 19 twins already on the baseline, none budgeted; `SOURCE_SURFACES` alone has four divergent value sets | Name-keyed; a rename removes a name from the comparison | +| E14 | The smoke was not on the pull-request path | `1dc6ad8d8` + M0 | `loopx canary premerge --changed-file loopx/control_plane/turn_driver/loop_controller.py --changed-file loopx/control_plane/quota/turn_envelope.ts`; `.github/workflows/full-public-smokes.yml` triggers | 32 commands planned, smoke absent; fleet runs on push to `main` and schedule only | Selection by path token; CI wiring read from the workflow files | +| E15 | A tightened budget could drift back to its anchor | `1dc6ad8d8` + M0 | `ratchets[key] <= BUDGET_ANCHOR[key]` and `floor[key] >= anchored` in the smoke | any value between the tightened budget and the anchor passed | Code reading; the precedent uses the same comparison | +| E16 | Equality closes the stall and the wrapper reaches the sweep | `1dc6ad8d8` + M0 | lower one `inventory_ratchets` entry with the anchor untouched, then `pytest tests/architecture/test_semantic_vocabulary_drift.py` on the clean tree | the mutation fails naming both values; the wrapper passes in about three seconds | Local exercise plus committed test | +| E13 | The conflict budget mostly measured local naming | `1dc6ad8d8` | `MODULE_LOCAL_CONVENTION` applied to `conflicting_values` and `same_runtime_forks` names | 16 of 18 conflicts and 7 of 25 forks are module-local conventions; the semantic subsets are 2 and 18 | Classification is a name pattern, documented in the scanner and pinned by a fixture test | + +## Appendix D: Rejected or superseded alternatives + +See Section 6. A single-PR enum unification was rejected because the three +enums have distinct change reasons; the evidence that could reopen it is a +projection proven to be a bijection after M2. + +## Appendix E: Incident and review lessons + +- Hand-synchronized parallel constant lists across runtimes pass review until + the day one side changes; a parity check must exist before the second copy is + accepted. +- A private extraction of a shared constant looks harmless in a large module + and is the most common way a schema version forks. Test fixtures are the + second most common: `HANDOFF_MODES` was copied into an e2e fixture. +- A literal scan that only accepts `[a-z_]` silently skipped a `_v2` spelling + during the M0 mutation exercise. Capture every quoted string and validate the + shape separately, so a malformed value is reported instead of ignored. +- A scan pattern written from Python examples matched no TypeScript at all, + and a guard that is green on a baseline containing violations proves only + that the guard is blind. Mutation-test every runtime the registry claims to + cover before declaring an invariant. +- When the registry is both the specification and the validator's input, a + data edit can weaken the validator. Keep the recognised forms in code, floor + the coverage counts, and reject owners that are not `module::Symbol`. +- A ratchet on names alone lets an already-conflicting name gain a third + spelling. Budget definitions as well as names. +- A smoke the fleet discovers is not a commit-time check. Ask on which + required PR job it is collected, and plan a diff that touches only the + guarded code to see whether selection finds it. If the answer is "after + merge", the invariant is a report, not a gate. +- An anchor compared with `<=` pins only the value it held when written. Every + tightening below it is unprotected until someone remembers to move the + anchor. Compare with equality so the two values cannot separate. +- One field name can carry several vocabularies inside one envelope; a scan + that sees the field cannot see the slot. Record the slots as a relation so + the ambiguity is a registered fact, not an accident the registry blesses. diff --git a/docs/architecture/rfcs/semantic-vocabulary-convergence-v0.zh-CN.md b/docs/architecture/rfcs/semantic-vocabulary-convergence-v0.zh-CN.md new file mode 100644 index 0000000000..10d46ce690 --- /dev/null +++ b/docs/architecture/rfcs/semantic-vocabulary-convergence-v0.zh-CN.md @@ -0,0 +1,557 @@ +# RFC:语义词表收敛与提交期漂移检查(v0) + +- **RFC status:** Draft +- **Delivery maturity:** Partial(M0 的注册表、生成清单与漂移 smoke 随本 RFC 一起交付) +- **Authors / owners:** LoopX 贡献者;控制面内核维护者拥有批准权 +- **Created:** 2026-09-15 +- **Last normative revision:** 2026-09-15 +- **Implementation baseline:** `1dc6ad8d8` +- **Related contracts:** `loopx/semantics/vocabulary_v0.json`、 + `loopx/semantics/inventory_v0.json`、 + `loopx/control_plane/turn_transaction_contract.json`、 + `loopx/control_plane/coordination/coordination_state_contract_v0.json`、 + [Turn Envelope v0](../../reference/protocols/turn-envelope-v0.md)、 + [Turn Loop Controller v0](../../reference/protocols/turn-loop-controller-v0.md)、 + [TypeScript 控制面迁移 v0](typescript-control-plane-migration-v0.zh-CN.md) +- **Language mirror:** [English](https://github.com/huangruiteng/loopx/blob/main/docs/architecture/rfcs/semantic-vocabulary-convergence-v0.md) + +## 文档地图与维护契约 + +本 RFC 同时交付英文版 `semantic-vocabulary-convergence-v0.md` 与本中文语义镜像; +两者互相链接,规范章节变更时必须同步修订。 + +- 第 1-10 节是持久的设计与验收契约。 +- 第 11 节是规范性交付计划。 +- 第 12 节是未决决策;建议答案不等于批准。 +- 附录是非规范的执行账本、决策日志、证据登记与被否决方案。 + +RFC 成熟度与交付成熟度彼此独立。带日期的进度条目不修改规范章节。 + +--- + +## 1. 决策摘要 + +1. **什么成为权威。** `loopx/semantics/` 下的两份文件。策展注册表 + `vocabulary_v0.json` 为每个内核与跨运行时词表命名:允许定义它的确切 + `module::Symbol`、词表之间的关系(同一概念、共享字段名、子集)、完整投影, + 以及仓库同意只降不升的预算。生成清单 `inventory_v0.json` 映射 `loopx/` 下 + 每一个闭集载体:字符串枚举、`Literal` 别名、命名闭集、TypeScript `as const` + 数组,以及在多个模块中定义的每个常量名。一支公共 smoke + `examples/semantic-vocabulary-drift-smoke.py` 在每次 premerge 与 full-public + 运行时用两份文件核对代码。任何扩宽词表、分叉常量、新增载体或削弱注册表的 + 改动,必须在同一个 diff 里修改注册表或重新生成清单,评审者因此能把语义 + 变化当作变化看见。 +2. **什么不变。** 运行时行为、线上格式、枚举类本身。每个枚举继续住在自己的 + owner 模块里;注册表通过 AST 与文本扫描核对代码,不生成代码,产品代码也 + 永不导入它。 +3. **默认与可选边界。** 检查对仓库始终开启。它没有运行时开关,因为它从不在 + 产品内运行。 +4. **主要约束。** 失败即关闭、确定性、且不能仅靠改数据被削弱。任一运行时的 + 未注册字面量、第二个定义模块、预算超支、注册表列出但无模块携带的值、过期 + 的清单、不带符号的 owner 声明、低于记录下限的覆盖计数,每一项都让 smoke + 失败。扫描识别的分发形式写在 smoke 里而不在注册表里。smoke 只读已跟踪 + 源码,不打印任何私有数据。 +5. **本 RFC 不批准的事。** 把三套 Turn 结果枚举合并为一套、拆分 + `effective_action` 的三个槽位、删除任何旧的 should-run 字段、删除任何 + Python 孪生模块、重命名任何现有值。这些属于后续里程碑,各自受 `AGENTS.md` + 中 schema 缩减规则的门控。 + +## 2. 问题与动机 + +LoopX 由大量小型 agent 驱动的 PR 生长而成。每个 PR 在需要之处加上它需要的 +词汇。结果不是错误行为,而是漂移:同一概念多种拼法,同一常量在多个文件定义, +同一字段名承载不同词表,以及任何模块都可扩宽而无人察觉的开放字符串集合。 +评审者无法从 diff 判断一个新字面量是新状态还是拼写错误,文档也无法跟上一个 +没人枚举的集合。 + +语义面是全仓库的,不是 Turn 内核的局部问题。清单生成器在基线上扫描 `loopx/` +下 1169 个源文件得到: + +| 载体 | 数量 | 说明 | +| --- | --- | --- | +| Python 字符串枚举 | 102 | 控制面 29、capabilities 17、extensions 6 | +| 命名闭集(`NAME = frozenset/tuple` 字符串) | 490 | 66 个是字段列表、31 kinds、31 states、29 statuses | +| `Literal[...]` 别名 | 8 | | +| TypeScript `as const` 数组 | 40 | 21 个有值集相等的 Python 侧;14 个没有 | +| 命名字符串常量 | 2002 | 754 个是 `*_SCHEMA_VERSION` | +| 同名同值、跨两个运行时 | 166 | 合法的 py/ts 孪生 | +| 同名同值、同一运行时 | 25 个名字 / 58 处定义 | 分叉;其中 7 个是 schema 版本 | +| 同名不同值 | 18 个名字 / 59 处定义 | 见下 | + +在基线上审计出的具体失败: + +- `TURN_ENVELOPE_SCHEMA_VERSION` 定义了三次: + `loopx/control_plane/quota/turn_envelope.py:16`、 + `loopx/control_plane/quota/turn_envelope.ts:13`,以及 + `loopx/control_plane/turn_driver/driver.py:31` 的一份私有副本。M0 删除该副本。 +- `HANDOFF_MODES` 由 TypeScript owner 定义,又在 + `control_plane/testing/authority_e2e_fixtures.py:33` 以字面元组重定义。M0 让 + 夹具元组从 `HandoffMode` 枚举派生。 +- 同一值集跨运行时有两个名字:`work_items/delivery_outcome.ts` 的 + `MATERIAL_DELIVERY_OUTCOMES` 等于 `goals/goal_frontier/outcome_continuity.py` + 的 `VISION_OUTCOME_CHECKPOINT_MATERIAL_OUTCOMES`。两者都是 `DeliveryOutcome` + 去掉 `surface_only`;没有任何地方说明这一点。 +- 同名不同值:`DECISION_CONTEXT_CAPABILITY_ID` 在 + `capabilities/decision_context/packets.py:18` 是 `decision_context`,在 + `extension_provider.py:24` 是 `decision-context`;`MCP_REQUIREMENT` 在 + `kunluncode_goal_mode/cli.py:28` 是 `mcp==1.28.1`,在 + `claude_goal_mode/scripts/install.py:83` 是 `mcp<2`。另外 16 个名字是模块内 + 通用常量(`SCHEMA_VERSION`、`COMMAND`、`CAPABILITY_ID`),今天的碰撞无害, + 明天却不可见。 +- Turn 结果种类靠手工维护了两份:`transaction.py:28` 的 `LoopXTurnResultKind` + 与 `settlement.ts:49` 的 `TURN_RESULT_KINDS`。今天一致;没有任何测试断言过。 + 另外 11 对 py/ts 词表同样如此(settlement 的 step、binding、failure kind, + receipt-bound phase,scheduler transition,Todo completion 的 continuation 与 + recovery,delivery outcome,delivery workspace kind,Goal amendment class, + Todo decision scope)。 +- `effective_action` 是两侧都没有枚举的开放字符串集合。Python 与 TypeScript + 共靠字符串比较分发 31 个不同字面量。其中两个(`observe_replay`、 + `block_replay`)由 `turn_journal.ts:656` 写入 Turn Envelope 的 replay + observation 槽位,根本不是 should-run 裁决。另外两个 + (`quota_action_selection_deferred`、`quota_action_selection_rejected`)是 + `cli_commands/quota.py:279` 复制进该槽位的 quota 错误码。 + `AgentScopeFrontierAction` 的值又被写进同一 envelope 的 + `agent_scope_frontier.effective_action` 槽位。一个字段名,三套词表。 + `user_gate.py:162` 还把该槽位与 `skip` 比较,而没有任何生产者写入它。 +- 三套近似同构的 Turn 结果词表并存:`LoopXTurnResultKind`(12)、 + `LoopXTurnRoute`(8)、`LoopDisposition`(8),`repair`/`repair_required` 与 + `replan`/`replan_required` 是同一裁决的不同拼法。route 到 disposition 的投影 + 是 `loop_controller.py:126` 的私有字典;没有任何声明说它覆盖全部输入。真正承重的 + `decide_loop_disposition` 决策表(result kind、retryable、attempt budget、 + decision user action、durable no-follow-up)只存在于控制器协议文档的散文里。 +- 文档已称为 legacy 的六个 should-run 决策字段仍各被 7 到 35 个 Python 模块 + 提及,没有棘轮阻止新消费者。 +- `loopx/control_plane` 下有 43 对同名 `.py`/`.ts` 模块,而迁移 RFC 是 + replacement-first。这个数量没有守卫。 +- 仓库已经在运行一支 AST 支撑的控制面债务棘轮 + (`loopx/canary/maintainability_ratchet.py`),带评审化的例外生命周期,但它 + 度量的是模块指标与依赖方向,不是词表形状。词表漂移没有棘轮。 + +现有 owner 无法在本地解决,因为每处修复天然跨模块:Turn driver、quota、 +todos、capabilities 与 TypeScript 运行时各自拥有同一想法的一种拼法。 + +### 不变量 + +- **I1 单一 owner。** 每个注册词表或常量,恰有注册表列出的定义模块,且注册的 + 符号名在 `loopx/` 下别无定义。其余模块一律 import。 +- **I2 闭集。** 注册词表可携带的每个值都被列出。任一运行时的代码都不携带未 + 注册的值,注册表也不列出代码不携带的值。 +- **I3 跨运行时一致。** 词表同时有 Python 与 TypeScript owner 时,两侧集合完全 + 相同。 +- **I4 完整投影。** 注册投影为每个源值恰好命名一次:要么映射,要么声明拒绝。 +- **I5 棘轮只降。** 退休、孪生与清单预算可在任何 PR 中调低。每个预算在 smoke + 里另由一个 `BUDGET_ANCHOR`(或 `RETIREMENT_ANCHOR`)字面量钉住,每个下限由 + 一个 `COVERAGE_ANCHOR` 钉住,沿用 + `tests/control_plane/test_m6_quality_gates.py` 的 `RFC_MODULE_BUDGETS` 锚点 + 模式,但有一处刻意的不同:注册表的值必须**等于**锚点。先例用 `<=` 比较, + 这会让一个已收紧到锚点以下的预算,在之后的 PR 里不改任何代码就涨回锚点。 + 相等性让每次收紧都是两个文件的 diff,每次放松都是评审者可见的代码修改。 +- **I6 同 diff 可见。** 语义变化与其注册表修改或清单再生成落在同一个可评审 + diff 里。 +- **I7 确定性且公开安全。** 检查只读已跟踪源码,不需网络或凭据,失败文本只 + 命名文件与值,绝不含私有数据。 +- **I8 覆盖只增。** 注册词表数、owner 符号数、投影数、关系数、schema 版本数 + 与扫描后缀集合被记录为下限。owner 只能是 `module::Symbol` 或 `null`;裸模块 + 路径被拒绝,null owner 必须声明字面量扫描。扫描识别的分发形式固定在 smoke + 里。因此一次注册表修改不可能悄悄收窄守卫所见。 +- **I9 两种载体形状都被度量。** 词表进入代码的形态有两种:字符串常量 + (`NAME = "value"`)与多值载体(枚举、命名闭集、`Literal` 别名、 + TypeScript `as const` 数组)。两者适用同一条冲突规则:同一个名字在两个模块 + 中被定义,值集相同是孪生,值集不同是分叉。冲突预算只统计共享词表子集; + `SCHEMA_VERSION`、`COMMAND`、`*_LABEL` 这类模块局部约定名仍保留在清单 + 总数中可见,但不算漂移。 +- **I10 在 PR 路径上。** 漂移 smoke 通过 + `tests/architecture/test_semantic_vocabulary_drift.py` 跑在默认 `pytest` + 扫描里,因此在每个运行 Python 测试的 PR 上失败即关闭。`examples/` 下的舰队 + 发现与 `repo-architecture-budget` premerge profile 是附加表面,不是义务: + 舰队在合并后和按日程运行,premerge 按改动路径的 token 选择。 + +## 3. 范围与非目标 + +### 范围内 + +- 注册表文件、其 schema,以及编辑它的所有权规则。 +- 生成清单、带 `--check` 的生成器及其单元测试。 +- 漂移 smoke 及其在 premerge 与 full-public 舰队中的位置。 +- M0 注册的词表:四个 Turn 内核集合(`turn_result_kind`、`turn_route`、 + `loop_disposition`、`effective_action`)、`agent_scope_frontier_action` 与 + `lease_action`,以及基线上 Python 与 TypeScript owner 值集相等的二十个跨 + 运行时集合;route 到 disposition 的投影;九条关系;Turn Envelope 的 schema + 版本;六个旧 should-run 字段;控制面孪生数量;清单的分叉与冲突预算。 +- 后续里程碑:把 `effective_action` 变成类型化枚举、拆分其三个槽位、通过契约 + 发布投影、按现有仓库规则退休旧字段与孪生模块。 + +### 非目标 + +- 改变任何运行时决策、载荷形状或线上格式。 +- 手工策展每个闭集。清单映射全部闭集;只有跨模块或跨运行时边界并被分发的 + 词表才带 owner、值与关系进入策展层。 +- 取代 `turn_transaction_contract.json` 或 + `coordination_state_contract_v0.json`。它们仍是各自阶段与记录的 owner;本 + 注册表可以引用它们,不能复述它们。 +- 取代 `maintainability_ratchet.py`。它拥有模块指标与依赖方向;本注册表拥有 + 词表形状。两者的例外生命周期是否合并见第 12 节 Q7。 +- 用散文术语表作为强制机制。术语表是有用的伴随物,在第 12 节跟踪,但它不能 + 让构建失败。 + +## 4. 现行系统契约 + +基线 `1dc6ad8d8` 上的事实: + +- `turn_transaction_contract.json` 是两个运行时同时读取的唯一契约: + `effect_program.py:160-166` 加载阶段元组,`turn_journal.ts:1` 导入该 JSON。 + 这是注册表作为共享事实源所效仿的模板。 +- `coordination_state_contract_v0.json` 更进一步,通过 + `scripts/generate_coordination_state_contract.py --check` 生成 + `coordination_state_contract_generated.py` 与 + `coordination_state_contract.generated.ts`,由 + `tests/control_plane/test_coordination_state_contract.py` 守卫。清单生成器 + 现在效仿它,M2 提议的生成阶段之后效仿它。 +- canary runner 会发现每个已跟踪的 `examples/**/*-smoke.py` + (`loopx/canary/runner.py:392`),因此 `examples/` 下的 smoke 无需在 + `planner.py` 或 `premerge.py` 登记。 +- `loopx/canary/maintainability_ratchet.py` 是现有的 AST 支撑的控制面债务棘轮。 + 它带有含 `retirement_plan` 的评审化例外并检测过期例外 id。它的对象是模块 + 体积、`Any` 密度、决策点数量与禁止的依赖方向;它不读取枚举或常量的值。 +- `AGENTS.md` 已要求状态分类使用类型化枚举、禁止 Python 为控制面权威建立第二 + 事实源、新增模块前做 scope-fit 评审、并要求任何 schema 缩减获得维护者批准。 + 本 RFC 增加的是让这些规则在 diff 中可观测的检查;它不改变规则本身。 +- `loopx.control_plane` 的 package data 已经打包 `*.json`;`pyproject.toml` + 增加一行,让 `loopx.semantics` 以同样方式打包其两份 JSON。 + +## 5. 提议架构 + +### 所有权与权威 + +注册表由控制面内核维护者拥有。任何贡献者可以调低预算,或随携带它的代码一起 +新增一个值。只有维护者可以批准调高预算、删除值或迁移 owner 模块,批准记入 +附录 B。 + +禁止的替代权威:第二份注册表、复述已注册值的模块内列表,或宣称对已注册词表 +具有规范性的散文表格。 + +### 状态模型与 schema + +`loopx/semantics/vocabulary_v0.json`,`schema_version` 为 +`loopx_semantic_vocabulary_v0`。键集合是封闭的;未知的顶层键或词表键让 smoke +失败。 + +| 键 | 内容 | 检查 | +| --- | --- | --- | +| `coverage_floor` | 词表、owner 符号、字面量扫描字段、投影、关系、schema 版本的数量;扫描后缀集合 | 实际计数不低于下限,声明的后缀覆盖下限集合,且每个下限必须等于其 `COVERAGE_ANCHOR`(I8) | +| `vocabularies..owners` | `python` 与 `typescript`,各为 `path::Symbol` 或 `null` | 枚举成员、闭集成员、`Literal` 别名或 `as const` 数组等于 `values`;该符号只在 owner 模块中定义(I1、I2、I3) | +| `vocabularies..tier`、`status` | `kernel`、`cross_runtime`、`cross_module`;`canonical`、`legacy`、`merge_candidate` | 封闭枚举 | +| `vocabularies..literal_scan` | `field`、根目录、后缀 | 固定分发形式捕获的每个字面量都已注册;每个注册值被捕获或来自变量(I2) | +| `vocabularies..variable_sourced_values` | 值到生产者模块 | 生产者仍包含带引号的该值 | +| `vocabularies..value_notes`、`deprecated_values` | 逐值评审备注;计划删除的值 | 名字必须是已注册值 | +| `relations.same_concept` | `vocabulary.value` 成员组 | 每个成员可解析 | +| `relations.shared_field_names` | 一个字段名、其槽位及各槽位承载的词表或值 | 每个槽位可解析 | +| `relations.subsets` | 超集词表、排除值、子集符号的 owner | owner 符号等于超集减排除值 | +| `projections..mapping` | 源值到目标值或 `null` | 键等于源词表;映射值与 owner 函数一致;`null` 路由抛出(I4) | +| `schema_versions.` | 常量名、值、owner 模块 | 唯一的定义模块就是列出的 owner 且都携带该值(I1) | +| `retirement_ledger..fields` | 每字段的 Python 与 TypeScript 模块预算 | 实际模块数不超过预算,且字段集合与每个预算与 `RETIREMENT_ANCHOR` 一致(I5) | +| `dual_runtime_twins` | 根目录与模块预算 | 同名 `.py`/`.ts` 对数不超过预算(I5) | +| `inventory_ratchets` | 同运行时分叉的名字数与定义数、冲突的名字数与定义数、schema 版本分叉数、多值孪生与分叉数,以及共享词表冲突与分叉子集的预算 | 清单摘要计数不超过预算,且每个预算必须等于其 `BUDGET_ANCHOR` 条目(I5、I9) | + +`loopx/semantics/inventory_v0.json`,`schema_version` 为 +`loopx_semantic_inventory_v0`,由 `scripts/generate_semantic_inventory.py` 生成, +必须与新鲜构建完全一致。它每行一条地列出 Python 枚举、闭集、`Literal` 别名、 +TypeScript `as const` 数组,以及拆为跨运行时孪生、同运行时分叉、冲突值、多值 +孪生与多值分叉四类的重复定义。每个多值冲突都带上全部定义模块及其值集,因此 +可评审的是分叉本身而不只是计数。消费者计数由 `--report` 打印,合并候选组通过 `merge_candidate_groups` 获取, +两者均不提交,因此普通的消费者改动不会碰这个文件;合并候选是建议性的,因为值集 +相同并不能证明是同一个概念。单模块的字符串常量只计数,不列出。 + +值是只增的。删除一个值、字段、owner 或关系属于 schema 缩减,遵循 `AGENTS.md` +规则:枚举受影响表面、调研生产者与读者、在同一 diff 中调低下限、记录维护者 +批准。 + +### 命令或事件生命周期 + +检查只有一个命令:运行 smoke。它幂等且无副作用。失败文本命名词表、违规文件与 +值,修复是机械的:注册该值、import 该常量,或收窄改动范围。 + +### Provider 或扩展契约 + +新词表通过一个 PR 加入:新增注册表条目、提高覆盖下限,若存在 TypeScript owner +则指名其 `as const` 数组。当一个词表被多个模块分发或跨越 Python/TypeScript +边界时,即有资格进入策展层;其余由清单映射而不策展。新增任何载体都要在同一 +PR 中重新生成清单。 + +## 6. 备选方案与设计选择 + +| 备选 | 为何现在不选 | +| --- | --- | +| 一个 PR 把三套 Turn 枚举合一 | 违背 I5 式的渐进;三套枚举有不同 owner 与变化原因(settlement、route、controller)。先注册并投影,只在投影证明同一后再合并(第 12 节 Q2)。 | +| 依赖 `mypy` 的 `Literal` 类型 | 覆盖不到 TypeScript、JSON 载荷与 CLI;而漂移恰恰发生在这些边界。 | +| 仅靠文档术语表 | 不能让构建失败;仓库已有十一份自称 mental model 的文档且没有术语表,这本身就是症状。 | +| 立即从注册表生成绑定 | owner 尚未定下之前为时过早。生成是 M2,效仿协调契约先例。 | +| CI 里不带注册表的 grep 式 lint | 把允许集合编码进 linter,变成没有评审痕迹的第二份注册表。 | +| 扩展 `maintainability_ratchet.py` 而不新建注册表 | 它的对象是模块指标与依赖方向,按模块设上限;词表形状需要值、owner 与关系。两者共享棘轮思想而非数据模型。例外生命周期是否合并见 Q7。 | +| 把扫描正则放进注册表 | 数据里的正则可以在扩宽词表的同一次修改中被收窄;M0 评审表明第一版模式漏掉了全部 TypeScript `===` 分发点。形式固定在 smoke 里,后缀集合设下限。 | +| 在清单中提交消费者计数 | 每次消费者改动都会搅动文件,让新鲜度检查变成噪音。计数通过 `--report` 保持为参考信息。 | + +## 7. 安全、隐私与兼容 + +- M0 没有任何运行时路径导入注册表;检查存在与否,产品行为不变。 +- 扫描器使用 `git ls-files --cached -z` 枚举索引中的源文件路径,再读取工作树内容。 + 未跟踪与忽略文件不进入清单;新增源文件需先暂存路径,再重新生成清单。已跟踪 + 的符号链接与无法解析的 Python 源码使检查失败;运行时需要带 Git 元数据的检出。 +- 字面量及 TypeScript 载体扫描同时识别单引号与双引号。它们仍是结构性文本 + 扫描,不是完整解析器,也不做数据流分析。 +- 字面量扫描根目录与后缀、孪生模块根目录与预算均有代码锚点;仅修改 JSON + 不能缩窄扫描范围或提高孪生预算。 +- 失败文本只使用仓库相对路径与已注册标识符。 +- 旧的读写方不受影响。预算冻结其当前分布,不删除任何一处引用。 +- 构建期检查不涉及混合版本。M2 引入生成绑定时,生成器的 `--check` 模式与 + smoke 同时运行,过期的生成文件无法合入。 + +## 8. 迁移与回滚 + +- **准入。** M0 落地时注册表与清单和基线完全一致,外加两处保持行为的修改以让 + owner 检查通过:`driver.py` 中重复的 `TURN_ENVELOPE_SCHEMA_VERSION` 改为 + import,authority e2e 夹具中的 `HANDOFF_MODES` 元组改为从 `HandoffMode` 枚举 + 派生。 +- **回滚。** 删除 smoke、`loopx/semantics/` 包、生成器、其测试与 `pyproject.toml` + 的那一行即恢复原状,无运行时影响。后续里程碑在第 11 节各带回滚。 +- **不可回退点。** M0 没有。M3 的字段删除是第一个不可逆步骤,逐个门控。 + +## 9. 验证与验收 + +| 声明 | 测试或证据 | 要求结果 | 边界 / 排除 | +| --- | --- | --- | --- | +| 基线上注册表与清单和代码一致 | `python3.11 examples/semantic-vocabulary-drift-smoke.py` | `ok` 并输出覆盖、棘轮、预算与孪生报告 | 只证明已注册词表与已映射载体的一致性 | +| 清单新鲜 | `python3.11 scripts/generate_semantic_inventory.py --check` | 退出码 0 | 仅结构性映射 | +| 扫描器分类规则 | `pytest tests/architecture/test_semantic_inventory.py` | 通过 | 夹具仓库;规则来自本 RFC 而非输出 | +| Python 侧扩宽 `effective_action` 时失败关闭 | 通过 `==`、成员测试或条件表达式加一个未注册字面量 | 失败文本命名该值与文件 | 突变练习;非提交测试 | +| TypeScript 侧扩宽 `effective_action` 时失败关闭 | 通过 `===` 或三元表达式加一个未注册字面量 | 同上 | 同上 | +| 分叉常量时失败关闭 | 在非 owner 模块重定义 `TURN_ENVELOPE_SCHEMA_VERSION` 或 `HANDOFF_MODES`,重新生成清单 | 失败列出多出的定义模块或分叉预算 | 同上 | +| Python 与 TypeScript owner 不能分叉 | 从已注册 `as const` 数组删一项,或扩宽已注册枚举 | 失败命名缺失或未注册的值 | 同上 | +| 注册表不能仅靠改数据被削弱 | 声明裸模块 owner;删掉一个 owner;把后缀收窄为 `.py`;重命名一个被关系引用的词表;加一个未知键 | 每项都失败并点名规则 | 同上 | +| 新载体可见 | 新增一个枚举而不重新生成 | 失败文本说清单过期 | 同上 | +| 冲突拼法不能增长 | 为已冲突名字加第三种值,重新生成 | 失败命名定义数预算 | 同上 | +| 多值冲突不能增长 | 让一个闭集名在两个模块中以不同值集定义,或以相同值集定义,并重新生成 | `multi_value_forks` 或 `multi_value_twins` 失败并命名新名字 | 突变练习;非提交测试 | +| 注册表不能放松自己的棘轮 | 在同一 diff 中调低任一 `coverage_floor` 计数、调高任一 `inventory_ratchets` 预算或退休预算,同时删掉它所统计的覆盖 | `COVERAGE_ANCHOR`、`BUDGET_ANCHOR` 或 `RETIREMENT_ANCHOR` 失败并命名被锚定的值 | 突变练习;挪动锚点是一次评审者可见的代码修改 | +| 已收紧的预算不能漂回过期锚点 | 只调低注册表预算而不动锚点 | 失败文本指出注册表值与锚点不等 | 用相等而非 `<=`;修法是同 diff 调低锚点 | +| smoke 在 PR 路径上 | `pytest tests/architecture/test_semantic_vocabulary_drift.py` | 通过;该测试被 `python-tests.yml` 的默认 `pytest -q` 扫描收集 | 舰队与 premerge 表面不是义务(I10) | +| premerge 会为 `loopx/` 的 diff 选中该 smoke | `loopx canary premerge --changed-file loopx/control_plane/turn_driver/loop_controller.py` | 计划在 `repo-architecture-budget` 下列出 `examples/semantic-vocabulary-drift-smoke.py` | 选择靠触发词;pytest 包装才是保证 | +| 度量覆盖两种载体形状并过滤局部命名 | `pytest tests/architecture/test_semantic_inventory.py` | 通过,含冲突与模块局部约定两组夹具 | 规则来自本 RFC 而非扫描输出 | +| 两处 owner 修正不改变行为 | `pytest tests/test_loopx_turn_transaction.py tests/test_loop_turn_loop_controller.py tests/test_turn_loop_disposition.py tests/test_loopx_turn_managed_step.py tests/control_plane -k authority` 与 `loopx canary premerge --from-git-diff` | 通过 | 在干净树上可复现的 `main` 既有环境失败除外 | +| 文档治理接受这对 RFC | `python3 examples/docs-governance-smoke.py` | 通过 | 检查镜像、链接、索引 | + +已知边界,写明是为了不让这个检查被过度信任: + +- **改名可以洗白冲突。** 冲突按名字归组,因此把分叉的一侧改名会降低计数而 + 不消除漂移。这里的评审辅助是建议性合并报告;值集相同不能做成硬预算,因为 + `CONFIDENCE_LEVELS` 与 `EDGE_CASE_COMPLEXITIES` 共享 `high/low/medium` 却 + 含义不同。 +- **单元素载体不可见。** 只有一个字符串成员的闭集不构成词表,因此把一个两值 + 集合降为一个值会让它完全退出清单。 +- **字面量扫描可能误读同一行上无关的比较。** 形如 + `log("effective_action", kind === "repair_required")` 会被捕获为 + `effective_action` 的值。为了让失败消失而登记被报告的值会扩宽词表,正确做法 + 是同时登记字段名与字面量,或改写该行;失败文本会给出文件,评审时可见。 +- **锚点是代码而非历史。** PR 仍可挪动锚点,但必须修改一个具名字面量,就在 + 注册表改动的旁边。因为检查是相等性,锚点不可能过期,但它也不记住曾达到的 + 最低值;那段历史在 git log 里。 + +## 10. 运维契约 + +标准 premerge 的 catalog 检查上限从 9 提高到 10,避免新增词表检查挤掉原有 +heartbeat/quota 覆盖。quick 与 deep 档位的上限不变。 + +该检查不可能影响运行中的系统:它只在测试、premerge 与 CI 中执行。其操作者 +界面就是失败文本。不适用可观测性、容量或值班契约。 + +它在哪里运行,以及哪个表面是义务: + +| 表面 | 触发 | 选择 | 角色 | +| --- | --- | --- | --- | +| `pytest` 扫描,`python-tests.yml` | 每个分类为需运行 Python 测试的 PR | 经 `tests/architecture/test_semantic_vocabulary_drift.py` 始终被收集 | **提交时义务(I10)** | +| `loopx canary premerge` | 本地,开 PR 之前 | `repo-architecture-budget` profile,触发词含 `loopx/`、`examples/`、`scripts/`、`refactor` | 早期本地信号 | +| 全量公共 smoke 舰队 | push 到 `main`、每日日程、手动触发 | `examples/**/*-smoke.py` 发现 | 合并后确认;按设计不是 PR 必需检查 | + +在这张表存在之前,RFC 说 smoke "在 premerge 与 CI 中运行"。在基线上这只在合并 +后成立:premerge 对只改 `loopx/control_plane/` 的 diff 不会选中该 smoke,而舰队 +工作流被刻意设为非 PR 必需检查。舰队能发现的 smoke 不是提交时检查,除非某个 +必需的 PR 作业收集它。 + +## 11. 规范性交付计划 + +| 里程碑 | 交付行为 | 进入门 | 退出证据 | 回滚 | +| --- | --- | --- | --- | --- | +| M0 | 含 26 个词表与 9 条关系的注册表、带 `--check` 的生成清单、带固定分发形式与覆盖下限的漂移 smoke、删除两处 owner 分叉、RFC 索引条目 | 本 RFC 开启 | 第 9 节各行全绿;20 类突变失败关闭 | 删除 smoke、`loopx/semantics/`、生成器及其测试 | +| M1 | 单一 owner 模块中的 `EffectiveAction` 类型化枚举;replay observation 与 frontier 槽位拆出(Q6);生产者与消费者 import 它;注册表 `literal_scan` 收紧到枚举 | M0 合入;owner 模块已定(Q3);槽位拆分已决(Q6) | smoke 绿;owner 之外零裸 `effective_action` 字面量;status/should-run 的 parity fixture 不变 | 回退为字面量;注册表保留集合 | +| M2 | route 到 disposition 的投影、`decide_loop_disposition` 决策表与跨运行时集合通过共享契约发布,生成 Python 与 TypeScript 绑定,效仿协调契约生成器 | M1 合入;Q2 与 Q7 已决 | 生成器 `--check` 与 smoke 绿;`settlement.ts` 与 `transaction.py` 读取生成集合 | 从上一版契约重新生成 | +| M3 | 逐字段退休旧 should-run 字段,每个 PR 一个字段,预算降到零并删除字段 | 经生产者/读者调研证明该字段外部读者为零 | 按 `AGENTS.md` 的 schema 缩减记录;附录 B 条目 | 从最后一个写方恢复字段 | +| M4 | 随迁移 RFC 的每次 replacement-first 切换调低孪生预算 | 每个切换 PR | 同 diff 中的预算修改 | 无需;预算跟随代码 | + +## 12. 未决决策 + +1. **注册表位置。** Owner:内核维护者。M0 实现于 `loopx/semantics/`,因为范围是 + 全仓库的,而 `loopx/control_plane/` 与 `docs/reference/` 都不是;该包只含两份 + JSON 与扫描器,没有任何产品代码导入它。在记入附录 B 之前这只是提案。M1 前 + 需定。 +2. **是否合并 `LoopXTurnRoute` 与 `LoopDisposition`?** Owner:Turn driver owner。 + 投影覆盖全部输入但非单射(`blocked` 与 `wait` 都映到 `wait`),而 `stop`、 + `terminal`、`contract_error` 只在一侧存在。`same_concept` 关系记录了四个共享 + 裁决。建议:两者都保留,M2 发布投影,待 managed-step 消费者成熟后再议。 + M2 前需定。 +3. **`EffectiveAction` 的 owner 模块。** 注册表今天不声明 owner,因为不存在任何 + 符号;字面量扫描是唯一检查。选项:`quota/should_run_packet.py`(最大生产者)、 + 新建 `quota/effective_action.py`,或按迁移 RFC 以 TypeScript `turn_envelope.ts` + 为 owner 并生成 Python 绑定。建议:若 M2 先落地则以 TypeScript 为 owner 并 + 生成 Python 绑定;否则新建 `quota/effective_action.py`。M1 前需定。 +4. **伴随术语表。** 是否新增 `docs/reference/glossary.md`,从注册表的 `meaning` + 字段与清单生成。Owner:文档维护者。建议:是,在 M1 生成以免漂移。 +5. **词族命名规则。** `gate`、`scope`、`packet`、`handoff`、`settlement` 词族中的 + 新标识符是否必须在评审中引用术语表条目。这是评审规则而非 smoke;建议在 + 术语表存在后纳入 first-review roster。 +6. **拆分 `effective_action` 的三个槽位。** decision 槽位、`agent_scope_frontier` + 槽位与 replay observation 槽位在同一个 Turn Envelope 里共用一个字段名、承载 + 三套词表;`skip` 被比较却从未被生产。选项:重命名 observation 与 frontier + 槽位,或保留一个字段并注册其并集。Owner:Turn Envelope owner。建议:在 M1 + 重命名,让 Q3 的枚举只有一种含义。M1 前需定。 +7. **与 `maintainability_ratchet.py` 的关系。** 清单棘轮是否采用它的评审化例外 + 生命周期(`retirement_plan`、过期例外检测),还是保持为纯预算。建议:在 M2 + 生成落地时采用,让有书面理由的分叉可以被例外而非被预算。Owner:canary + 维护者。 +8. **从清单到注册表的晋升规则。** 外部消费者模块不少于三个或存在跨运行时孪生 + 的已映射载体是否必须策展。建议:现在作为评审规则采用,待清单积累一个季度 + 历史后再由 smoke 强制。Owner:内核维护者。 + +## 附录 A:执行账本(非规范) + +### 2026-09-15 — 随 RFC 开启 M0 + +- **基线:** `1dc6ad8d8` +- **交付:** 含四个词表、一个投影、一个 schema 版本、六个旧字段预算、一个孪生 + 预算的注册表;漂移 smoke;`driver.py` 中重复的 `TURN_ENVELOPE_SCHEMA_VERSION` + 改为 import。 +- **证据:** 第 9 节各行;见附录 C。 +- **已知缺口:** 投影检查在 M2 发布之前导入私有的 `_route_to_disposition`。 +- **对规范设计的影响:** 无。 + +### 2026-09-15 — 评审后修订 M0;范围改为全仓库 + +- **基线:** `1dc6ad8d8` +- **触发:** 一次评审发现第一版字面量扫描对 TypeScript 完全失明(`===` 从不 + 匹配)、基线上已有两个未注册值(`observe_replay`、`block_replay`),以及 + owner 检查会静默跳过任何不带符号的 owner。 +- **交付:** 注册表迁至 `loopx/semantics/vocabulary_v0.json` 并扩为 26 个词表、 + 46 个 owner 符号、9 条关系与覆盖下限;生成清单 `inventory_v0.json`,带 + `--check` 的生成器与单元测试;smoke 重写为固定分发形式(比较、赋值、三元、 + 成员、条件表达式)、基于 AST 的 owner 解析、owner 排他性、清单新鲜度与 + 分叉/冲突预算;`HANDOFF_MODES` 夹具分叉改为从枚举派生。 +- **证据:** 附录 C 的 E6 到 E10。 +- **已知缺口:** 承重的 `decide_loop_disposition` 决策表仍只有散文(M2); + 字面量扫描无法把一个字面量归到 `effective_action` 三个槽位中的某一个(Q6); + 扫描无法跟随变量传值,因此两个 quota 错误码以"变量来源值"登记并核验生产者, + 而非被证明。 +- **对规范设计的影响:** 第 1 至 5、8、9、11、12 节修订;新增 I8。记为未合入 + 草案的当日修订。 + +### 2026-09-15 — 第二次评审后修复 M0 的度量 + +- **基线:** `1dc6ad8d8` +- **触发:** 第二次评审对 smoke 跑了 14 种攻击,7 种逃逸:单独调低某个 + `coverage_floor`、一次调低全部下限、调高 `inventory_ratchets` 或某个退休 + 预算,以及最关键的——在同一个 diff 中删掉一个 owner 并同时调低对应的下限。 + 下限与被它守护的文件在同一个文件里,且只用 `>=` 比较,因此注册表可以放松 + 自己的棘轮。I5 与 I8 当时是散文,不是机器约束。 +- **同时发现:** 冲突检测只跑字符串常量,599 个多值载体只被列出、从未被比较。 + 基线上已经有四个同名分叉,其中 `SOURCE_SURFACES` 被定义四次、四套不同值集, + 另有 19 个隐藏孪生。另外,18 个 `conflicting_values` 名字中有 16 个是模块 + 局部约定(`SCHEMA_VERSION` 出现 16 次,另有 `COMMAND`、`REQUEST_SCHEMA`、 + `SURFACE`),因此该预算主要在度量局部命名。 +- **交付:** smoke 中新增锚点 `COVERAGE_ANCHOR`、`COVERAGE_SUFFIX_ANCHOR`、 + `BUDGET_ANCHOR`、`RETIREMENT_ANCHOR`,关闭全部七种逃逸; + `multi_value_name_collisions` 让枚举、闭集、`Literal` 别名与 `as const` + 数组适用字符串常量的冲突规则,四个分叉与 19 个孪生按当日计数入预算; + `MODULE_LOCAL_CONVENTION` 让局部名保留在可见总数中但不进入语义预算 + (`conflicting_values_semantic` 为 2,`same_runtime_forks_semantic` 为 18); + 针对 32 组同名异名同值集的建议性合并候选报告;在独立冲突夹具上新增两个 + 扫描器测试;新增 I9 并写明第 9 节的边界。 +- **证据:** 附录 C 的 E11 到 E13。 +- **已知缺口:** 冲突按名字归组,因此改名仍可洗白一个;单元素载体不可见; + 字面量扫描可能误读同一行上无关的比较。 +- **对规范设计的影响:** I5 与 I8 从"意图"改写为"已强制";新增 I9;第 5 节 + 表格与第 9 节各行更新。现在放松预算的唯一方式是挪动锚点,而那是一次代码 + 修改。 +- **被收紧的未决项:** Q7 可能从"采纳 `maintainability_ratchet` 的例外 + 生命周期"收敛为"共用它的锚点模式",因为本 smoke 已经在用该模式。 + +### 2026-09-15 — 第三次评审后把 M0 放上 PR 路径 + +- **基线:** `1dc6ad8d8` +- **触发:** 第三次评审问 smoke 到底在哪里运行。对只改 `loop_controller.py` + 与 `turn_envelope.ts` 的 diff 做 premerge 规划,得到 32 条命令,不含本 + smoke;`full-public-smokes.yml` 只在 push 到 `main` 与每日日程触发,且文档 + 写明刻意不作 PR 必需检查。每个 PR 都跑的唯一表面是 `pytest` 扫描,而已提交 + 的测试只覆盖夹具上的扫描器。RFC 的"提交时"声明因此只在合并后成立。 +- **同时发现:** 每个锚点都用 `<=`(下限用 `>=`)比较,忠实复制了 + `RFC_MODULE_BUDGETS` 先例。一个 PR 把预算收紧到锚点以下后,后续 PR 可以不 + 改代码把它涨回锚点,棘轮停在锚点最后的值上。 +- **交付:** `tests/architecture/test_semantic_vocabulary_drift.py` 在默认扫描 + 里以子进程运行 smoke;smoke 加入 `repo-architecture-budget` premerge + profile,与可维护性棘轮并列;三处锚点比较改为相等;新增 I10;第 10 节增加 + 表面表格。 +- **证据:** 附录 C 的 E14 到 E16。 +- **已知缺口:** pytest 包装每次扫描约耗 3 秒;premerge 选择仍依赖触发词匹配 + 改动路径。 +- **对规范设计的影响:** I5 改述为相等并说明偏离先例的理由;新增 I10;第 9 节 + 增三行;第 10 节从一句话改写为表面表格。 + +## 附录 B:决策日志 + +| 日期 | 决策 | Owner / 批准 | 备选 | 变更的规范章节 | +| --- | --- | --- | --- | --- | +| — | 尚无记录 | — | — | — | + +## 附录 C:证据登记 + +| 证据 id | 声明 | 基线 / 环境 | 产物或命令 | 结果 | 隐私 / 有效性边界 | +| --- | --- | --- | --- | --- | --- | +| E1 | envelope schema 常量有三处定义 | `1dc6ad8d8` | `rg -n 'TURN_ENVELOPE_SCHEMA_VERSION\s*=' loopx` | 3 个文件 | 仅源码 | +| E2 | `loopx/` 下 28 个不同的 `effective_action` 字面量 | `1dc6ad8d8` | smoke 的 `literal_scan` | 28 | 受正则约束;不含散文提及 | +| E3 | 控制面下 43 对 py/ts 孪生 | `1dc6ad8d8` | smoke 孪生报告 | 43 | 仅同名规则 | +| E4 | 旧字段分布 | `1dc6ad8d8` | smoke 预算报告 | 见注册表 | 模块提及数,非调用点 | +| E6 | 闭集载体全局普查 | `1dc6ad8d8` | `python3.11 scripts/generate_semantic_inventory.py` 摘要 | 102 枚举、490 闭集、8 别名、40 数组、2002 命名常量、166 孪生、25/58 分叉、18/59 冲突 | AST 与 `as const` 文本扫描;仅模块级 | +| E7 | 第一版扫描模式捕获零个 TypeScript 站点 | `1dc6ad8d8` | 对每个含 `effective_action` 的 `.ts` 行应用该模式 | 7 个分发文件中 0 个匹配;`===` 总是失败 | 受模式约束 | +| E8 | 第一版 smoke 全绿时基线上已有两个未注册 `effective_action` 值 | `1dc6ad8d8` | `turn_journal.ts:656` 三元表达式 | `observe_replay`、`block_replay` | 同上 | +| E9 | owner 检查跳过了裸模块 owner | `1dc6ad8d8` | 第一版 smoke 的 `if "::" in python_owner` | `effective_action` 的 owner 从未被检查 | 读码加突变 | +| E10 | 二十个漂移突变全部失败关闭(TS `===`、TS 三元、Python 成员、经 `or ""` 的 Python `==`、裸 owner、删 owner、收窄后缀、重命名词表、分叉符号、删 TS 值、扩宽枚举、改投影、旧字段回涨、清单过期、第三种冲突拼法、死值、变量生产者消失、子集破坏、schema 版本分叉、注册表未知键) | `1dc6ad8d8` + 本地改动,改动新增载体时重新生成清单,每次运行后恢复 | 临时改动后以 `python3 -B` 运行 smoke | 20/20 退出码 1 并点名规则、值或文件 | 本地练习,非提交测试 | +| E5 | 九个漂移突变全部失败关闭(含数字与不含数字的未注册字面量、分叉常量、删除 TS 种类、扩宽 Python 枚举、改投影、旧字段回涨、注册表死值、新 py/ts 孪生) | `1dc6ad8d8` + 本地改动,每次运行后恢复 | 临时改动后以 `python3 -B` 运行 smoke | 9/9 退出码 1 并命名违规值或文件 | 本地练习,非提交测试;同尺寸同秒改写需 `-B` 绕过过期字节码 | +| E11 | 注册表可以在一个 diff 内放松自己的棘轮 | `1dc6ad8d8` + 本地改动 | 十四种注册表突变:调低一个下限、调低全部下限、在删掉它统计的 owner 的同时调低下限、调高全部 `inventory_ratchets` 条目、调高单个条目、调高一个退休预算 | 锚点前 7 种逃逸,锚点后 0 种;每个被捕获的失败都命名被锚定的值 | 本地练习,非提交测试 | +| E12 | 599 个多值载体只被列出、从未被比较 | `1dc6ad8d8` | 对枚举、闭集、`Literal` 别名与 `as const` 数组应用冲突规则 | 基线上已有 4 个同名分叉(10 个定义)与 19 个孪生,均未入预算;仅 `SOURCE_SURFACES` 就有四套不同值集 | 按名字归组;一次改名会把一个名字移出比较 | +| E14 | smoke 不在 PR 路径上 | `1dc6ad8d8` + M0 | `loopx canary premerge --changed-file loopx/control_plane/turn_driver/loop_controller.py --changed-file loopx/control_plane/quota/turn_envelope.ts`;`.github/workflows/full-public-smokes.yml` 的触发条件 | 规划 32 条命令,smoke 缺席;舰队只在 push 到 `main` 与日程运行 | 按路径 token 选择;CI 接线读自工作流文件 | +| E15 | 已收紧的预算可以漂回锚点 | `1dc6ad8d8` + M0 | smoke 中的 `ratchets[key] <= BUDGET_ANCHOR[key]` 与 `floor[key] >= anchored` | 收紧后的预算与锚点之间的任何值都能通过 | 代码阅读;先例用同样的比较 | +| E16 | 相等性关闭停滞,包装进入扫描 | `1dc6ad8d8` + M0 | 只调低一个 `inventory_ratchets` 条目而不动锚点,然后在干净树上跑 `pytest tests/architecture/test_semantic_vocabulary_drift.py` | 突变失败并同时命名两个值;包装约 3 秒通过 | 本地练习加已提交测试 | +| E13 | 冲突预算主要在度量局部命名 | `1dc6ad8d8` | 对 `conflicting_values` 与 `same_runtime_forks` 名字应用 `MODULE_LOCAL_CONVENTION` | 18 个冲突中 16 个、25 个分叉中 7 个是模块局部约定;语义子集分别为 2 与 18 | 分类是名字模式,已在扫描器中说明并由夹具测试钉住 | + +## 附录 D:被否决或取代的方案 + +见第 6 节。单 PR 合并枚举被否决,因为三套枚举变化原因不同;可重开该决策的证据 +是 M2 之后投影被证明为双射。 + +## 附录 E:事故与评审教训 + +- 跨运行时手工同步的平行常量列表在其中一侧改变之前总能通过评审;接受第二份 + 副本之前必须先有一致性检查。 +- 在大模块里私有抽一份共享常量看起来无害,却是 schema 版本分叉最常见的方式。 + 测试夹具是第二常见的方式:`HANDOFF_MODES` 被复制进了一个 e2e 夹具。 +- 只接受 `[a-z_]` 的字面量扫描在 M0 突变练习中悄悄放过了 `_v2` 拼法。应捕获 + 所有带引号字符串并单独校验形状,让畸形值被报告而非被忽略。 +- 按 Python 例子写出的扫描模式在 TypeScript 上一个都不匹配;一个在含违规的 + 基线上仍然全绿的守卫,只证明守卫是盲的。在宣称不变量之前,对注册表声称 + 覆盖的每个运行时做突变测试。 +- 当注册表既是规范又是校验器的输入,一次数据修改就能削弱校验器。把识别形式 + 留在代码里、给覆盖计数设下限、拒绝不是 `module::Symbol` 的 owner。 +- 只按名字计数的棘轮会放过已冲突名字的第三种拼法。定义数与名字数都要预算。 +- 舰队能发现的 smoke 不是提交时检查。要问它被哪个必需的 PR 作业收集,并用 + 一个只改被守护代码的 diff 做规划,看选择是否找到它。如果答案是"合并后", + 这条不变量就是报告,不是门。 +- 用 `<=` 比较的锚点只钉住写下它时的值。之后的每次收紧都无保护,直到有人记得 + 挪锚点。用相等性比较,两个值就分不开。 +- 同一个字段名可以在一个 envelope 里承载多套词表;看得见字段的扫描看不见 + 槽位。把槽位记为关系,让歧义成为已登记的事实,而不是注册表背书的意外。 diff --git a/examples/canary/premerge-validation-gate-smoke.py b/examples/canary/premerge-validation-gate-smoke.py index 0d3faf8c62..d8d01a10ba 100644 --- a/examples/canary/premerge-validation-gate-smoke.py +++ b/examples/canary/premerge-validation-gate-smoke.py @@ -34,7 +34,7 @@ def commands_from(run: dict | None) -> list[str]: return commands -def assert_control_plane_change_selects_state_machine_validation() -> None: +def assert_control_plane_change_retains_state_machine_and_vocabulary_validation() -> None: payload = build_premerge_validation_gate( changed_files=[ "loopx/control_plane/work_items/interaction_contract.py", @@ -59,6 +59,7 @@ def assert_control_plane_change_selects_state_machine_validation() -> None: assert any("interaction-contract-state-machine-smoke.py" in item for item in catalog_commands), payload assert not any("control-plane-integrated-canary-smoke.py" in item for item in catalog_commands), payload assert any("heartbeat-quota-flow-smoke.py" in item for item in catalog_commands), payload + assert any("semantic-vocabulary-drift-smoke.py" in item for item in catalog_commands), payload assert any("bounded-context-namespace-smoke.py" in item for item in catalog_commands), payload assert risk_commands, payload assert payload["gate"]["status"] == "preview_only", payload @@ -513,7 +514,7 @@ def assert_inherited_maintainability_red_is_advisory_only() -> None: def main() -> None: - assert_control_plane_change_selects_state_machine_validation() + assert_control_plane_change_retains_state_machine_and_vocabulary_validation() assert_public_docs_change_adds_boundary_scan() assert_quick_public_docs_change_skips_risk_profile_smokes() assert_public_boundary_scan_executes_in_process() diff --git a/examples/canary/smoke-suite-runner-smoke.py b/examples/canary/smoke-suite-runner-smoke.py index e2fe635694..17d3c85e58 100755 --- a/examples/canary/smoke-suite-runner-smoke.py +++ b/examples/canary/smoke-suite-runner-smoke.py @@ -135,9 +135,13 @@ def assert_catalog_profile_preview_is_supported() -> None: execute=False, ) assert payload["ok"] is True, payload - assert payload["selected_check_count"] == 1, payload - assert payload["selected_checks"][0]["command"] == "python3 examples/control_plane/control-plane-maintainability-ratchet-smoke.py", payload - assert payload["catalog_plan"]["planned_check_count"] == 1, payload + assert payload["selected_check_count"] == 2, payload + commands = [check["command"] for check in payload["selected_checks"]] + assert commands == [ + "python3 examples/control_plane/control-plane-maintainability-ratchet-smoke.py", + "python3 examples/semantic-vocabulary-drift-smoke.py", + ], payload + assert payload["catalog_plan"]["planned_check_count"] == 2, payload def assert_named_smoke_profile_expands_to_suite_selection() -> None: @@ -246,11 +250,12 @@ def assert_named_smoke_profile_can_mix_with_catalog_profile() -> None: assert payload["ok"] is True, payload assert payload["selection_inputs"]["smoke_profiles"] == ["canary-runner"], payload assert payload["selection_inputs"]["catalog_profiles"] == ["repo-architecture-budget"], payload - assert payload["catalog_plan"]["planned_check_count"] == 1, payload + assert payload["catalog_plan"]["planned_check_count"] == 2, payload commands = [check["command"] for check in payload["selected_checks"]] assert any("examples/canary/" in command for command in commands), payload assert all("canary-promotion" not in command for command in commands), payload assert any("examples/control_plane/control-plane-maintainability-ratchet-smoke.py" in command for command in commands), payload + assert any("examples/semantic-vocabulary-drift-smoke.py" in command for command in commands), payload def assert_cli_json_preview_works() -> None: diff --git a/examples/semantic-vocabulary-drift-smoke.py b/examples/semantic-vocabulary-drift-smoke.py new file mode 100755 index 0000000000..b5d3367778 --- /dev/null +++ b/examples/semantic-vocabulary-drift-smoke.py @@ -0,0 +1,425 @@ +#!/usr/bin/env python3 +"""Guard the repository's registered vocabularies against silent drift. + +``loopx/semantics/vocabulary_v0.json`` names each kernel and cross-runtime +vocabulary, the exact ``module::Symbol`` allowed to define it, how vocabularies +relate, and the budgets the repository ratchets down. ``inventory_v0.json`` is +the generated map of every closed-set carrier under ``loopx/``. This smoke +checks code against both so a PR that widens a vocabulary, forks a constant, +adds an unmapped carrier, or weakens the registry itself must show that change +in the same diff. It reads tracked sources only and prints no private data. +""" + +from __future__ import annotations + +import json +import re +import sys +from pathlib import Path +from typing import Any + +REPO_ROOT = Path(__file__).resolve().parents[1] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from loopx.semantics.inventory import ( # noqa: E402 + INVENTORY_SCHEMA_VERSION, + SourceFile, + build_inventory, + collect_string_constants, + load_sources, + python_facts, + render_inventory, + string_constant_definitions, + typescript_facts, +) + +REGISTRY_PATH = REPO_ROOT / "loopx" / "semantics" / "vocabulary_v0.json" +REGISTRY_SCHEMA_VERSION = "loopx_semantic_vocabulary_v0" +VALUE_SHAPE = re.compile(r"^[a-z][a-z0-9_]*$") +OWNER_SHAPE = re.compile(r"^[A-Za-z0-9_./-]+\.(py|ts)::[A-Za-z_][A-Za-z0-9_]*$") +QUOTED = re.compile(r'''["']([^"']*)["']''') + +REGISTRY_KEYS = { + "schema_version", "rfc", "inventory", "policy", "coverage_floor", "vocabularies", "relations", + "projections", "schema_versions", "retirement_ledger", "dual_runtime_twins", "inventory_ratchets", +} +VOCABULARY_KEYS = {"meaning", "tier", "status", "owners", "values"} +VOCABULARY_OPTIONAL_KEYS = {"literal_scan", "variable_sourced_values", "value_notes", "deprecated_values"} +TIERS = {"kernel", "cross_runtime", "cross_module"} +STATUSES = {"canonical", "legacy", "merge_candidate"} + +# Hard ceiling on the registry's own floors and budgets, kept in code rather than +# in the registry so one single-diff edit to ``vocabulary_v0.json`` cannot relax +# the ratchet that guards it. Same anchor pattern as +# ``tests/control_plane/test_m6_quality_gates.py::RFC_MODULE_BUDGETS``: the +# registry value must equal the anchor, so tightening a budget edits this literal +# and the JSON in one diff, and a later PR cannot raise the JSON back toward a stale +# anchor. A `<=` comparison would let every tightening below the anchor be undone +# silently; that is the gap the anchor exists to close. +COVERAGE_ANCHOR = { + "vocabularies": 26, + "owner_symbols": 46, + "literal_scan_fields": 1, + "projections": 1, + "relations": 9, + "schema_versions": 1, +} +COVERAGE_SUFFIX_ANCHOR = (".py", ".ts") +LITERAL_SCAN_ROOTS = ["loopx"] +TWIN_ROOT_ANCHOR = "loopx/control_plane" +TWIN_BUDGET_ANCHOR = 43 +BUDGET_ANCHOR = { + "same_runtime_forks": 25, + "same_runtime_fork_definitions": 58, + "conflicting_values": 18, + "conflicting_definitions": 59, + "schema_version_same_runtime_forks": 7, + "multi_value_twins": 19, + "multi_value_forks": 4, + "multi_value_fork_definitions": 10, + "same_runtime_forks_semantic": 18, + "conflicting_values_semantic": 2, +} +# Budgets for the legacy should-run decision fields, anchored the same way so a +# single diff cannot widen a retirement budget to keep a field alive. +RETIREMENT_ANCHOR = { + "execution_obligation": (21, 1), + "heartbeat_recommendation": (18, 1), + "work_lane_contract": (32, 3), + "external_evidence_observation": (11, 1), + "goal_boundary": (35, 2), + "protocol_action_packet": (7, 2), +} +RATCHET_KEYS = ( + "same_runtime_forks", + "same_runtime_fork_definitions", + "conflicting_values", + "conflicting_definitions", + "schema_version_same_runtime_forks", + "multi_value_twins", + "multi_value_forks", + "multi_value_fork_definitions", + "same_runtime_forks_semantic", + "conflicting_values_semantic", +) + +# Dispatch forms the literal scan recognises. Fixed here, not in the registry, so +# the registry cannot narrow what the scan sees. ``{f}`` is the field name. +DISPATCH_FORMS = ( + # Python/TypeScript comparisons, including wrapped field reads. + r"""{f}\b[^\n]*?(?:===|!==|==|!=)\s*["']([^"']*)["']""", + # Assignment or object/dict key. + r"""{f}["\'\]\)]*\s*(?::|=|\bis)\s*["']([^"']*)["']""", + # TypeScript conditional expression. + r"""{f}\b[^"\n]*?\?\s*["']([^"']*)["']\s*:\s*["']([^"']*)["']""", + # Membership in an inline collection. + r"""{f}["\'\]\)]*[^"\n]*?\bin\s*[\(\[\{{]([^\)\]\}}]*)[\)\]\}}]""", + # Python conditional expression. + r"""{f}\b[^"\n]*?=\s*["']([^"']*)["']\s+if\b[^"\n]*?\belse\s+["']([^"']*)["']""", +) +MEMBERSHIP_FORM_INDEX = 3 + + +class Drift(AssertionError): + pass + + +def require(condition: bool, message: str) -> None: + if not condition: + raise Drift(message) + + +# --- registry shape ----------------------------------------------------------------- + + +def load_registry() -> dict[str, Any]: + registry = json.loads(REGISTRY_PATH.read_text(encoding="utf-8")) + require(set(registry) == REGISTRY_KEYS, f"registry keys must be exactly {sorted(REGISTRY_KEYS)}") + require(registry["schema_version"] == REGISTRY_SCHEMA_VERSION, f"registry schema_version must be {REGISTRY_SCHEMA_VERSION}") + require((REPO_ROOT / registry["rfc"]).is_file(), f"registry must point at an existing RFC: {registry['rfc']}") + require((REPO_ROOT / registry["inventory"]).is_file(), f"registry must point at an existing inventory: {registry['inventory']}") + for name, vocabulary in registry["vocabularies"].items(): + require(VALUE_SHAPE.match(name) is not None, f"vocabulary name must be lower snake_case: {name}") + keys = set(vocabulary) + require(VOCABULARY_KEYS <= keys <= VOCABULARY_KEYS | VOCABULARY_OPTIONAL_KEYS, f"{name}: unexpected keys {sorted(keys ^ VOCABULARY_KEYS)}") + require(vocabulary["tier"] in TIERS, f"{name}: tier must be one of {sorted(TIERS)}") + require(vocabulary["status"] in STATUSES, f"{name}: status must be one of {sorted(STATUSES)}") + owners = vocabulary["owners"] + require(set(owners) == {"python", "typescript"}, f"{name}: owners must name python and typescript, each module::Symbol or null") + for runtime, owner in owners.items(): + if owner is None: + continue + require(OWNER_SHAPE.match(owner) is not None, f"{name}: {runtime} owner must be module::Symbol, got {owner!r}") + require(owner.endswith(".py::" + owner.split("::")[1]) if runtime == "python" else owner.split("::")[0].endswith(".ts"), f"{name}: {runtime} owner has the wrong suffix: {owner}") + require((REPO_ROOT / owner.split("::")[0]).is_file(), f"{name}: owner module does not exist: {owner}") + require(any(owners.values()) or "literal_scan" in vocabulary, f"{name}: a vocabulary with no owner symbol must declare a literal_scan") + values = vocabulary["values"] + require(isinstance(values, list) and values, f"{name}: values must be a non-empty list") + require(len(values) == len(set(values)), f"{name}: values repeat") + malformed = [value for value in values if not VALUE_SHAPE.match(value)] + require(not malformed, f"{name}: values must be lower snake_case: {malformed}") + for key in ("value_notes", "variable_sourced_values"): + extra = set(vocabulary.get(key, {})) - set(values) + require(not extra, f"{name}: {key} names unregistered values {sorted(extra)}") + require(set(vocabulary.get("deprecated_values", [])) <= set(values), f"{name}: deprecated_values must be a subset of values") + scan = vocabulary.get("literal_scan") + if scan is not None: + require(set(scan) == {"field", "roots", "suffixes"}, f"{name}: literal_scan keys must be field, roots, suffixes") + require(VALUE_SHAPE.match(scan["field"]) is not None, f"{name}: literal_scan.field must be an identifier") + return registry + + +def check_coverage_floor(registry: dict[str, Any]) -> str: + for vocabulary in registry["vocabularies"].values(): + if scan := vocabulary.get("literal_scan"): + require(scan["roots"] == LITERAL_SCAN_ROOTS, "literal_scan roots must cover loopx") + require(set(scan["suffixes"]) == set(COVERAGE_SUFFIX_ANCHOR), "literal_scan must cover both Python and TypeScript") + floor = registry["coverage_floor"] + actual = { + "vocabularies": len(registry["vocabularies"]), + "owner_symbols": sum(1 for v in registry["vocabularies"].values() for o in v["owners"].values() if o), + "literal_scan_fields": sum(1 for v in registry["vocabularies"].values() if "literal_scan" in v), + "projections": len(registry["projections"]), + "relations": sum(len(group) for group in registry["relations"].values()), + "schema_versions": len(registry["schema_versions"]), + } + for key, count in actual.items(): + require(count >= floor[key], f"coverage_floor.{key} is {floor[key]} but the registry now has {count}; coverage may only grow") + declared_suffixes = {s for v in registry["vocabularies"].values() for s in v.get("literal_scan", {}).get("suffixes", [])} + require(set(floor["literal_scan_suffixes"]) <= declared_suffixes, f"literal scans must still cover {floor['literal_scan_suffixes']}; declared {sorted(declared_suffixes)}") + for key, anchored in COVERAGE_ANCHOR.items(): + require( + floor[key] == anchored, + f"coverage_floor.{key} is {floor[key]} but COVERAGE_ANCHOR pins {anchored}; " + "the registry and the anchor move together in one diff (see COVERAGE_ANCHOR in this smoke)", + ) + for suffix in COVERAGE_SUFFIX_ANCHOR: + require(suffix in set(floor["literal_scan_suffixes"]), f"coverage_floor.literal_scan_suffixes dropped the anchored suffix {suffix}") + return "coverage=" + ",".join(f"{key}:{count}/{floor[key]}" for key, count in actual.items()) + + +# --- owners and closed sets ----------------------------------------------------------- + + +def source(path: str) -> SourceFile: + file = REPO_ROOT / path + return SourceFile(path=path, suffix=file.suffix, text=file.read_text(encoding="utf-8", errors="replace")) + + +def owner_values(owner: str) -> list[str]: + module, symbol = owner.split("::") + facts = python_facts(source(module)) if module.endswith(".py") else typescript_facts(source(module)) + sections = ("enums", "closed_sets", "literal_aliases") if module.endswith(".py") else ("const_arrays",) + for section in sections: + for entry in facts[section]: + if entry["name"] == symbol: + return list(entry["values"]) + raise Drift(f"{module} does not define a string enum, closed set, Literal alias, or as-const array named {symbol}") + + +def assert_closed_set(label: str, actual: list[str], expected: list[str]) -> None: + require(len(actual) == len(set(actual)), f"{label} repeats a value: {actual}") + missing = sorted(set(expected) - set(actual)) + unregistered = sorted(set(actual) - set(expected)) + require(not missing and not unregistered, f"{label} drifted from the registry; missing={missing} unregistered={unregistered}") + + +def check_owned_vocabularies(registry: dict[str, Any], inventory: dict[str, Any]) -> None: + defined_in: dict[str, set[str]] = {} + for section in ("python_enums", "python_closed_sets", "python_literal_aliases", "typescript_const_arrays"): + for entry in inventory[section]: + defined_in.setdefault(entry["name"], set()).add(entry["module"]) + problems: list[str] = [] + for name, vocabulary in registry["vocabularies"].items(): + owners = [owner for owner in vocabulary["owners"].values() if owner] + for owner in owners: + try: + assert_closed_set(f"{name} owner {owner}", owner_values(owner), vocabulary["values"]) + except Drift as error: + problems.append(str(error)) + # I1: a registered symbol name is defined only in its owner modules. + for owner in owners: + _module, symbol = owner.split("::") + others = sorted(defined_in.get(symbol, set()) - {o.split("::")[0] for o in owners}) + if others: + problems.append(f"{name}: {symbol} is also defined in {others}; only the registered owners may define it") + require(not problems, "owned vocabularies drifted:\n " + "\n ".join(problems)) + + +# --- literal scan ------------------------------------------------------------------- + + +def scan_literals(field: str, roots: list[str], suffixes: list[str], sources: list[SourceFile]) -> dict[str, set[str]]: + observed: dict[str, set[str]] = {} + forms = [re.compile(form.format(f=re.escape(field))) for form in DISPATCH_FORMS] + for root in roots: + for file in sources: + if file.suffix not in suffixes or not file.path.startswith(root.rstrip("/") + "/"): + continue + for index, form in enumerate(forms): + for match in form.finditer(file.text): + tokens = QUOTED.findall(match.group(1)) if index == MEMBERSHIP_FORM_INDEX else list(match.groups()) + for token in tokens: + if token == "": + continue # ``?? ""`` and ``or ""`` clear the field; not a value + observed.setdefault(token, set()).add(file.path) + return observed + + +def check_literal_vocabularies(registry: dict[str, Any], sources: list[SourceFile]) -> None: + for name, vocabulary in registry["vocabularies"].items(): + scan = vocabulary.get("literal_scan") + if not scan: + continue + observed = scan_literals(scan["field"], scan["roots"], scan["suffixes"], sources) + expected = set(vocabulary["values"]) + unregistered = {value: sorted(files) for value, files in observed.items() if value not in expected} + require(not unregistered, f"{name}: literals not in the registry (register them or use a registered value): {unregistered}") + variable_sourced = vocabulary.get("variable_sourced_values", {}) + for value, producer in variable_sourced.items(): + text = (REPO_ROOT / producer).read_text(encoding="utf-8", errors="replace") + require(f'"{value}"' in text, f"{name}: variable-sourced value {value} is no longer produced by {producer}") + unused = sorted(expected - set(observed) - set(variable_sourced)) + require(not unused, f"{name}: registry lists values no module carries: {unused}") + + +# --- relations, projections, schema versions ---------------------------------------- + + +def check_relations(registry: dict[str, Any]) -> None: + vocabularies = registry["vocabularies"] + + def resolve(member: str) -> None: + vocabulary, _, value = member.partition(".") + require(vocabulary in vocabularies, f"relation member names unknown vocabulary: {member}") + require(value in vocabularies[vocabulary]["values"], f"relation member does not resolve: {member}") + + for group in registry["relations"]["same_concept"]: + require(len(group["members"]) >= 2, f"same_concept {group['concept']} needs two members") + for member in group["members"]: + resolve(member) + for shared in registry["relations"]["shared_field_names"]: + for slot in shared["slots"]: + if "vocabulary" in slot: + require(slot["vocabulary"] in vocabularies, f"shared field slot names unknown vocabulary {slot['vocabulary']}") + else: + for value in slot["values"]: + resolve(f"{shared['field']}.{value}") + for subset in registry["relations"]["subsets"]: + require(subset["superset"] in vocabularies, f"subset {subset['name']} names unknown superset {subset['superset']}") + superset = set(vocabularies[subset["superset"]]["values"]) + expected = superset - set(subset["excluded"]) + require(set(subset["excluded"]) <= superset, f"subset {subset['name']} excludes values outside {subset['superset']}") + for owner in subset["owners"].values(): + if owner: + assert_closed_set(f"subset {subset['name']} owner {owner}", owner_values(owner), sorted(expected)) + + +def check_projections(registry: dict[str, Any]) -> None: + projection = registry["projections"]["turn_route_to_loop_disposition"] + from loopx.control_plane.turn_driver.driver import LoopXTurnRoute + from loopx.control_plane.turn_driver.loop_controller import LoopDisposition, _route_to_disposition + + mapping = projection["mapping"] + routes = registry["vocabularies"]["turn_route"]["values"] + require(sorted(mapping) == sorted(routes), "projection must name every turn_route exactly once") + for route, expected in mapping.items(): + try: + actual = _route_to_disposition(LoopXTurnRoute(route)) + except KeyError: + require(expected is None, f"route {route} is rejected by the controller but the registry maps it to {expected}") + continue + require(expected is not None, f"route {route} is registered as rejected but projects {actual.value}") + require(actual is LoopDisposition(expected), f"route {route} projects {actual.value}, registry says {expected}") + + +def check_schema_version_owners(registry: dict[str, Any], sources: list[SourceFile]) -> None: + definitions = string_constant_definitions(collect_string_constants(sources)) + for name, entry in registry["schema_versions"].items(): + defining = definitions.get(entry["constant"], []) + modules = sorted(item["module"] for item in defining) + require(modules == sorted(entry["owner_modules"]), f"schema version {name} is defined in {modules}; registry owners are {entry['owner_modules']}") + values = {item["value"] for item in defining} + require(values == {entry["value"]}, f"schema version {name} carries {sorted(values)}; registry says {entry['value']}") + + +# --- ratchets ----------------------------------------------------------------------- + + +def check_retirement_budgets(registry: dict[str, Any], sources: list[SourceFile]) -> list[str]: + report: list[str] = [] + ledger = registry["retirement_ledger"]["should_run_legacy_decision_fields"]["fields"] + require(set(ledger) == set(RETIREMENT_ANCHOR), f"retirement ledger fields are {sorted(ledger)}; the anchored set is {sorted(RETIREMENT_ANCHOR)}") + for field, budgets in ledger.items(): + for suffix, key, anchored in ( + (".py", "python_module_budget", RETIREMENT_ANCHOR[field][0]), + (".ts", "typescript_module_budget", RETIREMENT_ANCHOR[field][1]), + ): + actual = sum(1 for file in sources if file.suffix == suffix and field in file.text) + require(actual <= budgets[key], f"legacy field {field} grew to {actual} {suffix} modules; budget is {budgets[key]}") + require( + budgets[key] == anchored, + f"legacy field {field} {suffix} budget is {budgets[key]} but RETIREMENT_ANCHOR pins {anchored}; " + "the registry and the anchor move together in one diff (see RETIREMENT_ANCHOR in this smoke)", + ) + report.append(f"{field}{suffix}={actual}/{budgets[key]}") + return report + + +def check_dual_runtime_twins(registry: dict[str, Any]) -> str: + entry = registry["dual_runtime_twins"] + require(entry["root"] == TWIN_ROOT_ANCHOR, "dual_runtime_twins root differs from TWIN_ROOT_ANCHOR") + require(entry["module_budget"] == TWIN_BUDGET_ANCHOR, "dual_runtime_twins budget differs from TWIN_BUDGET_ANCHOR") + paths = {file.path for file in load_sources(REPO_ROOT, entry["root"])} + twins = sorted(path for path in paths if path.endswith(".py") and not path.endswith("/__init__.py") and path[:-3] + ".ts" in paths) + require(len(twins) <= entry["module_budget"], f"{len(twins)} py/ts twin modules under {entry['root']}; budget is {entry['module_budget']}") + return f"twins={len(twins)}/{entry['module_budget']}" + + +def check_inventory(registry: dict[str, Any], sources: list[SourceFile]) -> tuple[dict[str, Any], str]: + inventory_path = REPO_ROOT / registry["inventory"] + committed = inventory_path.read_text(encoding="utf-8") + inventory = build_inventory(REPO_ROOT, sources=sources) + require(inventory["schema_version"] == INVENTORY_SCHEMA_VERSION, "inventory schema drift") + require(render_inventory(inventory) == committed, f"{registry['inventory']} is stale; run python3.11 scripts/generate_semantic_inventory.py and commit the result") + ratchets = registry["inventory_ratchets"] + summary = inventory["summary"] + parts = [] + for key in RATCHET_KEYS: + require(summary[key] <= ratchets[key], f"inventory {key} grew to {summary[key]}; budget is {ratchets[key]}") + require( + ratchets[key] == BUDGET_ANCHOR[key], + f"inventory {key} budget is {ratchets[key]} but BUDGET_ANCHOR pins {BUDGET_ANCHOR[key]}; " + "the registry and the anchor move together in one diff (see BUDGET_ANCHOR in this smoke)", + ) + parts.append(f"{key}={summary[key]}/{ratchets[key]}") + return inventory, " ".join(parts) + + +def main() -> int: + registry = load_registry() + coverage = check_coverage_floor(registry) + sources = load_sources(REPO_ROOT) + inventory, ratchets = check_inventory(registry, sources) + check_owned_vocabularies(registry, inventory) + check_literal_vocabularies(registry, sources) + check_relations(registry) + check_projections(registry) + check_schema_version_owners(registry, sources) + budgets = check_retirement_budgets(registry, sources) + twins = check_dual_runtime_twins(registry) + print("semantic-vocabulary-drift-smoke: ok") + print(" " + coverage) + print(" " + ratchets) + print(" " + " ".join(budgets)) + print(" " + twins) + return 0 + + +if __name__ == "__main__": + try: + raise SystemExit(main()) + except Drift as error: + print(f"semantic-vocabulary-drift-smoke: FAIL\n {error}", file=sys.stderr) + raise SystemExit(1) diff --git a/loopx/canary/planner.py b/loopx/canary/planner.py index 129e80837c..52071c84fd 100644 --- a/loopx/canary/planner.py +++ b/loopx/canary/planner.py @@ -384,6 +384,14 @@ "underlying debt has been retired" ), }, + { + "command": "python3 examples/semantic-vocabulary-drift-smoke.py", + "tier": "default", + "reason": ( + "fails on an unregistered vocabulary value, a forked owner symbol, " + "a stale semantic inventory, or a raised collision or retirement budget" + ), + }, ], }, *CONTROL_PLANE_QUALIFICATION_PROFILES, diff --git a/loopx/canary/premerge.py b/loopx/canary/premerge.py index 030bac6f02..9a727bbc88 100644 --- a/loopx/canary/premerge.py +++ b/loopx/canary/premerge.py @@ -754,7 +754,9 @@ def _tier_limits(tier: str) -> dict[str, int | bool]: return {"catalog_limit": 3, "profile_limit": 0, "deep": False} if normalized == "deep": return {"catalog_limit": 0, "profile_limit": 0, "deep": True} - return {"catalog_limit": 9, "profile_limit": 8, "deep": False} + # Reserve the added vocabulary check without displacing the existing + # state-machine and heartbeat/quota checks in the standard catalog slice. + return {"catalog_limit": 10, "profile_limit": 8, "deep": False} def build_premerge_validation_gate( diff --git a/loopx/control_plane/testing/authority_e2e_fixtures.py b/loopx/control_plane/testing/authority_e2e_fixtures.py index 4bc996b0c2..5ced733753 100644 --- a/loopx/control_plane/testing/authority_e2e_fixtures.py +++ b/loopx/control_plane/testing/authority_e2e_fixtures.py @@ -22,6 +22,7 @@ from typing import Any, Protocol from ...file_lock import exclusive_file_lock +from ..coordination.authority_core import HandoffMode from ..coordination.coordination_state_contract_generated import ( LOCAL_AUTHORITY_SHADOW_CONFIG_SCHEMA, ) @@ -30,7 +31,7 @@ TS_READBACK_PROBE = Path("tests") / "control_plane_ts" / "authority_store_readback_probe.ts" DEFAULT_REGISTERED_AGENTS: tuple[str, ...] = ("agent-a", "agent-b") RUNTIME_ROOT_BINDINGS: tuple[str, ...] = ("registry", "cli_override", "cli_override_divergent") -HANDOFF_MODES: tuple[str, ...] = ("legacy", "soft_claim", "hard_lease") +HANDOFF_MODES: tuple[str, ...] = tuple(mode.value for mode in HandoffMode) LOCAL_AUTHORITY_SHADOW_CONFIG = { "schema_version": LOCAL_AUTHORITY_SHADOW_CONFIG_SCHEMA, "mode": "file_one_way", diff --git a/loopx/control_plane/turn_driver/driver.py b/loopx/control_plane/turn_driver/driver.py index d5d06734f3..acd414495e 100644 --- a/loopx/control_plane/turn_driver/driver.py +++ b/loopx/control_plane/turn_driver/driver.py @@ -15,7 +15,10 @@ bind_child_operations_to_topology, build_subagent_execution_topology, ) -from ..quota.turn_envelope import turn_envelope_action_signature_document +from ..quota.turn_envelope import ( + TURN_ENVELOPE_SCHEMA_VERSION, + turn_envelope_action_signature_document, +) from ..scheduler.execution_context import ( scheduler_execution_context_for_turn, ) @@ -28,7 +31,6 @@ "loopx_iteration_context_policy_v0" ) LOOPX_CHILD_HOST_OPERATION_SCHEMA_VERSION = "loopx_child_host_operation_v0" -TURN_ENVELOPE_SCHEMA_VERSION = "loopx_turn_envelope_v0" SUPPORTED_HOSTS = {"codex-cli", "claude-code", "dsh", "generic-cli"} SUPPORTED_EXECUTION_MODES = {"interactive-visible", "isolated-headless"} SUPPORTED_ITERATION_CONTEXT_POLICIES = {"fresh", "resume_if_available"} diff --git a/loopx/semantics/__init__.py b/loopx/semantics/__init__.py new file mode 100644 index 0000000000..5011a36f97 --- /dev/null +++ b/loopx/semantics/__init__.py @@ -0,0 +1,7 @@ +"""Repository-wide semantic vocabulary registry and inventory. + +``vocabulary_v0.json`` is the curated registry (what each cross-module vocabulary +may carry, who defines it, how vocabularies relate). ``inventory_v0.json`` is the +generated map of every closed-set vocabulary carrier under ``loopx/``. Both are +checked, never imported, by product code; see the semantic vocabulary RFC. +""" diff --git a/loopx/semantics/inventory.py b/loopx/semantics/inventory.py new file mode 100644 index 0000000000..02a05716ea --- /dev/null +++ b/loopx/semantics/inventory.py @@ -0,0 +1,457 @@ +"""Scan ``loopx/`` for every carrier of a closed-set vocabulary. + +The inventory is the repository-wide map behind the curated registry. It is +generated by ``scripts/generate_semantic_inventory.py`` and checked for +freshness by the drift smoke, so a PR that adds an enum, a ``Literal`` alias, a +TypeScript ``as const`` array, a named closed set, or a schema-version constant +shows that addition in a reviewable JSON diff. Nothing here is imported by +product code. +""" + +from __future__ import annotations + +import ast +from collections import defaultdict +from dataclasses import dataclass +from pathlib import Path +import re +import subprocess +from typing import Any + +INVENTORY_SCHEMA_VERSION = "loopx_semantic_inventory_v0" +DEFAULT_ROOT = "loopx" +SOURCE_SUFFIXES = (".py", ".ts") +SKIP_PARTS = frozenset({"__pycache__", "node_modules"}) + +UPPER_NAME = re.compile(r"^[A-Z][A-Z0-9_]*$") +SCHEMA_VERSION_NAME = re.compile(r"SCHEMA_VERSION$") +# Names that are a per-module convention rather than shared vocabulary: every +# module legitimately names its own ``SCHEMA_VERSION``, ``COMMAND``, or +# ``*_LABEL``. Counting them as vocabulary conflicts measured local naming, not +# drift, so they are reported but kept out of the semantic budgets. +MODULE_LOCAL_CONVENTION = re.compile( + r"^(?:SCHEMA_VERSION|[A-Z][A-Z0-9_]*_SCHEMA_VERSION|COMMAND|REQUEST_SCHEMA|SURFACE|" + r"HOOK_ID|CAPABILITY_ID|DEFAULT_AGENT_ID|[A-Z][A-Z0-9_]*_LABEL|OWNER|NAME|VERSION|KIND|" + r"STATUS|MODE)$" +) +TS_CONST_ARRAY = re.compile( + r"^export const (?P[A-Z][A-Z0-9_]*)\s*(?::[^=\n]+)?=\s*\[(?P.*?)\]\s*as const;", + re.MULTILINE | re.DOTALL, +) +TS_STRING_CONST = re.compile( + r'''^export const (?P[A-Z][A-Z0-9_]*)\s*(?::\s*string)?\s*=\s*["\'](?P[^"\']*)["\'];''', + re.MULTILINE, +) +QUOTED = re.compile(r'''["']([^"']*)["']''') + + +@dataclass(frozen=True) +class SourceFile: + path: str + suffix: str + text: str + + +def load_sources(repo_root: Path, root: str = DEFAULT_ROOT) -> list[SourceFile]: + files: list[SourceFile] = [] + # Use the index as the source boundary, matching the repository canary + # policy. Untracked work and ignored local notes must never enter the map. + tracked = subprocess.run( + ["git", "ls-files", "--cached", "-z", "--", root], + cwd=repo_root, check=True, stdout=subprocess.PIPE, + ).stdout.decode("utf-8").split("\0") + for relative in sorted(set(tracked) - {""}): + path = repo_root / relative + if path.is_symlink(): + raise ValueError(f"tracked source must not be a symlink: {relative}") + if not path.is_file() or path.suffix not in SOURCE_SUFFIXES: + continue + if SKIP_PARTS.intersection(path.parts): + continue + files.append( + SourceFile( + path=path.relative_to(repo_root).as_posix(), + suffix=path.suffix, + text=path.read_text(encoding="utf-8", errors="replace"), + ) + ) + return files + + +def _is_enum_class(node: ast.ClassDef) -> bool: + for base in node.bases: + name = base.id if isinstance(base, ast.Name) else getattr(base, "attr", "") + if name.endswith("Enum"): + return True + return False + + +def _string_elements(node: ast.AST) -> list[str] | None: + if isinstance(node, ast.Call) and isinstance(node.func, ast.Name): + if node.func.id in {"frozenset", "set", "tuple", "list"} and len(node.args) == 1: + return _string_elements(node.args[0]) + return None + if isinstance(node, (ast.Tuple, ast.Set, ast.List)): + values: list[str] = [] + for element in node.elts: + if not isinstance(element, ast.Constant) or not isinstance(element.value, str): + return None + values.append(element.value) + return values + return None + + +def _container_name(node: ast.AST) -> str: + if isinstance(node, ast.Call) and isinstance(node.func, ast.Name): + return node.func.id + return type(node).__name__.lower() + + +def _assigned_name(node: ast.AST) -> tuple[str, ast.AST] | None: + if isinstance(node, ast.Assign) and len(node.targets) == 1 and isinstance(node.targets[0], ast.Name): + return node.targets[0].id, node.value + if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name) and node.value is not None: + return node.target.id, node.value + return None + + +def python_facts(source: SourceFile) -> dict[str, list[dict[str, Any]]]: + facts: dict[str, list[dict[str, Any]]] = { + "enums": [], + "closed_sets": [], + "literal_aliases": [], + "string_constants": [], + } + try: + tree = ast.parse(source.text) + except SyntaxError as error: + raise ValueError(f"cannot inventory invalid Python source: {source.path}:{error.lineno}") from None + for node in tree.body: + if isinstance(node, ast.ClassDef) and _is_enum_class(node): + values: list[str] = [] + string_valued = True + for item in node.body: + assigned = _assigned_name(item) + if assigned is None: + continue + name, value = assigned + if name.startswith("_"): + continue + if isinstance(value, ast.Constant) and isinstance(value.value, str): + values.append(value.value) + else: + string_valued = False + if values and string_valued: + facts["enums"].append({"name": node.name, "module": source.path, "values": values}) + continue + assigned = _assigned_name(node) + if assigned is None: + continue + name, value = assigned + if isinstance(value, ast.Subscript) and isinstance(value.value, ast.Name) and value.value.id == "Literal": + elements = _string_elements(value.slice) if isinstance(value.slice, ast.Tuple) else None + if elements is None and isinstance(value.slice, ast.Constant) and isinstance(value.slice.value, str): + elements = [value.slice.value] + if elements: + facts["literal_aliases"].append({"name": name, "module": source.path, "values": elements}) + continue + if not UPPER_NAME.match(name): + continue + if isinstance(value, ast.Constant) and isinstance(value.value, str): + facts["string_constants"].append({"name": name, "module": source.path, "value": value.value}) + continue + elements = _string_elements(value) + if elements is not None and len(elements) >= 2: + facts["closed_sets"].append( + { + "name": name, + "module": source.path, + "container": _container_name(value), + "values": elements, + } + ) + return facts + + +def typescript_facts(source: SourceFile) -> dict[str, list[dict[str, Any]]]: + facts: dict[str, list[dict[str, Any]]] = {"const_arrays": [], "string_constants": []} + for match in TS_CONST_ARRAY.finditer(source.text): + values = QUOTED.findall(match.group("body")) + if values: + facts["const_arrays"].append( + {"name": match.group("name"), "module": source.path, "values": values} + ) + for match in TS_STRING_CONST.finditer(source.text): + facts["string_constants"].append( + {"name": match.group("name"), "module": source.path, "value": match.group("value")} + ) + return facts + + +def _duplicate_kind(modules: list[str]) -> str: + """One .py plus one .ts definition is a runtime twin; anything else is a fork.""" + suffixes = sorted(Path(module).suffix for module in modules) + return "cross_runtime_twin" if suffixes == [".py", ".ts"] else "same_runtime_fork" + + +def multi_value_carriers( + *, + enums: list[dict[str, Any]], + closed_sets: list[dict[str, Any]], + literal_aliases: list[dict[str, Any]], + const_arrays: list[dict[str, Any]], +) -> list[dict[str, Any]]: + """Tag each scan section with the carrier kind the collision report prints.""" + carriers: list[dict[str, Any]] = [] + for kind, entries in zip( + ("python_enum", "python_closed_set", "python_literal_alias", "typescript_const_array"), + (enums, closed_sets, literal_aliases, const_arrays), + strict=True, + ): + carriers.extend({**entry, "kind": kind} for entry in entries) + return carriers + + +def multi_value_name_collisions( + carriers: list[dict[str, Any]], +) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]: + """Group multi-value carriers by name to find collisions between modules. + + A string constant is ``NAME = "value"``; a multi-value carrier is an enum, a + named closed set, a ``Literal`` alias, or a TypeScript ``as const`` array. + Both carry vocabulary, so both need the same collision rule: one name defined + in two modules with identical values is a twin, with different values is a + fork. Each entry keeps every defining module and its value set, so a reviewer + sees the divergence rather than a count. + """ + by_name: dict[str, list[dict[str, Any]]] = defaultdict(list) + for carrier in carriers: + by_name[carrier["name"]].append(carrier) + twins: list[dict[str, Any]] = [] + forks: list[dict[str, Any]] = [] + for name, carriers_for_name in sorted(by_name.items()): + if len(carriers_for_name) < 2: + continue + definitions = sorted( + ( + {"kind": item["kind"], "module": item["module"], "values": list(item["values"])} + for item in carriers_for_name + ), + key=lambda item: item["module"], + ) + entry: dict[str, Any] = {"name": name, "definitions": definitions} + if len({tuple(item["values"]) for item in definitions}) == 1: + entry["values"] = definitions[0]["values"] + entry["modules"] = [item["module"] for item in definitions] + twins.append(entry) + else: + forks.append(entry) + return twins, forks + + +def _sorted_entries(entries: list[dict[str, Any]]) -> list[dict[str, Any]]: + return sorted(entries, key=lambda entry: (entry["module"], entry["name"])) + + +def build_inventory( + repo_root: Path, root: str = DEFAULT_ROOT, sources: list[SourceFile] | None = None +) -> dict[str, Any]: + if sources is None: + sources = load_sources(repo_root, root) + enums: list[dict[str, Any]] = [] + closed_sets: list[dict[str, Any]] = [] + literal_aliases: list[dict[str, Any]] = [] + const_arrays: list[dict[str, Any]] = [] + string_constants: list[dict[str, Any]] = [] + for source in sources: + if source.suffix == ".py": + facts = python_facts(source) + enums.extend(facts["enums"]) + closed_sets.extend(facts["closed_sets"]) + literal_aliases.extend(facts["literal_aliases"]) + string_constants.extend(facts["string_constants"]) + else: + facts = typescript_facts(source) + const_arrays.extend(facts["const_arrays"]) + string_constants.extend(facts["string_constants"]) + + multi_value = multi_value_carriers( + enums=enums, + closed_sets=closed_sets, + literal_aliases=literal_aliases, + const_arrays=const_arrays, + ) + multi_twins, multi_forks = multi_value_name_collisions(multi_value) + + definitions = string_constant_definitions(string_constants) + twins: list[dict[str, Any]] = [] + forks: list[dict[str, Any]] = [] + conflicting: list[dict[str, Any]] = [] + for name, defs in sorted(definitions.items()): + if len(defs) < 2: + continue + modules = [item["module"] for item in defs] + entry: dict[str, Any] = {"name": name, "is_schema_version": bool(SCHEMA_VERSION_NAME.search(name))} + if len({item["value"] for item in defs}) == 1: + entry.update({"value": defs[0]["value"], "modules": modules}) + (twins if _duplicate_kind(modules) == "cross_runtime_twin" else forks).append(entry) + else: + entry["definitions"] = defs + conflicting.append(entry) + + return { + "schema_version": INVENTORY_SCHEMA_VERSION, + "root": root, + "generator": "scripts/generate_semantic_inventory.py", + "advisory": ( + "Structural map only. Consumer counts are printed by the generator's --report " + "and are not committed. Single-module string constants are counted, not listed." + ), + "python_enums": _sorted_entries(enums), + "python_closed_sets": _sorted_entries(closed_sets), + "python_literal_aliases": _sorted_entries(literal_aliases), + "typescript_const_arrays": _sorted_entries(const_arrays), + "duplicate_definitions": { + "cross_runtime_twins": twins, + "same_runtime_forks": forks, + "conflicting_values": conflicting, + "multi_value_twins": multi_twins, + "multi_value_forks": multi_forks, + }, + "summary": { + "source_files": len(sources), + "python_enums": len(enums), + "python_closed_sets": len(closed_sets), + "python_literal_aliases": len(literal_aliases), + "typescript_const_arrays": len(const_arrays), + "named_string_constants": len(string_constants), + "schema_version_names": sum(1 for name in definitions if SCHEMA_VERSION_NAME.search(name)), + "schema_version_same_runtime_forks": sum(1 for item in forks if item["is_schema_version"]), + "cross_runtime_twins": len(twins), + "same_runtime_forks": len(forks), + "same_runtime_fork_definitions": sum(len(item["modules"]) for item in forks), + "conflicting_values": len(conflicting), + "conflicting_definitions": sum(len(item["definitions"]) for item in conflicting), + "multi_value_twins": len(multi_twins), + "multi_value_forks": len(multi_forks), + "multi_value_fork_definitions": sum(len(item["definitions"]) for item in multi_forks), + "same_runtime_forks_semantic": sum( + 1 for item in forks if not MODULE_LOCAL_CONVENTION.match(item["name"]) + ), + "conflicting_values_semantic": sum( + 1 for item in conflicting if not MODULE_LOCAL_CONVENTION.match(item["name"]) + ), + }, + } + + +def string_constant_definitions(string_constants: list[dict[str, Any]]) -> dict[str, list[dict[str, Any]]]: + """Group ``NAME = "value"`` definitions by constant name, modules sorted.""" + by_name: dict[str, list[dict[str, Any]]] = defaultdict(list) + for entry in string_constants: + by_name[entry["name"]].append({"module": entry["module"], "value": entry["value"]}) + return {name: sorted(defs, key=lambda item: item["module"]) for name, defs in by_name.items()} + + +def collect_string_constants(sources: list[SourceFile]) -> list[dict[str, Any]]: + constants: list[dict[str, Any]] = [] + for source in sources: + facts = python_facts(source) if source.suffix == ".py" else typescript_facts(source) + constants.extend(facts["string_constants"]) + return constants + + +def render_inventory(inventory: dict[str, Any]) -> str: + """Two-space indented JSON with one line per inventory entry for readable diffs.""" + import json + + def one_line(value: Any) -> str: + return json.dumps(value, ensure_ascii=False, separators=(", ", ": ")) + + lines = ["{"] + keys = list(inventory) + for index, key in enumerate(keys): + value = inventory[key] + comma = "," if index < len(keys) - 1 else "" + if isinstance(value, list): + if not value: + lines.append(f' "{key}": []{comma}') + continue + lines.append(f' "{key}": [') + for position, entry in enumerate(value): + lines.append(" " + one_line(entry) + ("," if position < len(value) - 1 else "")) + lines.append(f" ]{comma}") + elif isinstance(value, dict) and value and all(isinstance(item, list) for item in value.values()): + lines.append(f' "{key}": {{') + inner_keys = list(value) + for inner_index, inner_key in enumerate(inner_keys): + entries = value[inner_key] + inner_comma = "," if inner_index < len(inner_keys) - 1 else "" + if not entries: + lines.append(f' "{inner_key}": []{inner_comma}') + continue + lines.append(f' "{inner_key}": [') + for position, entry in enumerate(entries): + lines.append(" " + one_line(entry) + ("," if position < len(entries) - 1 else "")) + lines.append(f" ]{inner_comma}") + lines.append(f" }}{comma}") + else: + rendered = json.dumps(value, ensure_ascii=False, indent=2) + rendered = "\n".join((" " + line) if i else line for i, line in enumerate(rendered.splitlines())) + lines.append(f' "{key}": {rendered}{comma}') + lines.append("}") + return "\n".join(lines) + "\n" + + +def merge_candidate_groups(inventory: dict[str, Any]) -> list[dict[str, Any]]: + """Advisory: distinct names carrying an identical multi-value set. + + Value-set equality is a candidate signal, not proof of one concept: + ``CONFIDENCE_LEVELS`` and ``EDGE_CASE_COMPLEXITIES`` share ``high/low/medium`` + while meaning different things. Each group is for review, never auto-merged, + and is printed on demand rather than committed so it cannot be mistaken for a + ratified decision. + """ + by_values: dict[tuple[str, ...], list[dict[str, Any]]] = defaultdict(list) + for section in ("python_enums", "python_closed_sets", "python_literal_aliases", "typescript_const_arrays"): + for entry in inventory[section]: + if len(entry["values"]) >= 2: + by_values[tuple(sorted(entry["values"]))].append(entry) + groups: list[dict[str, Any]] = [] + for values, entries in by_values.items(): + names = sorted({entry["name"] for entry in entries}) + if len(names) < 2: + continue + groups.append( + { + "names": names, + "values": list(values), + "modules": sorted({entry["module"] for entry in entries}), + } + ) + return sorted(groups, key=lambda group: (-len(group["names"]), group["names"])) + + +def consumer_ranking(inventory: dict[str, Any], sources: list[SourceFile]) -> list[dict[str, Any]]: + """Advisory ranking: modules outside the definer that mention each symbol. + + Not stored in the committed inventory because it changes with every consumer + edit; the generator prints it on demand so retirement work can be ordered. + """ + ranking: list[dict[str, Any]] = [] + for section in ("python_enums", "typescript_const_arrays", "python_closed_sets", "python_literal_aliases"): + for entry in inventory[section]: + token = re.compile(rf"\b{re.escape(entry['name'])}\b") + consumers = sum( + 1 for source in sources if source.path != entry["module"] and token.search(source.text) + ) + ranking.append( + { + "kind": section, + "name": entry["name"], + "module": entry["module"], + "values": len(entry["values"]), + "external_consumer_modules": consumers, + } + ) + return sorted(ranking, key=lambda item: (-item["external_consumer_modules"], item["module"], item["name"])) diff --git a/loopx/semantics/inventory_v0.json b/loopx/semantics/inventory_v0.json new file mode 100644 index 0000000000..0653aae0ae --- /dev/null +++ b/loopx/semantics/inventory_v0.json @@ -0,0 +1,924 @@ +{ + "schema_version": "loopx_semantic_inventory_v0", + "root": "loopx", + "generator": "scripts/generate_semantic_inventory.py", + "advisory": "Structural map only. Consumer counts are printed by the generator's --report and are not committed. Single-module string constants are counted, not listed.", + "python_enums": [ + {"name": "BenchmarkContinuationDecision", "module": "loopx/capabilities/benchmark_toolkit/continuation.py", "values": ["continue", "stop_complete", "stop_progress_regression", "stop_prompt_mismatch", "stop_round_limit", "stop_task_shape_mismatch", "stop_time_budget"]}, + {"name": "NetworkRequestScope", "module": "loopx/capabilities/benchmark_toolkit/integrity.py", "values": ["none", "loopback", "external"]}, + {"name": "RestrictedAccessAdjudicationDecision", "module": "loopx/capabilities/benchmark_toolkit/integrity.py", "values": ["qualified_with_warning", "confirmed_cheating"]}, + {"name": "PublicTrajectoryLifecycleState", "module": "loopx/capabilities/benchmark_toolkit/public_trajectory.py", "values": ["attached", "in_progress", "turn_terminal", "goal_terminal"]}, + {"name": "RunPermissionAction", "module": "loopx/capabilities/benchmark_toolkit/run_permissions.py", "values": ["codex_model_invocation", "local_docker_runner", "local_harbor_runner", "benchmark_dependency_fetch", "compact_result_reduction", "public_result_upload", "leaderboard_submission", "public_benchmark_claim", "production_cloud_action", "credential_sync", "raw_artifact_publication"]}, + {"name": "BenchmarkEventWindowState", "module": "loopx/capabilities/benchmark_toolkit/runtime_continuity.py", "values": ["qualified", "missing", "ambiguous", "outside_launch_window"]}, + {"name": "BenchmarkRuntimeContinuityClassification", "module": "loopx/capabilities/benchmark_toolkit/runtime_continuity.py", "values": ["continuity_input_invalid", "qualified", "generation_mismatch", "runtime_artifact_mismatch", "event_window_missing", "event_window_ambiguous", "event_window_outside_launch"]}, + {"name": "BenchmarkRuntimeContinuityTransition", "module": "loopx/capabilities/benchmark_toolkit/runtime_continuity.py", "values": ["repair_continuity_evidence", "accept_closeout", "route_to_launch_generation", "reject_runtime_artifact", "repair_event_window_evidence"]}, + {"name": "BenchmarkJobReceiptState", "module": "loopx/capabilities/benchmark_toolkit/runtime_observation.py", "values": ["resolved", "missing", "ambiguous"]}, + {"name": "BenchmarkRunnerOwnerState", "module": "loopx/capabilities/benchmark_toolkit/runtime_observation.py", "values": ["alive", "absent_after_grace", "unknown"]}, + {"name": "BenchmarkRuntimeClassification", "module": "loopx/capabilities/benchmark_toolkit/runtime_observation.py", "values": ["not_admitted", "running_qualified", "terminal_pending_reconcile", "runner_invalid_pending_reconcile", "runtime_authority_unresolved", "runner_lost_pending_reconcile", "startup_or_liveness_unresolved"]}, + {"name": "BenchmarkRuntimeTransition", "module": "loopx/capabilities/benchmark_toolkit/runtime_observation.py", "values": ["none", "write_terminal_then_release", "write_runner_invalid_then_release", "repair_runtime_authority", "reobserve_after_startup_grace"]}, + {"name": "PageDensityOrder", "module": "loopx/capabilities/content_ops/layout.py", "values": ["first_page_maximum"]}, + {"name": "PageRole", "module": "loopx/capabilities/content_ops/layout.py", "values": ["cover", "argument", "mechanism", "evidence", "boundary", "closing", "cta"]}, + {"name": "CounterfactualDecision", "module": "loopx/capabilities/explore/counterfactual_runtime.py", "values": ["promoted", "rejected", "observed_only"]}, + {"name": "ItemFailurePolicy", "module": "loopx/capabilities/explore/harness_runtime.py", "values": ["record", "fatal"]}, + {"name": "ReplayChildConcurrency", "module": "loopx/capabilities/explore/replay_runtime.py", "values": ["serial_only", "thread_safe", "process_isolated"]}, + {"name": "ReplayChildFailureStage", "module": "loopx/capabilities/explore/replay_runtime.py", "values": ["intent", "suffix"]}, + {"name": "ReplayFidelity", "module": "loopx/capabilities/explore/replay_runtime.py", "values": ["exact", "semantic_equivalent", "best_effort", "non_replayable"]}, + {"name": "ReplayPointLifecycle", "module": "loopx/capabilities/explore/replay_runtime.py", "values": ["ready", "releasing", "released", "failed"]}, + {"name": "ReplayRiskDisposition", "module": "loopx/capabilities/explore/replay_runtime.py", "values": ["allow", "deny"]}, + {"name": "TraceEventKind", "module": "loopx/capabilities/explore/trace_runtime.py", "values": ["agent_context", "action_intent", "action_outcome", "environment_observation", "validation", "lifecycle"]}, + {"name": "PullRequestReviewPriority", "module": "loopx/capabilities/pr_review_queue/scheduling.py", "values": ["other-developers-first", "owner-first"]}, + {"name": "PullRequestSchedulingLane", "module": "loopx/capabilities/pr_review_queue/scheduling.py", "values": ["authenticated_developer_owned", "community_feedback", "community_aged_backlog", "composite_remaining", "current_head_concluded", "merged", "draft", "closed"]}, + {"name": "ClockSource", "module": "loopx/capabilities/reliability_diagnostics/envelope.py", "values": ["harness_event_time", "observer_wall_clock", "fixture"]}, + {"name": "EnvelopeRejection", "module": "loopx/capabilities/reliability_diagnostics/envelope.py", "values": ["schema_mismatch", "control_field_rejected", "raw_material_field_rejected", "unsupported_field_rejected", "identity_invalid", "sequence_invalid", "clock_invalid", "event_kind_invalid", "summary_invalid", "source_ref_invalid", "public_safety_violation", "observer_internal_failure"]}, + {"name": "ObserverEventKind", "module": "loopx/capabilities/reliability_diagnostics/envelope.py", "values": ["session_started", "turn_started", "turn_ended", "step_started", "step_ended", "user_message", "tool_called", "tool_completed", "agent_status", "agent_pre_step", "agent_error", "session_disposed", "unsupported"]}, + {"name": "DiagnosticSignal", "module": "loopx/capabilities/reliability_diagnostics/projection.py", "values": ["stall_suspected", "repetition_suspected", "unrecovered_error", "event_loss", "integrity_not_valid"]}, + {"name": "DiagnosticStage", "module": "loopx/capabilities/reliability_diagnostics/projection.py", "values": ["unknown", "idle", "running", "tool_running", "errored", "disposed"]}, + {"name": "ReceiptReason", "module": "loopx/capabilities/reliability_diagnostics/receipt.py", "values": ["no_observations", "outbound_endpoint_configured", "observation_entered_worker_context", "observer_failure", "control_field_rejected", "public_safety_violation", "ledger_record_invalid", "observer_stats_missing", "observer_stats_mismatch", "identity_rejected", "observation_entered_scheduler_inputs", "sequence_gap", "sequence_duplicate", "backpressure_drop", "raw_material_rejected", "unsupported_field_rejected", "clock_uncertainty_exceeded"]}, + {"name": "ReceiptStatus", "module": "loopx/capabilities/reliability_diagnostics/receipt.py", "values": ["valid", "degraded", "quarantined", "invalid"]}, + {"name": "EnforcementLevel", "module": "loopx/capabilities/repository_change_window/git_hook.py", "values": ["hook_only", "reference_guard"]}, + {"name": "GitSshService", "module": "loopx/capabilities/repository_change_window/git_hook.py", "values": ["git-receive-pack", "git-upload-pack", "git-upload-archive"]}, + {"name": "ReferenceTransactionPhase", "module": "loopx/capabilities/repository_change_window/git_hook.py", "values": ["preparing", "prepared", "committed", "aborted"]}, + {"name": "AgentLaneFrontierHintDecision", "module": "loopx/control_plane/agents/agent_scope_frontier.py", "values": ["claim_unowned_in_scope", "add_next_advancement", "record_no_followup", "quiet_noop_blocker"]}, + {"name": "AgentScopeFrontierAction", "module": "loopx/control_plane/agents/agent_scope_frontier.py", "values": ["agent_scope_exhausted", "agent_scope_wait", "reassignment_required", "successor_replan_required"]}, + {"name": "AgentRuntimeModel", "module": "loopx/control_plane/agents/runtime_model.py", "values": ["peer_v1"]}, + {"name": "SupervisorDecisionKind", "module": "loopx/control_plane/agents/supervisor.py", "values": ["observe", "inject", "handoff", "discard"]}, + {"name": "SupervisorReceiptOutcome", "module": "loopx/control_plane/agents/supervisor_events.py", "values": ["executed", "rejected", "failed"]}, + {"name": "SupervisorRollbackMode", "module": "loopx/control_plane/agents/supervisor_events.py", "values": ["compensating_action", "not_reversible"]}, + {"name": "DecisionOutcome", "module": "loopx/control_plane/coordination/authority_core.py", "values": ["apply", "no_change", "conflict", "rejected"]}, + {"name": "HandoffMode", "module": "loopx/control_plane/coordination/authority_core.py", "values": ["legacy", "soft_claim", "hard_lease"]}, + {"name": "LeaseAction", "module": "loopx/control_plane/coordination/authority_core.py", "values": ["acquire", "renew", "transfer", "release"]}, + {"name": "LeaseFence", "module": "loopx/control_plane/coordination/authority_core.py", "values": ["not_required", "required", "auto_acquire", "delegated_override"]}, + {"name": "OwnershipGate", "module": "loopx/control_plane/coordination/authority_core.py", "values": ["not_required", "require_holder", "delegated_override"]}, + {"name": "TodoAction", "module": "loopx/control_plane/coordination/authority_core.py", "values": ["claim", "update", "complete", "supersede"]}, + {"name": "ReceiptBoundMonitorPhase", "module": "loopx/control_plane/effect_program.py", "values": ["poll_due", "settlement_pending", "settled"]}, + {"name": "ReceiptBoundReplayPhase", "module": "loopx/control_plane/effect_program.py", "values": ["open", "settlement_pending", "settled"]}, + {"name": "SettlementBindingKind", "module": "loopx/control_plane/effect_program.py", "values": ["todo", "autonomous_replan", "unbound"]}, + {"name": "SettlementFailureKind", "module": "loopx/control_plane/effect_program.py", "values": ["invalid_identity", "receipt_missing", "identity_mismatch", "writeback_missing", "writeback_rejected", "quota_spend_rejected", "terminal_closeout_rejected", "cancelled", "permission_denied", "budget_rejected", "effect_outcome_unknown"]}, + {"name": "SettlementStepKind", "module": "loopx/control_plane/effect_program.py", "values": ["validation", "durable_writeback", "quota_spend", "terminal_closeout"]}, + {"name": "GoalActivationState", "module": "loopx/control_plane/goals/activation.py", "values": ["active", "stopped"]}, + {"name": "GoalActivationAuthorityRouteMode", "module": "loopx/control_plane/goals/activation_service.py", "values": ["source_to_global", "requested_to_global", "orphaned_global_stop_fallback"]}, + {"name": "GoalActivationSourceStatus", "module": "loopx/control_plane/goals/activation_service.py", "values": ["available", "registry_missing", "registry_unreadable", "goal_missing"]}, + {"name": "BotmuxDispatchState", "module": "loopx/control_plane/goals/botmux_runtime.py", "values": ["attempting", "queued", "running", "completed", "failed", "not_found", "unknown", "rejected"]}, + {"name": "OutcomeCheckpointReason", "module": "loopx/control_plane/goals/goal_frontier/outcome_continuity.py", "values": ["final_outcome_claim_missing", "final_outcome_checkpoint_incomplete"]}, + {"name": "GoalFrontierReplanRule", "module": "loopx/control_plane/goals/goal_frontier/replan_rules.py", "values": ["existing_obligation", "blocking_handoff_gate", "ready_deferred_successor", "open_user_todo", "user_action_owns_empty_frontier", "todo_succession_gap", "vision_acceptance_gap", "long_todo_chain", "current_agent_blocker", "monitor_no_change_streak", "not_monitor_only", "no_open_monitor", "advancement_remains", "due_monitor_execution", "future_monitor_wait", "monitor_frontier_exhausted"]}, + {"name": "GoalVisionAdvancementPolicy", "module": "loopx/control_plane/goals/goal_vision_policy.py", "values": ["as_needed", "repeat_until_closed"]}, + {"name": "HostGuardState", "module": "loopx/control_plane/host_adapter_settlement.py", "values": ["selected", "terminal_no_selection", "invalid"]}, + {"name": "QuotaIdentityPrecondition", "module": "loopx/control_plane/quota/error_codes.py", "values": ["public_safe_agent_id", "registered_agent_roster_present", "requested_agent_registered"]}, + {"name": "AutomaticTurnPauseCause", "module": "loopx/control_plane/quota/states.py", "values": ["goal_stopped", "compute_quota_zero"]}, + {"name": "SchedulerDisposition", "module": "loopx/control_plane/scheduler/arbitration.py", "values": ["terminal_stop", "peer_coordination_stop", "agent_monitor_only_wait", "active_work", "agent_scope_wait", "consistency_repair", "human_gate", "monitor_wait", "quiet_wait", "unchanged_wait"]}, + {"name": "ExecutionMode", "module": "loopx/control_plane/scheduler/execution_context.py", "values": ["interactive", "isolated_headless", "hosted_automation"]}, + {"name": "GoalRuntimeContinuationDisposition", "module": "loopx/control_plane/scheduler/execution_context.py", "values": ["continue_now", "defer", "complete"]}, + {"name": "HostSurface", "module": "loopx/control_plane/scheduler/execution_context.py", "values": ["ark_managed_agent", "codex_app", "codex_app_ssh", "codex_cli", "trae_app", "generic_cli", "claude_code", "kunluncode", "local_scheduler"]}, + {"name": "SchedulerOwner", "module": "loopx/control_plane/scheduler/execution_context.py", "values": ["host_automation", "agent_cli_loop", "goal_runtime", "outer_controller", "none"]}, + {"name": "SchedulerRuntimeProfile", "module": "loopx/control_plane/scheduler/execution_context.py", "values": ["ark_managed_agent_goal", "codex_app_heartbeat", "codex_app_ssh_goal", "codex_cli", "trae_app", "claude_code", "kunluncode", "generic_cli", "outer_controller"]}, + {"name": "MonitorWaitPhase", "module": "loopx/control_plane/scheduler/monitor_wait.py", "values": ["expired", "active_window", "near_window", "far_window", "cadence_only"]}, + {"name": "SchedulerCadenceTransition", "module": "loopx/control_plane/scheduler/state_transition_rules.py", "values": ["initial", "identity_reset", "retry_unacknowledged_failure", "hold_active_initial", "advance_after_interval", "hold_until_interval"]}, + {"name": "SchedulerHostTransition", "module": "loopx/control_plane/scheduler/state_transition_rules.py", "values": ["apply_required", "host_match_ack_required", "recorded_failure_suppressed", "settled"]}, + {"name": "TodoCompletionContinuation", "module": "loopx/control_plane/todos/completion_state.py", "values": ["active_goal", "successor", "no_followup"]}, + {"name": "TodoCompletionRecovery", "module": "loopx/control_plane/todos/completion_state.py", "values": ["same_turn_terminal_closeout", "lifecycle_reentry_terminal_closeout"]}, + {"name": "TodoContinuationPolicy", "module": "loopx/control_plane/todos/contract.py", "values": ["independent_handoff", "same_agent_non_delivery"]}, + {"name": "HandoffGateState", "module": "loopx/control_plane/todos/handoff_gate.py", "values": ["blocking", "cleared_without_successor", "cleared_with_successor", "cleared_no_followup", "superseded", "deferred"]}, + {"name": "ProjectionDeliveryStatus", "module": "loopx/control_plane/todos/provider_projection.py", "values": ["pending", "delivered", "current", "not_required"]}, + {"name": "LoopXTurnRoute", "module": "loopx/control_plane/turn_driver/driver.py", "values": ["ready_for_host", "capability_action_required", "repair_required", "replan_required", "user_action_required", "wait", "blocked", "contract_error"]}, + {"name": "LoopDisposition", "module": "loopx/control_plane/turn_driver/loop_controller.py", "values": ["run_now", "capability_action_required", "wait", "stop", "user_action_required", "repair", "replan", "terminal"]}, + {"name": "LoopXTurnResultKind", "module": "loopx/control_plane/turn_driver/transaction.py", "values": ["validated_progress", "validated_completion", "repair_required", "replan_required", "user_action_required", "wait", "iteration_failed", "host_failure", "validation_failed", "writeback_failed", "quota_spend_failed", "terminal_closeout_failed"]}, + {"name": "DeliveryBatchScale", "module": "loopx/control_plane/work_items/delivery_batch_scale.py", "values": ["test_only", "single_surface", "multi_surface", "implementation"]}, + {"name": "DeliveryOutcome", "module": "loopx/control_plane/work_items/delivery_outcome.py", "values": ["surface_only", "outcome_gap", "outcome_progress", "primary_goal_outcome"]}, + {"name": "DeliveryTurnKind", "module": "loopx/control_plane/work_items/delivery_outcome.py", "values": ["contract_only_preparation", "compact_evidence", "blocker_writeback", "product_path_execution", "outcome_gap", "unknown"]}, + {"name": "GovernedTransitionSettlementPhase", "module": "loopx/control_plane/work_items/governed_transition_proposal.py", "values": ["pre_settlement", "post_settlement"]}, + {"name": "ProgressResultClass", "module": "loopx/control_plane/work_items/progress_result.py", "values": ["advanced", "unchanged", "blocked", "exploration_exhausted", "no_followup"]}, + {"name": "GitRevisionRelation", "module": "loopx/doctor_git.py", "values": ["same", "installed_ahead", "installed_behind", "diverged", "unknown"]}, + {"name": "ExternalCapturePolicy", "module": "loopx/extensions/external_connector_runtime.py", "values": ["addressed_only", "configured_source_all", "incremental"]}, + {"name": "ExternalConnectorCapability", "module": "loopx/extensions/external_connector_runtime.py", "values": ["realtime_receive", "history_catch_up", "response_write", "response_readback", "acknowledge"]}, + {"name": "ExternalConnectorLifecycle", "module": "loopx/extensions/external_connector_runtime.py", "values": ["connected", "listening", "stale", "disconnected"]}, + {"name": "ExternalEffectKind", "module": "loopx/extensions/external_connector_runtime.py", "values": ["working_session_turn", "todo_update", "authority_update", "design_update", "no_follow_up"]}, + {"name": "ExternalIngressPolicy", "module": "loopx/extensions/external_connector_runtime.py", "values": ["live_steering", "session_queue", "async_inbox"]}, + {"name": "ExternalResponsePolicy", "module": "loopx/extensions/external_connector_runtime.py", "values": ["no_response", "source_thread", "topic_reply", "configured_mirror"]}, + {"name": "ExternalSourceKind", "module": "loopx/extensions/external_connector_runtime.py", "values": ["group_message", "document_comment"]}, + {"name": "LarkTopicEventDecisionReason", "module": "loopx/extensions/lark/goal_channel_contracts.py", "values": ["matched", "invalid_event", "binding_unavailable", "chat_mismatch", "topic_mismatch", "route_ambiguous", "self_message", "invalid_routing_state", "not_addressed"]}, + {"name": "BotChatMembershipResult", "module": "loopx/extensions/lark/goal_channel_transport.py", "values": ["already_verified", "already_unverified", "added_verified", "add_failed", "added_unverified"]}, + {"name": "CaptureScope", "module": "loopx/extensions/lark/goal_topic_routing.py", "values": ["addressed_only", "configured_chat_all"]}, + {"name": "IngressMode", "module": "loopx/extensions/lark/goal_topic_routing.py", "values": ["live_steering", "session_queue", "direct_session", "async_inbox"]}, + {"name": "ReplyMode", "module": "loopx/extensions/lark/goal_topic_routing.py", "values": ["topic_reply"]}, + {"name": "BotIdentityVerification", "module": "loopx/extensions/lark/inbox_reply.py", "values": ["verified", "retryable_verify_failed", "rejected"]}, + {"name": "ManagerAuthorityMode", "module": "loopx/extensions/lark/manager_routing.py", "values": ["context_only", "turn_authorized"]}, + {"name": "LockAcquisitionPolicy", "module": "loopx/file_lock.py", "values": ["mutation", "monitor", "single_flight"]}, + {"name": "SourceQuality", "module": "loopx/goal_portfolio.py", "values": ["verified", "stale", "conflicting", "unreadable", "partial", "omitted"]}, + {"name": "UpdateAction", "module": "loopx/self_update.py", "values": ["check", "plan", "apply"]}, + {"name": "KeyState", "module": "loopx/session_runtime.py", "values": ["compact", "raw_material", "unclassified"]}, + {"name": "RawMaterialCategory", "module": "loopx/session_runtime.py", "values": ["credential", "transcript", "log", "local_path", "raw_output"]} + ], + "python_closed_sets": [ + {"name": "AGY_ACCEPTED_INPUTS", "module": "loopx/agy_goal_mode/__init__.py", "container": "tuple", "values": ["agy", "antigravity", "antigravity-cli", "antigravity_cli", "antigravity cli", "google antigravity"]}, + {"name": "AGY_NATIVE_WAKE_FACTS", "module": "loopx/agy_goal_mode/__init__.py", "container": "tuple", "values": ["native `schedule` tool: DurationSeconds + Prompt wake message, recurring wakes via MaxIterations, one-shot early-termination conditions", "background tasks (`manage_task`) and async subagents (`invoke_subagent`/`send_message`) wake a live session without an external driver", "`hooks.json` (user or plugin) runs PostToolUse/Stop/PostInvocation automation on tool events"]}, + {"name": "AGY_NATIVE_WAKE_TOOLS", "module": "loopx/agy_goal_mode/__init__.py", "container": "tuple", "values": ["schedule", "manage_task", "invoke_subagent", "send_message", "manage_inbox"]}, + {"name": "AUTHORITY_REGISTRY_CANONICAL_FIELDS", "module": "loopx/authority.py", "container": "tuple", "values": ["default_entry_docs", "topic_authority", "project_materials", "deprecated_sources"]}, + {"name": "AUTHORITY_REGISTRY_SUMMARY_FIELDS", "module": "loopx/authority.py", "container": "tuple", "values": ["declared", "required", "path", "path_exists", "read_status", "default_entry_count", "default_entries_checked", "default_entries_present", "topic_authority_count", "project_material_count", "project_material_repository_count", "project_material_owner_review_required_count", "project_material_stale_count", "project_material_current_authority_count", "deprecated_source_count", "conflict_risk"]}, + {"name": "AUTHORITY_SOURCE_BOUNDARIES", "module": "loopx/authority.py", "container": "set", "values": ["public", "local_private", "private_redacted"]}, + {"name": "CODEX_APP_HEARTBEAT_CHOICES", "module": "loopx/bootstrap.py", "container": "set", "values": ["ask", "yes", "no"]}, + {"name": "GENERIC_ONBOARDING_ADAPTER_KINDS", "module": "loopx/bootstrap.py", "container": "frozenset", "values": ["generic_project_goal_v0", "read_only_project_map_v0"]}, + {"name": "START_GOAL_HOST_SURFACES", "module": "loopx/bootstrap_command_pack.py", "container": "tuple", "values": ["codex-app", "trae_app", "codex-app-ssh", "codex-ide-plugin", "codex-cli-tui", "claude-code", "opencode", "opencode2", "traex-cli", "pi", "gemini-cli", "cursor-agent", "zcode", "agy", "kiro-cli", "deepseek-harness", "deepseek-harness-native", "ark-managed-agent", "shell", "other-agent"]}, + {"name": "ACTIVE_BOUNDARY_AUTHORITY_STATUSES", "module": "loopx/boundary_authority.py", "container": "set", "values": ["active", "approved"]}, + {"name": "BOUNDARY_AUTHORITY_DECISIONS", "module": "loopx/boundary_authority.py", "container": "set", "values": ["approve", "reject", "defer"]}, + {"name": "CONTROL_PLANE_FORBIDDEN_DEPENDENCY_PREFIXES", "module": "loopx/canary/maintainability_ratchet.py", "container": "tuple", "values": ["loopx.capabilities", "loopx.cli", "loopx.cli_commands", "loopx.presentation"]}, + {"name": "BENCHMARK_SENSITIVE_TOKENS", "module": "loopx/canary/premerge.py", "container": "tuple", "values": ["benchmark/", "loopx/capabilities/benchmark_toolkit/", "deprecate/benchmark-legacy/", "loopx/worker_bridge.py", "examples/benchmark"]}, + {"name": "CANARY_TOKENS", "module": "loopx/canary/premerge.py", "container": "tuple", "values": ["loopx/canary/", "loopx/cli_commands/canary.py", "examples/canary/", "tests/test_smoke_suite.py"]}, + {"name": "CHANGE_QUALITY_TOKENS", "module": "loopx/canary/premerge.py", "container": "tuple", "values": ["loopx/capabilities/change_quality/", "skills/loopx-change-quality/", "tests/capabilities/test_change_quality.py", "examples/change-quality-qualification-smoke.py"]}, + {"name": "CONTROL_PLANE_TOKENS", "module": "loopx/canary/premerge.py", "container": "tuple", "values": ["loopx/control_plane/", "loopx/quota.py", "loopx/status.py", "loopx/todos.py", "loopx/state_refresh.py", "loopx/review_packet.py", "loopx/heartbeat_prompt.py", "loopx/cli_commands/quota", "loopx/cli_commands/status", "loopx/cli_commands/todo", "loopx/cli_commands/refresh"]}, + {"name": "DOC_CONTENT_TOKENS", "module": "loopx/canary/premerge.py", "container": "tuple", "values": ["docs/", "README", "AGENTS.md", "docs/development/contributor-tasks.md", "examples/project/", "loopx/capabilities/content_ops/"]}, + {"name": "EXTENSION_RUNTIME_TOKENS", "module": "loopx/canary/premerge.py", "container": "tuple", "values": ["loopx/extensions/", "loopx/cli_commands/extension.py", "examples/capability-extension", "examples/openviking-extension"]}, + {"name": "INSTALL_RELEASE_TOKENS", "module": "loopx/canary/premerge.py", "container": "tuple", "values": ["scripts/install", "scripts/loopx", "loopx/promotion_gate.py", "examples/release/", "examples/public_entry/"]}, + {"name": "LARK_KANBAN_TOKENS", "module": "loopx/canary/premerge.py", "container": "tuple", "values": ["loopx/lark_kanban.py", "loopx/cli_commands/lark_kanban.py", "examples/lark-kanban"]}, + {"name": "PREMERGE_TIERS", "module": "loopx/canary/premerge.py", "container": "set", "values": ["quick", "standard", "deep"]}, + {"name": "PUBLIC_BOUNDARY_TOKENS", "module": "loopx/canary/premerge.py", "container": "tuple", "values": ["docs/", "examples/", "README", "AGENTS.md", ".github/", "package-lock.json"]}, + {"name": "DETERMINISTIC_MINIMUM_LAYERS", "module": "loopx/canary/quality_surface_catalog.py", "container": "tuple", "values": ["unit_contract", "durable_smoke", "catalog_canary"]}, + {"name": "QUALITY_LAYER_IDS", "module": "loopx/canary/quality_surface_catalog.py", "container": "tuple", "values": ["unit_contract", "durable_smoke", "catalog_canary", "host_upgrade", "model_behavior", "release_gate"]}, + {"name": "EXPLICIT_GROUPED_SMOKES", "module": "loopx/canary/runner.py", "container": "set", "values": ["canary-promotion-readiness-smoke.py", "dashboard-demo-readiness-smoke.py"]}, + {"name": "PYTHON_BINARIES", "module": "loopx/canary/runner.py", "container": "set", "values": ["python", "python3"]}, + {"name": "SHELL_TOKENS", "module": "loopx/canary/runner.py", "container": "set", "values": ["&&", "||", ";", "|", ">", "<", ">>", "2>", "2>>"]}, + {"name": "SMOKE_SUITE_CHOICES", "module": "loopx/canary/runner.py", "container": "set", "values": ["default-public", "full-public", "catalog-plan"]}, + {"name": "CADENCE_IDS", "module": "loopx/canary/smoke_health.py", "container": "tuple", "values": ["pr_fast", "catalog_canary", "daily_full_public", "release_gate"]}, + {"name": "NON_BENCHMARK_SMOKE_EXCLUDE_MODULES", "module": "loopx/canary/smoke_profiles.py", "container": "list", "values": ["agentissue-bench", "agents-last-exam", "benchmark", "skillsbench", "swe-marathon", "terminal-bench"]}, + {"name": "BENCHMARK_CANDIDATE_SOURCE_ACTIVE_STATE_MARKERS", "module": "loopx/capabilities/benchmark_toolkit/artifacts.py", "container": "tuple", "values": ["/active_goal_state.md", ".codex/goals/", ".local/goals/"]}, + {"name": "BENCHMARK_CANDIDATE_SOURCE_PRIVATE_RUN_MARKERS", "module": "loopx/capabilities/benchmark_toolkit/artifacts.py", "container": "tuple", "values": [".local/private-benchmark-jobs", "/private-benchmark-jobs/"]}, + {"name": "BENCHMARK_CANDIDATE_SOURCE_PUBLIC_DOC_PREFIXES", "module": "loopx/capabilities/benchmark_toolkit/artifacts.py", "container": "tuple", "values": ["benchmark/", "docs/", "examples/", "goals/", "regression/"]}, + {"name": "BENCHMARK_CANDIDATE_SOURCE_RAW_MARKERS", "module": "loopx/capabilities/benchmark_toolkit/artifacts.py", "container": "tuple", "values": ["/agent/", "/origin_log", "/output/", "/outputs/", "/screenshots/", "/tasks/", "codex.txt", "trajectory.json", "instruction.md", "task.md", "lock.json", "config.json", "result.json"]}, + {"name": "BENCHMARK_PRIVATE_MANIFEST_SUFFIXES", "module": "loopx/capabilities/benchmark_toolkit/artifacts.py", "container": "tuple", "values": [".local.json", ".private.json"]}, + {"name": "BENCHMARK_PUBLIC_ARTIFACT_FILENAMES", "module": "loopx/capabilities/benchmark_toolkit/artifacts.py", "container": "tuple", "values": ["paired_comparison.compact.json", "launch_status.public.json", "launch_summaries.public.json", "loopx-active-user-observation.json"]}, + {"name": "BENCHMARK_PUBLIC_ARTIFACT_SUFFIXES", "module": "loopx/capabilities/benchmark_toolkit/artifacts.py", "container": "tuple", "values": [".compact.json", ".public.json"]}, + {"name": "BENCHMARK_RAW_PRIVATE_PATH_MARKERS", "module": "loopx/capabilities/benchmark_toolkit/artifacts.py", "container": "tuple", "values": ["/agent/trajectory.json", "/sessions/", "/logs/", "/raw/", "trajectory.json", "origin_log", "instruction.md", "task.md", "/screenshots/", "screenshot"]}, + {"name": "BENCHMARK_FOUR_ARM_RUNNER_OBLIGATIONS", "module": "loopx/capabilities/benchmark_toolkit/four_arm_contract.py", "container": "tuple", "values": ["keep_loopx_startup_out_of_band", "match_runtime_task_goal_hash_to_selected_arm", "pin_all_non_factor_inputs", "register_each_run_on_experiment_board"]}, + {"name": "INTEGRITY_EVIDENCE_CATEGORIES", "module": "loopx/capabilities/benchmark_toolkit/integrity.py", "container": "tuple", "values": ["restricted_answer_source_request", "restricted_task_source_request", "restricted_test_source_request", "verifier_source_request", "other_trial_request", "controller_private_state_request", "host_escape_probe", "credential_probe", "credential_value_observed", "loopback_network_request", "external_network_request"]}, + {"name": "NETWORK_ACCESS_MODES", "module": "loopx/capabilities/benchmark_toolkit/integrity.py", "container": "tuple", "values": ["denied", "loopback_only", "permitted_solving"]}, + {"name": "REQUIRED_RUNTIME_ATTESTATIONS", "module": "loopx/capabilities/benchmark_toolkit/integrity.py", "container": "tuple", "values": ["agent_phase_isolated", "evaluator_sources_denied", "other_trials_denied", "controller_state_denied", "host_escape_denied", "shell_network_denied", "provider_credential_shell_excluded", "case_local_control_state", "canonical_control_state_root", "independent_verifier", "verifier_started_after_agent", "official_feedback_blinded"]}, + {"name": "VALIDATION_CATEGORIES", "module": "loopx/capabilities/change_quality/oracles.py", "container": "tuple", "values": ["format", "lint", "typecheck", "test"]}, + {"name": "EVIDENCE_REF_KINDS", "module": "loopx/capabilities/change_quality/result.py", "container": "frozenset", "values": ["path", "instruction", "validator"]}, + {"name": "REUSE_OUTCOMES", "module": "loopx/capabilities/change_quality/result.py", "container": "frozenset", "values": ["reused", "retained", "deferred", "not_applicable"]}, + {"name": "RISK_SEVERITIES", "module": "loopx/capabilities/change_quality/result.py", "container": "frozenset", "values": ["blocker", "warning", "advisory"]}, + {"name": "SIMPLIFICATION_OUTCOMES", "module": "loopx/capabilities/change_quality/result.py", "container": "frozenset", "values": ["fixed", "retained", "deferred", "not_applicable"]}, + {"name": "SIMPLIFY_PRIMARY_LENS_IDS", "module": "loopx/capabilities/change_quality/result.py", "container": "tuple", "values": ["reuse", "quality_simplification"]}, + {"name": "VALIDATION_STATUSES", "module": "loopx/capabilities/change_quality/result.py", "container": "frozenset", "values": ["passed", "failed", "skipped"]}, + {"name": "CHANGE_QUALITY_SHADOW_CASE_KINDS", "module": "loopx/capabilities/change_quality/shadow.py", "container": "tuple", "values": ["real_pr_clean", "real_pr_adversarial", "synthetic_simplification"]}, + {"name": "CHANGE_QUALITY_SHADOW_CONTRACT_VERSIONS", "module": "loopx/capabilities/change_quality/shadow.py", "container": "tuple", "values": ["v0", "v1"]}, + {"name": "CHANGE_QUALITY_SHADOW_FINDING_CLASSES", "module": "loopx/capabilities/change_quality/shadow.py", "container": "tuple", "values": ["correctness", "security_privacy", "api_contract", "validation", "complexity", "efficiency", "error_supervision", "documentation", "release_compatibility"]}, + {"name": "CHANGE_QUALITY_SHADOW_SAFE_FIX_ACTIONS", "module": "loopx/capabilities/change_quality/shadow.py", "container": "tuple", "values": ["none", "bounded", "manual"]}, + {"name": "CHANGE_QUALITY_SHADOW_SIMPLIFICATION_OUTCOMES", "module": "loopx/capabilities/change_quality/shadow.py", "container": "tuple", "values": ["retain", "simplify", "hold"]}, + {"name": "ALLOWED_EFFECT_KINDS", "module": "loopx/capabilities/content_ops/item_lifecycle.py", "container": "set", "values": ["profile_update", "publish", "reply", "repost"]}, + {"name": "ALLOWED_ITEM_KINDS", "module": "loopx/capabilities/content_ops/item_lifecycle.py", "container": "set", "values": ["article", "post", "profile_update", "reply", "repost"]}, + {"name": "ALLOWED_ITEM_STATES", "module": "loopx/capabilities/content_ops/item_lifecycle.py", "container": "set", "values": ["captured", "draft", "review_ready", "approved", "delivery_ready", "published", "readback_verified", "skipped", "superseded"]}, + {"name": "TERMINAL_STATES", "module": "loopx/capabilities/content_ops/item_lifecycle.py", "container": "set", "values": ["readback_verified", "skipped", "superseded"]}, + {"name": "ALLOWED_ANGLE_DECISIONS", "module": "loopx/capabilities/content_ops/surface.py", "container": "set", "values": ["draft", "reject", "hold", "needs_review"]}, + {"name": "ALLOWED_CONNECTOR_ACCESS_MODES", "module": "loopx/capabilities/content_ops/surface.py", "container": "set", "values": ["public_metadata_only", "private_metadata_only", "synthetic_fixture_only"]}, + {"name": "ALLOWED_CONNECTOR_TRIAL_STATES", "module": "loopx/capabilities/content_ops/surface.py", "container": "set", "values": ["candidate", "metadata_packet_collected", "ready_for_metadata_trial", "needs_owner_gate", "blocked"]}, + {"name": "ALLOWED_DRAFT_STATES", "module": "loopx/capabilities/content_ops/surface.py", "container": "set", "values": ["outline", "draft", "rewrite", "blocked", "ready_for_review"]}, + {"name": "ALLOWED_EXPLORATION_EVIDENCE_QUALITIES", "module": "loopx/capabilities/content_ops/surface.py", "container": "set", "values": ["primary_source_metadata", "metadata_only", "not_evidence_until_approved", "compact_result_metadata"]}, + {"name": "ALLOWED_EXPLORATION_READ_STATUSES", "module": "loopx/capabilities/content_ops/surface.py", "container": "set", "values": ["metadata_ready", "not_read", "blocked_until_owner_gate", "compact_result_ready"]}, + {"name": "ALLOWED_FEEDBACK_EFFECTS", "module": "loopx/capabilities/content_ops/surface.py", "container": "set", "values": ["preference_hint", "source_boundary_correction", "rewrite_todo", "publish_decision"]}, + {"name": "ALLOWED_FRESHNESS", "module": "loopx/capabilities/content_ops/surface.py", "container": "set", "values": ["fresh", "stale", "unknown"]}, + {"name": "ALLOWED_PUBLISH_GATE_STATUSES", "module": "loopx/capabilities/content_ops/surface.py", "container": "set", "values": ["blocked_until_user_approval", "approved", "denied", "needs_revision"]}, + {"name": "ALLOWED_SOURCE_STATUSES", "module": "loopx/capabilities/content_ops/surface.py", "container": "set", "values": ["public", "private_needs_review", "synthetic_public_safe", "unpublished", "forbidden_for_public_surface"]}, + {"name": "ALLOWED_USE_POLICIES", "module": "loopx/capabilities/content_ops/surface.py", "container": "set", "values": ["summarize_and_transform", "metadata_only", "do_not_quote", "forbidden"]}, + {"name": "RAW_MATERIAL_KEY_HINTS", "module": "loopx/capabilities/content_ops/surface.py", "container": "tuple", "values": ["body", "chat", "credential", "dm", "local_path", "log", "message", "raw", "secret", "token", "transcript"]}, + {"name": "DECISION_OUTCOME_VERIFICATION_STATUSES", "module": "loopx/capabilities/decision_context/packets.py", "container": "set", "values": ["pending", "verified", "refuted", "inconclusive"]}, + {"name": "DECISION_REVIEW_DISPOSITIONS", "module": "loopx/capabilities/decision_context/packets.py", "container": "set", "values": ["approve", "reject", "defer", "no_change"]}, + {"name": "SHARED_DEPENDENCY_CAPABILITY_PREFIXES", "module": "loopx/capabilities/explore/todo_branch_plan.py", "container": "tuple", "values": ["shared_artifact:", "shared_implementation:"]}, + {"name": "RELEVANT_EDGE_TYPES", "module": "loopx/capabilities/explore/todo_evidence.py", "container": "set", "values": ["supports", "refutes"]}, + {"name": "BRANCH_FILL_POLICIES", "module": "loopx/capabilities/explore/worker_branch_plan.py", "container": "set", "values": ["bundle-by-affinity", "value-first", "confident-prefix"]}, + {"name": "COMMON_TOPIC_TOKENS", "module": "loopx/capabilities/explore/worker_branch_plan.py", "container": "set", "values": ["add", "after", "agent", "against", "and", "audit", "before", "between", "branch", "build", "check", "codex", "continue", "current", "deliver", "existing", "explore", "fix", "from", "goal", "inspect", "into", "latest", "loopx", "new", "next", "one", "p0", "p1", "p2", "recent", "review", "run", "test", "the", "then", "this", "through", "todo", "update", "validate", "when", "while", "with", "without"]}, + {"name": "PROMOTION_DECISIONS", "module": "loopx/capabilities/issue_fix/discovered_issue_promotion.py", "container": "set", "values": ["reuse_existing", "no_equivalent_found"]}, + {"name": "COMMENT_VALUES", "module": "loopx/capabilities/issue_fix/feasibility.py", "container": "set", "values": ["none", "clarification", "diagnosis"]}, + {"name": "REPRODUCTION_STATES", "module": "loopx/capabilities/issue_fix/feasibility.py", "container": "set", "values": ["confirmed", "planned", "missing", "blocked"]}, + {"name": "RESOLUTION_ROUTES", "module": "loopx/capabilities/issue_fix/feasibility.py", "container": "set", "values": ["fix_pr", "comment_only", "triage_only"]}, + {"name": "SCOPE_CLASSES", "module": "loopx/capabilities/issue_fix/feasibility.py", "container": "set", "values": ["bounded", "uncertain", "oversized"]}, + {"name": "ALLOWED_GITHUB_REF_TYPES", "module": "loopx/capabilities/issue_fix/github_public.py", "container": "set", "values": ["issue", "pull", "discussion"]}, + {"name": "GITHUB_COMMENT_BODY_KEYS", "module": "loopx/capabilities/issue_fix/github_public.py", "container": "set", "values": ["body", "body_text", "comment_body", "comment_bodies", "raw", "response_payload", "timeline"]}, + {"name": "MAINTAINER_ASSOCIATIONS", "module": "loopx/capabilities/issue_fix/github_public.py", "container": "set", "values": ["COLLABORATOR", "MEMBER", "OWNER"]}, + {"name": "ALLOWED_ISSUE_FIX_ROUTE_STATUSES", "module": "loopx/capabilities/issue_fix/intake_surface.py", "container": "set", "values": ["candidate", "blocked_until_gate", "selected"]}, + {"name": "ALLOWED_ISSUE_FIX_INTAKE_STATES", "module": "loopx/capabilities/issue_fix/metadata_preview.py", "container": "set", "values": ["open", "closed", "unknown"]}, + {"name": "GITHUB_BODY_OR_COMMENT_KEYS", "module": "loopx/capabilities/issue_fix/metadata_preview.py", "container": "set", "values": ["body", "body_text", "comments", "comment_bodies", "timeline", "events", "raw", "response_payload"]}, + {"name": "BRANCH_REPLAN_MERGE_STATES", "module": "loopx/capabilities/issue_fix/outcome_projection.py", "container": "set", "values": ["BEHIND", "DIRTY"]}, + {"name": "DELIVERY_OUTCOME_STATUSES", "module": "loopx/capabilities/issue_fix/outcome_projection.py", "container": "set", "values": ["in_progress", "completed", "blocked"]}, + {"name": "DELIVERY_VALIDATION_STATUSES", "module": "loopx/capabilities/issue_fix/outcome_projection.py", "container": "set", "values": ["passed", "failed", "partial", "not_run"]}, + {"name": "TERMINAL_PR_STATES", "module": "loopx/capabilities/issue_fix/pr_gate_reconcile.py", "container": "set", "values": ["MERGED", "CLOSED"]}, + {"name": "BRANCH_REPLAN_MERGE_STATES", "module": "loopx/capabilities/issue_fix/pr_lifecycle.py", "container": "set", "values": ["BEHIND", "DIRTY"]}, + {"name": "FAILING_CHECK_STATES", "module": "loopx/capabilities/issue_fix/pr_lifecycle.py", "container": "set", "values": ["ACTION_REQUIRED", "CANCELLED", "ERROR", "FAILURE", "FAILED", "STARTUP_FAILURE", "TIMED_OUT"]}, + {"name": "MAINTAINER_CORRECTION_INPUT_FIELDS", "module": "loopx/capabilities/issue_fix/pr_lifecycle.py", "container": "set", "values": ["schema_version", "correction_kind", "source_kind", "source_ref", "summary", "verification_plan", "pr_update_path", "user_question", "missing_authority_scopes"]}, + {"name": "MAINTAINER_CORRECTION_KINDS", "module": "loopx/capabilities/issue_fix/pr_lifecycle.py", "container": "set", "values": ["actionable_patch", "semantic_ambiguity", "missing_authority", "unchanged"]}, + {"name": "MAINTAINER_CORRECTION_SOURCE_KINDS", "module": "loopx/capabilities/issue_fix/pr_lifecycle.py", "container": "set", "values": ["review", "maintainer_comment"]}, + {"name": "PASSING_CHECK_STATES", "module": "loopx/capabilities/issue_fix/pr_lifecycle.py", "container": "set", "values": ["NEUTRAL", "SKIPPED", "SUCCESS"]}, + {"name": "PENDING_CHECK_STATES", "module": "loopx/capabilities/issue_fix/pr_lifecycle.py", "container": "set", "values": ["EXPECTED", "IN_PROGRESS", "PENDING", "QUEUED", "REQUESTED", "WAITING"]}, + {"name": "TERMINAL_PR_STATES", "module": "loopx/capabilities/issue_fix/pr_lifecycle.py", "container": "set", "values": ["MERGED", "CLOSED"]}, + {"name": "WRITE_SCOPES", "module": "loopx/capabilities/issue_fix/pr_lifecycle.py", "container": "set", "values": ["write", "publish", "external_review_request"]}, + {"name": "CONSULTATION_STATES", "module": "loopx/capabilities/issue_fix/repository_context.py", "container": "set", "values": ["not_applicable", "available", "queried", "unavailable"]}, + {"name": "FRESHNESS_STATES", "module": "loopx/capabilities/issue_fix/repository_context.py", "container": "set", "values": ["current", "stale", "unknown"]}, + {"name": "REQUIRED_FIX_ASPECTS", "module": "loopx/capabilities/issue_fix/repository_context.py", "container": "tuple", "values": ["change_scope", "reproduction", "validation"]}, + {"name": "SOURCE_KINDS", "module": "loopx/capabilities/issue_fix/repository_context.py", "container": "set", "values": ["repository_policy", "architecture_doc", "maintainer_map", "test_surface", "source_code", "prior_fix", "memory_retrieval", "external_expert", "knowledge_bundle"]}, + {"name": "SUPPORT_ASPECTS", "module": "loopx/capabilities/issue_fix/repository_context.py", "container": "set", "values": ["architecture", "ownership", "change_scope", "reproduction", "validation"]}, + {"name": "TRUST_LEVELS", "module": "loopx/capabilities/issue_fix/repository_context.py", "container": "set", "values": ["authoritative", "verified", "advisory"]}, + {"name": "DECISION_INFLUENCE_ASPECTS", "module": "loopx/capabilities/issue_fix/repository_memory.py", "container": "set", "values": ["reproduction", "change_scope", "patch", "validation"]}, + {"name": "PROVIDER_STATUSES", "module": "loopx/capabilities/issue_fix/repository_memory.py", "container": "set", "values": ["completed", "unavailable", "disabled"]}, + {"name": "SUPPORT_ASPECTS", "module": "loopx/capabilities/issue_fix/repository_memory.py", "container": "set", "values": ["architecture", "ownership", "change_scope", "reproduction", "validation"]}, + {"name": "VERIFICATION_STATUSES", "module": "loopx/capabilities/issue_fix/repository_memory.py", "container": "set", "values": ["confirmed", "refuted", "unverified"]}, + {"name": "REVIEWER_COMMANDS", "module": "loopx/capabilities/issue_fix/reviewer_cli.py", "container": "frozenset", "values": ["reviewer-plan", "reviewer-request", "reviewer-notification-drain", "reviewer-feedback-inbox"]}, + {"name": "CODEOWNERS_LOCATIONS", "module": "loopx/capabilities/issue_fix/reviewer_recommendation.py", "container": "tuple", "values": [".github/CODEOWNERS", "CODEOWNERS", "docs/CODEOWNERS"]}, + {"name": "REVIEWER_SOURCE_FIELDS", "module": "loopx/capabilities/issue_fix/reviewer_recommendation.py", "container": "set", "values": ["source_id", "source_kind", "reference", "trust", "freshness", "observed_at", "routes"]}, + {"name": "REVIEWER_SOURCE_FRESHNESS_STATES", "module": "loopx/capabilities/issue_fix/reviewer_recommendation.py", "container": "set", "values": ["current", "stale", "unknown"]}, + {"name": "REVIEWER_SOURCE_INPUT_FIELDS", "module": "loopx/capabilities/issue_fix/reviewer_recommendation.py", "container": "set", "values": ["schema_version", "sources"]}, + {"name": "REVIEWER_SOURCE_MATCH_KINDS", "module": "loopx/capabilities/issue_fix/reviewer_recommendation.py", "container": "set", "values": ["path_prefix", "path_glob", "repository_fallback"]}, + {"name": "REVIEWER_SOURCE_ROUTE_FIELDS", "module": "loopx/capabilities/issue_fix/reviewer_recommendation.py", "container": "set", "values": ["route_id", "match_kind", "pattern", "primary_reviewers", "fallback_reviewers"]}, + {"name": "REVIEWER_SOURCE_TRUST_LEVELS", "module": "loopx/capabilities/issue_fix/reviewer_recommendation.py", "container": "set", "values": ["authoritative", "verified", "advisory"]}, + {"name": "DELIVERY_ERRORS", "module": "loopx/capabilities/manager_context/roundtrip.py", "container": "set", "values": ["provider_delivery_unverified", "provider_locator_unavailable", "provider_verifier_unavailable", "provider_verification_unavailable", "provider_delivery_intent_conflict", "provider_message_missing", "provider_delivery_mismatch", "return_authorization_unavailable", "original_route_unavailable", "initial_delivery_receipt_unavailable", "original_route_or_return_delivery_unavailable", "delivery_state_unreadable"]}, + {"name": "DELIVERY_STATUSES", "module": "loopx/capabilities/manager_context/roundtrip.py", "container": "set", "values": ["queued", "retry_pending", "verification_required", "delivered", "superseded", "explicit_unverified"]}, + {"name": "PHASES", "module": "loopx/capabilities/manager_context/roundtrip.py", "container": "tuple", "values": ["decision", "conclusion"]}, + {"name": "RETURN_RESOLUTION_REASONS", "module": "loopx/capabilities/manager_context/roundtrip.py", "container": "frozenset", "values": ["return_authorization_unavailable", "original_route_unavailable", "initial_delivery_receipt_unavailable"]}, + {"name": "UNSAFE_FIELDS", "module": "loopx/capabilities/material_lifecycle/_validation.py", "container": "set", "values": ["api_key", "content", "credential", "credentials", "private_locator", "provider_payload", "raw_chat", "raw_content", "raw_provider_payload", "token", "tool_output"]}, + {"name": "MATERIAL_LIFECYCLE_STATES", "module": "loopx/capabilities/material_lifecycle/inventory.py", "container": "set", "values": ["active", "archived", "candidate", "carryover", "unread"]}, + {"name": "OBSERVATION_STATES", "module": "loopx/capabilities/pr_review_queue/core.py", "container": "set", "values": ["not_observed", "observed_unchanged", "material_transition"]}, + {"name": "DETAIL_FIELDS", "module": "loopx/capabilities/pr_review_queue/github_source.py", "container": "tuple", "values": ["body", "files", "reviewDecision", "mergeStateStatus", "createdAt", "commits", "reviews", "statusCheckRollup"]}, + {"name": "BEHAVIORAL_POLICY_AREAS", "module": "loopx/capabilities/pr_review_queue/review_contract.py", "container": "set", "values": ["public_entry_or_policy", "agent_instruction_surface"]}, + {"name": "CODE_AREAS", "module": "loopx/capabilities/pr_review_queue/review_contract.py", "container": "set", "values": ["product_runtime", "app_or_ui_surface", "ci_or_release", "build_or_config"]}, + {"name": "REQUIRED_FINAL_SECTIONS", "module": "loopx/capabilities/pr_review_queue/review_contract.py", "container": "list", "values": ["动机", "改动思路", "具体改动", "对主干的风险", "我的整体评价"]}, + {"name": "CAPABILITY_ORIGINS", "module": "loopx/capabilities/registry.py", "container": "frozenset", "values": ["builtin", "extension"]}, + {"name": "CAPABILITY_VISIBILITIES", "module": "loopx/capabilities/registry.py", "container": "frozenset", "values": ["public", "internal"]}, + {"name": "REQUIRED_CAPABILITY_FIELDS", "module": "loopx/capabilities/registry.py", "container": "tuple", "values": ["id", "title", "status", "user_value", "next_real_step"]}, + {"name": "REQUIRED_PUBLIC_CAPABILITY_FIELDS", "module": "loopx/capabilities/registry.py", "container": "tuple", "values": ["real_world_anchor", "entry_command"]}, + {"name": "CLOCK_FIELDS", "module": "loopx/capabilities/reliability_diagnostics/envelope.py", "container": "frozenset", "values": ["source", "uncertainty_ms"]}, + {"name": "CONTROL_FIELD_FAMILIES", "module": "loopx/capabilities/reliability_diagnostics/envelope.py", "container": "frozenset", "values": ["command", "commands", "send", "prompt", "inject", "schedule", "retry", "stop", "resume", "pause", "cancel", "gate", "gatedecision", "toolcall", "toolinvocation", "workerstate", "continuation", "callback", "endpoint", "outboundendpoint"]}, + {"name": "ENVELOPE_FIELDS", "module": "loopx/capabilities/reliability_diagnostics/envelope.py", "container": "frozenset", "values": ["schema_version", "capability_id", "provider_id", "observer_id", "goal_id", "session_id", "agent_id", "sequence", "observed_at", "clock", "event_kind", "summary", "source_refs"]}, + {"name": "RAW_MATERIAL_FIELD_FAMILIES", "module": "loopx/capabilities/reliability_diagnostics/envelope.py", "container": "frozenset", "values": ["transcript", "messages", "content", "text", "arguments", "result", "output", "tooloutput", "stdout", "stderr", "log", "logs", "trace", "path", "localpath", "cwd", "credential", "credentials", "token", "secret"]}, + {"name": "SUMMARY_INTEGER_FIELDS", "module": "loopx/capabilities/reliability_diagnostics/envelope.py", "container": "frozenset", "values": ["turn", "step"]}, + {"name": "SUMMARY_TOKEN_FIELDS", "module": "loopx/capabilities/reliability_diagnostics/envelope.py", "container": "frozenset", "values": ["reason", "status", "tool_name", "error_class", "source_event_type", "message_source_kind"]}, + {"name": "RUN_IDENTITY_FIELDS", "module": "loopx/capabilities/reliability_diagnostics/intake.py", "container": "frozenset", "values": ["worker_id", "model_id", "task_id", "environment_id", "tools_id", "budget_id", "adapter_revision", "observer_revision"]}, + {"name": "STATS_FIELDS", "module": "loopx/capabilities/reliability_diagnostics/intake.py", "container": "frozenset", "values": ["schema_version", "capability_id", "provider_id", "observer_id", "goal_id", "run_identity", "event_sources", "source_fields_consumed", "emitted_at", "observed_event_count", "accepted_event_count", "rejected_event_count", "rejected_by_reason", "buffer_bound", "backpressure_drop_count", "observer_failure_count", "peak_buffered_event_count", "flush_attempt_count", "outbound_endpoints", "observation_entered_worker_context", "observation_entered_scheduler_inputs", "clock_source"]}, + {"name": "BASE_HOOK_NAMES", "module": "loopx/capabilities/repository_change_window/git_hook.py", "container": "tuple", "values": ["pre-commit", "pre-push"]}, + {"name": "APPLICATION_OUTCOMES", "module": "loopx/capabilities/reward_memory/application.py", "container": "set", "values": ["applied", "ignored", "refuted", "failed", "not_available", "available_not_applied"]}, + {"name": "DURABLE_RECALL_CLASSES", "module": "loopx/capabilities/reward_memory/application.py", "container": "set", "values": ["hard_policy", "soft_preference", "procedural_experience"]}, + {"name": "RECALL_MODES", "module": "loopx/capabilities/reward_memory/application.py", "container": "set", "values": ["function_boundary", "bounded_agentic_search"]}, + {"name": "RECALL_QUERY_KINDS", "module": "loopx/capabilities/reward_memory/application.py", "container": "set", "values": ["business_recall", "ingest_verification"]}, + {"name": "BEHAVIOR_STATUSES", "module": "loopx/capabilities/reward_memory/architecture.py", "container": "set", "values": ["bug_confirmed", "by_design", "uncertain"]}, + {"name": "EDGE_CASE_COMPLEXITIES", "module": "loopx/capabilities/reward_memory/architecture.py", "container": "set", "values": ["low", "medium", "high"]}, + {"name": "MEMORY_CLASS_IDS", "module": "loopx/capabilities/reward_memory/architecture.py", "container": "tuple", "values": ["run_bound_reward", "hard_policy", "soft_preference", "procedural_experience", "working_context"]}, + {"name": "CONFIDENCE_LEVELS", "module": "loopx/capabilities/reward_memory/candidate_review.py", "container": "set", "values": ["low", "medium", "high"]}, + {"name": "CONFLICT_STATES", "module": "loopx/capabilities/reward_memory/candidate_review.py", "container": "set", "values": ["clear", "unresolved"]}, + {"name": "ELIGIBLE_POLICY_ACTOR_ROLES", "module": "loopx/capabilities/reward_memory/candidate_review.py", "container": "set", "values": ["verified_repository_core_contributor", "verified_project_owner_or_operator"]}, + {"name": "REVIEW_DECISIONS", "module": "loopx/capabilities/reward_memory/candidate_review.py", "container": "set", "values": ["accept", "edit", "reject", "retire", "no_write"]}, + {"name": "SOURCE_FRESHNESS_STATES", "module": "loopx/capabilities/reward_memory/candidate_review.py", "container": "set", "values": ["current", "stale", "unknown"]}, + {"name": "TARGET_CLASS_IDS", "module": "loopx/capabilities/reward_memory/candidate_review.py", "container": "set", "values": ["hard_policy", "soft_preference", "procedural_experience"]}, + {"name": "APPLICATION_DISPOSITIONS", "module": "loopx/capabilities/reward_memory/dogfood.py", "container": "set", "values": ["applied", "not_applied", "refuted"]}, + {"name": "DOMAIN_FAMILIES", "module": "loopx/capabilities/reward_memory/dogfood.py", "container": "set", "values": ["issue_fix", "loopx"]}, + {"name": "OPERATOR_ACTIONS", "module": "loopx/capabilities/reward_memory/dogfood.py", "container": "set", "values": ["edit", "retire"]}, + {"name": "UTILITY_EVALUATION_STATUSES", "module": "loopx/capabilities/reward_memory/dogfood.py", "container": "set", "values": ["accepted", "rejected", "not_requested"]}, + {"name": "REQUIRED_CASE_IDS", "module": "loopx/capabilities/reward_memory/evaluation.py", "container": "tuple", "values": ["compact_restart_survival", "project_module_scope_isolation", "supersede_revoke_rejection", "stale_source_rejection", "multi_person_authority_conditions", "gate_non_override", "candidate_ranking_influence", "large_edge_case_patch_protection"]}, + {"name": "ATTRIBUTION_LEVELS", "module": "loopx/capabilities/reward_memory/memory_utility.py", "container": "frozenset", "values": ["item", "set", "none"]}, + {"name": "EVIDENCE_BASES", "module": "loopx/capabilities/reward_memory/memory_utility.py", "container": "frozenset", "values": ["owner_correction", "controlled_replay", "deterministic_effect", "evaluator_inference", "insufficient"]}, + {"name": "UTILITY_LABELS", "module": "loopx/capabilities/reward_memory/memory_utility.py", "container": "frozenset", "values": ["helpful", "harmful", "neutral", "unknown"]}, + {"name": "FRESHNESS_MODES", "module": "loopx/capabilities/reward_memory/registry.py", "container": "set", "values": ["source_truth_bound", "revision_bound", "time_bound", "session_archive_bound", "execution_bound"]}, + {"name": "IDENTITY_SCOPE_FIELDS", "module": "loopx/capabilities/reward_memory/registry.py", "container": "tuple", "values": ["user_ref", "peer_ref", "session_ref"]}, + {"name": "LIFECYCLE_STATES", "module": "loopx/capabilities/reward_memory/registry.py", "container": "set", "values": ["active", "superseded", "retired"]}, + {"name": "READ_AUTHORITIES", "module": "loopx/capabilities/reward_memory/registry.py", "container": "set", "values": ["goal_run_scoped", "authority_scoped", "module_scoped", "actor_scoped", "session_scoped"]}, + {"name": "VISIBILITIES", "module": "loopx/capabilities/reward_memory/registry.py", "container": "set", "values": ["private", "workspace", "public_safe"]}, + {"name": "WRITE_AUTHORITIES", "module": "loopx/capabilities/reward_memory/registry.py", "container": "set", "values": ["append_only_overlay", "authorized_policy_source", "provider_managed", "read_only", "ephemeral_runtime"]}, + {"name": "ALLOWED_ACCESS_MODES", "module": "loopx/capabilities/value_connectors/planner.py", "container": "set", "values": ["public_metadata_only", "agent_owned_identity", "private_metadata_gate", "external_write_gated", "fixture_only"]}, + {"name": "ALLOWED_CONNECTOR_KINDS", "module": "loopx/capabilities/value_connectors/planner.py", "container": "set", "values": ["github_channel", "botmail_identity", "community_channel", "x_public_channel", "browser_social_channel", "signup_probe", "lead_monitor", "custom_connector"]}, + {"name": "ALLOWED_GATE_STATUSES", "module": "loopx/capabilities/value_connectors/planner.py", "container": "set", "values": ["blocked_until_explicit_approval", "approved_for_this_exact_call", "denied", "needs_revision"]}, + {"name": "ALLOWED_STAGES", "module": "loopx/capabilities/value_connectors/planner.py", "container": "set", "values": ["observe", "account_setup", "draft", "external_write_request", "monitor", "value_attribution"]}, + {"name": "ALLOWED_VALUE_AXES", "module": "loopx/capabilities/value_connectors/planner.py", "container": "set", "values": ["revenue", "cost_reduction", "demand", "capability"]}, + {"name": "FORBIDDEN_TEXT_SNIPPETS", "module": "loopx/capabilities/value_connectors/planner.py", "container": "tuple", "values": ["restricted-value", "sensitive-value", "bearer "]}, + {"name": "RAW_OR_PRIVATE_KEY_HINTS", "module": "loopx/capabilities/value_connectors/planner.py", "container": "tuple", "values": ["body", "chat", "cookie", "auth material", "dm", "local_path", "log", "message_body", "password", "raw", "secret", "token", "transcript"]}, + {"name": "SOURCE_PROFILE_IDS", "module": "loopx/capabilities/value_connectors/source_map.py", "container": "set", "values": ["all", "github_public_channel", "github_public_reply_monitor", "content_ops_public_handle", "social_browser_x", "agent_reach_ops_source_map", "finance_market_snapshot"]}, + {"name": "CHAT_PROTECTED_ACTION_OPERATIONS", "module": "loopx/chat.py", "container": "frozenset", "values": ["merge", "release", "deploy", "delete", "payment"]}, + {"name": "ACTION_KINDS", "module": "loopx/chat_action_store.py", "container": "set", "values": ["goal.create", "goal.update", "goal.lifecycle", "todo.create", "todo.update", "agent.bind", "heartbeat.bind", "monitor.create", "monitor.update", "gate.resolve", "run.correct", "operation.execute"]}, + {"name": "OPERATION_LIFECYCLE_STATES", "module": "loopx/chat_action_store.py", "container": "set", "values": ["awaiting_confirmation", "claimed", "outcome_observed"]}, + {"name": "PROPOSAL_STATES", "module": "loopx/chat_action_store.py", "container": "set", "values": ["preview_ready", "applying", "gated", "failed", "rejected", "deferred", "cancelled", "stale", "applied"]}, + {"name": "RETRYABLE_PROPOSAL_STATES", "module": "loopx/chat_action_store.py", "container": "set", "values": ["preview_ready", "gated", "failed", "deferred"]}, + {"name": "SUPPORTED_ACTION_KINDS", "module": "loopx/chat_actions.py", "container": "set", "values": ["todo.create", "todo.update", "run.correct", "goal.create", "goal.update", "goal.lifecycle", "agent.bind", "heartbeat.bind", "monitor.create", "monitor.update", "gate.resolve", "operation.execute"]}, + {"name": "CHAT_IMAGE_TYPES", "module": "loopx/chat_attachments.py", "container": "set", "values": ["image/gif", "image/jpeg", "image/png", "image/webp"]}, + {"name": "SUPPORTED_LOCATIONS", "module": "loopx/chat_endpoints.py", "container": "set", "values": ["local", "remote"]}, + {"name": "MANAGER_REASONING_EFFORTS", "module": "loopx/chat_manager.py", "container": "tuple", "values": ["none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra"]}, + {"name": "RESUMABLE_SESSION_STATES", "module": "loopx/chat_store.py", "container": "set", "values": ["ready", "busy", "stale", "resuming"]}, + {"name": "TERMINAL_TURN_STATES", "module": "loopx/chat_store.py", "container": "set", "values": ["completed", "interrupted", "timed_out", "failed"]}, + {"name": "CLAUDE_LEGACY_SCHEDULER_ARGS", "module": "loopx/claude_goal_mode/hooks/goal_policy.py", "container": "list", "values": ["--host-surface", "claude_code", "--scheduler-owner", "agent_cli_loop", "--execution-mode", "interactive"]}, + {"name": "CLAUDE_RUNTIME_PROFILE_ARGS", "module": "loopx/claude_goal_mode/hooks/goal_policy.py", "container": "list", "values": ["--runtime-profile", "claude_code"]}, + {"name": "DESTRUCTIVE", "module": "loopx/claude_goal_mode/hooks/goal_policy.py", "container": "tuple", "values": ["rm -rf", "rm -fr", "mkfs", "dd if=", ":(){", "shutdown", "reboot", "git push --force", "git reset --hard", "> /dev/sd", "format "]}, + {"name": "READONLY_TOOLS", "module": "loopx/claude_goal_mode/hooks/goal_policy.py", "container": "set", "values": ["Read", "Glob", "Grep", "NotebookRead", "TodoWrite", "WebFetch", "WebSearch", "ToolSearch"]}, + {"name": "WRITE_TOOLS", "module": "loopx/claude_goal_mode/hooks/goal_policy.py", "container": "set", "values": ["Edit", "Write", "MultiEdit", "NotebookEdit"]}, + {"name": "REGISTRY_DIRS", "module": "loopx/claude_goal_mode/hooks/goal_state.py", "container": "tuple", "values": [".loopx", ".goal-harness"]}, + {"name": "BENCHMARK_TOOLKIT_COMMANDS", "module": "loopx/cli_commands/benchmark_boundary.py", "container": "set", "values": ["candidate-source-boundary", "classify-artifacts", "integrity-qualification", "four-arm-contract", "runtime-continuity", "runtime-observation", "source-revision-fence", "traex-evidence", "treatment-continuation-receipt", "verify-verifier-reward"]}, + {"name": "BENCHMARK_CONCURRENCY_COMMANDS", "module": "loopx/cli_commands/benchmark_concurrency.py", "container": "set", "values": ["concurrency-status", "concurrency-configure", "concurrency-admit", "concurrency-release", "concurrency-tune"]}, + {"name": "BENCHMARK_EXPERIMENT_BOARD_COMMANDS", "module": "loopx/cli_commands/benchmark_experiment_board.py", "container": "set", "values": ["experiment-board-show", "experiment-board-reconcile", "experiment-board-upsert"]}, + {"name": "BENCHMARK_STUDY_COMMANDS", "module": "loopx/cli_commands/benchmark_study.py", "container": "set", "values": ["study-validate", "upload-envelope", "upload-local", "upload-readback", "study-dashboard", "behavior-report"]}, + {"name": "FEISHU_SINK_EXPLORE_COMMANDS", "module": "loopx/cli_commands/explore_feishu_commands.py", "container": "frozenset", "values": ["feishu-setup", "feishu-visual-configure", "feishu-sync", "feishu-card"]}, + {"name": "PROJECT_LIFECYCLE_COMMANDS", "module": "loopx/cli_commands/project_lifecycle.py", "container": "set", "values": ["refresh-state", "read-only-map", "reward", "operator-gate"]}, + {"name": "QUOTA_SCHEDULER_COMMANDS", "module": "loopx/cli_commands/quota_context.py", "container": "frozenset", "values": ["should-run", "monitor-poll", "scheduler-ack", "scheduler-ack-current", "scheduler-fail-current", "spend-slot"]}, + {"name": "QUOTA_SCHEDULER_FOLLOWUP_COMMANDS", "module": "loopx/cli_commands/quota_context.py", "container": "frozenset", "values": ["scheduler-ack", "scheduler-ack-current", "scheduler-fail-current"]}, + {"name": "QUOTA_SHOULD_RUN_DETAIL_SECTIONS", "module": "loopx/cli_commands/quota_request.py", "container": "tuple", "values": ["scheduler", "agent-todos", "user-todos", "goal-boundary", "vision"]}, + {"name": "REGISTRY_LIFECYCLE_COMMANDS", "module": "loopx/cli_commands/registry_admin_lifecycle.py", "container": "set", "values": ["archive-runtime", "retire-global-goal", "uninstall-project", "sync-global", "migrate-state"]}, + {"name": "REGISTRY_AUTHORITY_COMMANDS", "module": "loopx/cli_commands/registry_authority.py", "container": "set", "values": ["register-authority-source", "import-doc-registry-authority"]}, + {"name": "SUPERVISOR_CONTROL_COMMANDS", "module": "loopx/cli_commands/support_control_supervisor.py", "container": "set", "values": ["supervisor-event", "supervisor-observe", "supervisor-prompt"]}, + {"name": "PLANNED_TURN_HOST_CHOICES", "module": "loopx/cli_commands/turn_registration.py", "container": "list", "values": ["codex-cli", "claude-code", "dsh", "generic-cli"]}, + {"name": "RUN_ONCE_TURN_HOST_CHOICES", "module": "loopx/cli_commands/turn_registration.py", "container": "list", "values": ["codex-cli", "dsh", "generic-cli"]}, + {"name": "WORKER_BRIDGE_COMMANDS", "module": "loopx/cli_commands/worker_bridge.py", "container": "set", "values": ["active-user-codex-simulator-contract", "active-user-contract", "active-user-intervention", "active-user-observe", "active-user-simulator-output", "contract", "attached-session-bind", "attached-session-claim", "attached-session-complete", "attached-session-list"]}, + {"name": "GLOBAL_OPTIONS_WITH_VALUE", "module": "loopx/cli_runtime.py", "container": "frozenset", "values": ["--registry", "--runtime-root", "--format"]}, + {"name": "MULTI_SUBAGENT_FEATURE_CHOICES", "module": "loopx/configure_goal.py", "container": "tuple", "values": ["off", "enabled"]}, + {"name": "WAITING_ON_CHOICES", "module": "loopx/configure_goal.py", "container": "tuple", "values": ["codex", "user_or_controller", "controller", "external_evidence"]}, + {"name": "DEFAULT_SCAN_SUFFIXES", "module": "loopx/contract.py", "container": "set", "values": [".md", ".py", ".toml", ".json", ".yaml", ".yml", ".sh"]}, + {"name": "DEFAULT_SKIP_DIRS", "module": "loopx/contract.py", "container": "set", "values": [".git", ".goal-harness", ".loopx", ".goal-wrapper.local", ".local", ".venv", "__pycache__", ".pytest_cache", ".ruff_cache", "build", "dist", "node_modules", "runtime"]}, + {"name": "LOCAL_PRIVATE_STATE_FILE_NAMES", "module": "loopx/contract.py", "container": "set", "values": ["ACTIVE_GOAL_STATE.md", "ACTIVE_GOAL_STATE.md.lock"]}, + {"name": "LOCAL_PRIVATE_STATE_PARTS", "module": "loopx/contract.py", "container": "set", "values": [".codex", ".goal-harness", ".goal-wrapper.local", ".local", ".loopx"]}, + {"name": "CAPABILITY_OWNER_GATE_HINTS", "module": "loopx/control_plane/agents/capability_gate.py", "container": "set", "values": ["credentials", "production_access"]}, + {"name": "DELIVERY_WORKSPACE_IDENTITY_KINDS", "module": "loopx/control_plane/agents/delivery_workspace.py", "container": "frozenset", "values": ["git_repository", "local_goal"]}, + {"name": "DELIVERY_WORKSPACE_KINDS", "module": "loopx/control_plane/agents/delivery_workspace.py", "container": "frozenset", "values": ["canonical_checkout", "independent_git_worktree", "local_goal_workspace"]}, + {"name": "LEGACY_HIERARCHY_ROLES", "module": "loopx/control_plane/agents/legacy_migration.py", "container": "set", "values": ["primary-agent", "side-agent"]}, + {"name": "AGENT_PROFILE_FIELDS", "module": "loopx/control_plane/agents/profile.py", "container": "set", "values": ["schema_version", "agent_id", "profile_role", "scope_summary", "default_task_classes", "vision_requirement", "preferred_action_kinds", "avoid_action_kinds"]}, + {"name": "AGENT_PROFILE_HIERARCHY_ROLES", "module": "loopx/control_plane/agents/profile.py", "container": "set", "values": ["leader", "manager", "supervisor", "worker"]}, + {"name": "AGENT_PROFILE_VISION_REQUIREMENTS", "module": "loopx/control_plane/agents/profile.py", "container": "set", "values": ["optional", "required"]}, + {"name": "PEER_WRITE_ACTION_KINDS", "module": "loopx/control_plane/agents/workspace_guard.py", "container": "set", "values": ["fix", "implement", "rebuild", "repair", "writeback"]}, + {"name": "LOCAL_AUTHORITY_SOURCES", "module": "loopx/control_plane/coordination/local_authority.py", "container": "tuple", "values": ["file_v0", "sqlite_v0"]}, + {"name": "OBSERVED_LIFECYCLE_FLAGS", "module": "loopx/control_plane/goals/acceptance_observation.py", "container": "frozenset", "values": ["connected", "mapped", "refreshed", "adapter_inspected", "run_recorded", "reward_judged", "operator_approved", "controller_ready"]}, + {"name": "AGENT_TODO_HEADER_MARKERS", "module": "loopx/control_plane/goals/active_state_metadata.py", "container": "tuple", "values": ["agent todo", "codex todo", "project agent todo"]}, + {"name": "TODO_ARCHIVE_HEADER_MARKERS", "module": "loopx/control_plane/goals/active_state_metadata.py", "container": "tuple", "values": ["todo archive", "work archive", "completed archive", "completed work", "完成归档", "待办归档"]}, + {"name": "USER_TODO_HEADER_MARKERS", "module": "loopx/control_plane/goals/active_state_metadata.py", "container": "tuple", "values": ["user todo", "owner review reading queue", "owner reading queue"]}, + {"name": "GOAL_AMENDMENT_CLASSES", "module": "loopx/control_plane/goals/goal_amendment_proposal.py", "container": "tuple", "values": ["lane_route", "shared_work_graph", "shared_acceptance", "protected_authority"]}, + {"name": "GOAL_AMENDMENT_PROPOSAL_ADMISSIONS", "module": "loopx/control_plane/goals/goal_amendment_proposal.py", "container": "tuple", "values": ["admitted", "needs_rebase"]}, + {"name": "GOAL_AMENDMENT_PROPOSAL_ADMISSION_FACTS", "module": "loopx/control_plane/goals/goal_amendment_proposal.py", "container": "tuple", "values": ["base_state_event_basis_sequence_behind_derived_head", "base_source_basis_digest_mismatch", "base_source_basis_unverifiable", "base_revision_basis_superseded"]}, + {"name": "RAW_MATERIAL_KEY_HINTS", "module": "loopx/control_plane/goals/goal_channel_projection.py", "container": "tuple", "values": ["credential", "local_path", "log", "raw", "secret", "stderr", "stdout", "token", "trace", "transcript"]}, + {"name": "VISION_FALLBACK_DECLARATION_FIELDS", "module": "loopx/control_plane/goals/goal_frontier/fallback_disposition.py", "container": "tuple", "values": ["target_todo_id", "successor_todo_id"]}, + {"name": "VISION_TODO_DELTA_SUCCESSOR_ACTIONS", "module": "loopx/control_plane/goals/goal_frontier/fallback_disposition.py", "container": "frozenset", "values": ["create", "reopen"]}, + {"name": "VISION_OUTCOME_CHECKPOINT_CONTINUATION_OUTCOMES", "module": "loopx/control_plane/goals/goal_frontier/outcome_continuity.py", "container": "set", "values": ["continue", "no_change", "replan"]}, + {"name": "VISION_OUTCOME_CHECKPOINT_MATERIAL_OUTCOMES", "module": "loopx/control_plane/goals/goal_frontier/outcome_continuity.py", "container": "set", "values": ["outcome_gap", "outcome_progress", "primary_goal_outcome"]}, + {"name": "VISION_CHECKPOINT_SATISFIED_DECISIONS", "module": "loopx/control_plane/goals/goal_frontier/semantic_history.py", "container": "set", "values": ["patched", "unchanged_with_reason"]}, + {"name": "GOAL_PATH_DELTA_OUTCOMES", "module": "loopx/control_plane/goals/goal_vision.py", "container": "frozenset", "values": ["continue", "replan", "wait", "no_change", "ask_human", "stop"]}, + {"name": "GOAL_VISION_BUDGET_COMPACT_FIELDS", "module": "loopx/control_plane/goals/goal_vision.py", "container": "tuple", "values": ["schema_version", "status", "field_usage", "total_limit", "total_usage"]}, + {"name": "GOAL_VISION_FALLBACK_DECLARATION_FIELDS", "module": "loopx/control_plane/goals/goal_vision.py", "container": "tuple", "values": ["target_todo_id", "successor_todo_id"]}, + {"name": "VISION_FRONTIER_TODO_DELTA_ACTIONS", "module": "loopx/control_plane/goals/goal_vision_read_model.py", "container": "frozenset", "values": ["activate", "create", "reopen", "resume", "retain"]}, + {"name": "GOAL_VISION_CLOSED_STATES", "module": "loopx/control_plane/goals/goal_vision_state.py", "container": "frozenset", "values": ["vision_closed", "retired", "retired_or_superseded", "superseded", "no_followup"]}, + {"name": "HANDOFF_ADVANCEMENT_TASK_CLASSES", "module": "loopx/control_plane/handoff/review_packet_context.py", "container": "set", "values": ["advancement_task", "execution_task", "delivery_task"]}, + {"name": "HANDOFF_MONITOR_MARKERS", "module": "loopx/control_plane/handoff/review_packet_context.py", "container": "tuple", "values": ["monitor", "observation", "readiness", "watch", "poll", "dependency monitor", "观察", "监控", "等待"]}, + {"name": "HANDOFF_MONITOR_TASK_CLASSES", "module": "loopx/control_plane/handoff/review_packet_context.py", "container": "set", "values": ["blocker", "continuous_monitor", "monitor", "user_gate"]}, + {"name": "VISIBLE_GOAL_HOST_CONTROL_CAPABILITIES", "module": "loopx/control_plane/heartbeat/visible_goal.py", "container": "frozenset", "values": ["automation_update", "current_time", "first_turn_receipt", "heartbeat_prequota", "loop", "loopx_turn", "rrule", "scheduler_execution_context", "turn_instance_id"]}, + {"name": "POST_WRITEBACK_COMPOSITION_RETRY_ERROR_CODES", "module": "loopx/control_plane/post_writeback_composition_retry.py", "container": "tuple", "values": ["source_projection_failed", "dispatch_failed"]}, + {"name": "PROJECT_BINDING_FIELDS", "module": "loopx/control_plane/projects/contract.py", "container": "tuple", "values": ["repository_bindings", "external_locator_bindings"]}, + {"name": "PROJECT_KINDS", "module": "loopx/control_plane/projects/registry.py", "container": "tuple", "values": ["work", "personal"]}, + {"name": "HEARTBEAT_HANDOFF_READINESS_COMPACT_FIELDS", "module": "loopx/control_plane/quota/heartbeat_recommendation.py", "container": "tuple", "values": ["ready", "codex_ready", "source", "quota_state", "handoff_status", "post_handoff_run_seen", "post_handoff_small_scale_streak", "post_handoff_outcome_gap_streak", "handoff_interface_budget"]}, + {"name": "HEARTBEAT_POST_HANDOFF_RUN_COMPACT_FIELDS", "module": "loopx/control_plane/quota/heartbeat_recommendation.py", "container": "tuple", "values": ["generated_at", "classification", "progress_scope", "delivery_batch_scale", "delivery_outcome", "delivery_turn_kind", "health_check", "json_exists", "markdown_exists"]}, + {"name": "AUTONOMOUS_CANDIDATE_CONTEXT_FIELDS", "module": "loopx/control_plane/quota/policy_constants.py", "container": "tuple", "values": ["source", "open_count", "task_class", "items"]}, + {"name": "FOCUS_WAIT_LIFECYCLE_MARKERS", "module": "loopx/control_plane/quota/policy_constants.py", "container": "set", "values": ["continuation_boundary", "focus_wait"]}, + {"name": "SELF_REPAIR_SPEND_ACTIONS", "module": "loopx/control_plane/quota/policy_constants.py", "container": "set", "values": ["control_plane_health_repair", "control_plane_projection_repair", "state_projection_gap_repair", "boundary_projection_repair", "todo_decision_scope_projection_repair"]}, + {"name": "SELECTED_TODO_AGENT_FIELDS", "module": "loopx/control_plane/quota/selected_todo_projection.py", "container": "tuple", "values": ["agent_id", "selected_by", "confidence", "claim_required_before_work", "selection_binding", "selection_reason", "delivery_boundary"]}, + {"name": "SELECTED_TODO_COMPACT_FIELDS", "module": "loopx/control_plane/quota/selected_todo_projection.py", "container": "tuple", "values": ["todo_id", "index", "role", "priority", "status", "task_class", "action_kind", "task_domain", "capability_binding_ref", "task_repository", "continuation_policy", "required_write_scopes", "required_capabilities", "claimed_by", "bound_agent", "goal_bound", "blocks_agent", "excluded_agents", "unblocks_todo_id", "target_key", "next_due_at", "expires_at"]}, + {"name": "WORK_LANE_SELECTED_TODO_ITEM_FIELDS", "module": "loopx/control_plane/quota/selected_todo_projection.py", "container": "tuple", "values": ["monitor_due_items", "monitor_schedule_gap_items", "resume_blocked_by_monitor_items"]}, + {"name": "DELIVERY_WORKSPACE_REQUIREMENTS", "module": "loopx/control_plane/quota/settlement_workspace_causality.py", "container": "frozenset", "values": ["required", "not_required", "unknown"]}, + {"name": "RUNTIME_RECOVERY_ACTION_TOKENS", "module": "loopx/control_plane/quota/stall_repair.py", "container": "frozenset", "values": ["configure", "execute", "install", "launch", "materialize", "rebuild", "repair", "restore", "retry", "run", "start"]}, + {"name": "STALL_HEALTH_ITEM_COMPACT_FIELDS", "module": "loopx/control_plane/quota/stall_repair.py", "container": "tuple", "values": ["goal_id", "status", "waiting_on", "severity", "source", "recommended_action"]}, + {"name": "QUOTA_STATE_ORDER", "module": "loopx/control_plane/quota/states.py", "container": "tuple", "values": ["blocked_health", "operator_gate", "focus_wait", "eligible", "waiting", "throttled", "paused"]}, + {"name": "READ_ONLY_ACTION_KINDS", "module": "loopx/control_plane/quota/task_orchestration_admission.py", "container": "frozenset", "values": ["analyze", "compare", "inspect", "review", "test", "validate"]}, + {"name": "USAGE_METRIC_NAMES", "module": "loopx/control_plane/quota/usage_summary.py", "container": "tuple", "values": ["input_tokens", "output_tokens", "cache_tokens", "cost_usd", "duration_ms"]}, + {"name": "QUOTA_VOID_COMMIT_STATUSES", "module": "loopx/control_plane/quota/void_commit.py", "container": "frozenset", "values": ["preview", "not_found", "written", "replayed", "repaired", "conflict"]}, + {"name": "DECISION_FRESHNESS_CLASSIFICATION_PREFIXES", "module": "loopx/control_plane/runtime/decision_freshness.py", "container": "tuple", "values": ["human_reward", "reward_overlay"]}, + {"name": "EVENT_LEDGER_CLASSES", "module": "loopx/control_plane/runtime/event_ledger.py", "container": "tuple", "values": ["accounting", "decision", "evidence", "state", "work"]}, + {"name": "LOOPX_COMMAND_RECORD_ALLOWED_SUBCOMMANDS", "module": "loopx/control_plane/runtime/public_safety.py", "container": "set", "values": ["start-goal", "quota should-run", "todo add", "todo claim", "todo update", "todo complete", "refresh-state", "quota spend-slot", "status", "diagnose"]}, + {"name": "CONTROLLER_READINESS_COMPACT_FIELDS", "module": "loopx/control_plane/runtime/run_compaction.py", "container": "tuple", "values": ["classification", "read_only_observer_ready", "decision_advisor_ready", "write_controller_ready", "missing_gates", "review_judgment", "next_handoff_condition"]}, + {"name": "CONTROLLER_READINESS_GATE_FIELDS", "module": "loopx/control_plane/runtime/run_compaction.py", "container": "tuple", "values": ["id", "ok", "review"]}, + {"name": "HUMAN_REWARD_COMPACT_FIELDS", "module": "loopx/control_plane/runtime/run_compaction.py", "container": "tuple", "values": ["recorded_at", "decision", "reward", "reason_summary", "follow_up", "lesson"]}, + {"name": "OPERATOR_GATE_COMPACT_FIELDS", "module": "loopx/control_plane/runtime/run_compaction.py", "container": "tuple", "values": ["recorded_at", "gate", "decision", "operator_question", "reason_summary", "follow_up", "agent_command"]}, + {"name": "OPERATOR_GATE_RESUME_CONTRACT_COMPACT_FIELDS", "module": "loopx/control_plane/runtime/run_compaction.py", "container": "tuple", "values": ["version", "goal_id", "run_id", "gate_id", "created_state_ref", "created_policy_version", "allowed_decisions", "operator_decision", "latest_state_ref", "freshness_check", "precondition_check", "migration_or_rebase_result", "resulting_action", "validation_after_resume"]}, + {"name": "QUOTA_MONITOR_TARGET_COMPACT_FIELDS", "module": "loopx/control_plane/runtime/run_compaction.py", "container": "tuple", "values": ["schema_version", "target_id", "monitor_mode", "effective_action", "agent_id", "frontier_identity"]}, + {"name": "RUN_BASE_COMPACT_FIELDS", "module": "loopx/control_plane/runtime/run_compaction.py", "container": "tuple", "values": ["generated_at", "run_id", "turn_instance_id", "replan_obligation_id", "goal_id", "parent_run_id", "spawned_by_goal_id", "agent_role", "classification", "agent_id", "agent_lane", "progress_scope", "todo_id", "progress_observation", "delivery_batch_scale", "delivery_outcome", "lifecycle_phase", "lifecycle_flags", "recommended_action", "health_check", "result_status", "approval_state", "active_task_count", "active_priorities", "cache_check", "project_map", "json_exists", "markdown_exists", "usage"]}, + {"name": "VISION_CHECKPOINT_COMPACT_FIELDS", "module": "loopx/control_plane/runtime/run_compaction.py", "container": "tuple", "values": ["schema_version", "agent_id", "required", "satisfied", "decision", "delivery_boundary", "agent_vision_state", "unchanged_reason", "missing_baseline"]}, + {"name": "VISION_CHECKPOINT_CONTINUITY_BASIS_FIELDS", "module": "loopx/control_plane/runtime/run_compaction.py", "container": "tuple", "values": ["kind", "vision_generated_at"]}, + {"name": "VISION_CHECKPOINT_TRIGGER_FIELDS", "module": "loopx/control_plane/runtime/run_compaction.py", "container": "tuple", "values": ["kind", "delivery_outcome", "todo_id"]}, + {"name": "OUTCOME_VISION_CHECKPOINT_TRIGGER_KINDS", "module": "loopx/control_plane/runtime/run_context_retention.py", "container": "set", "values": ["autonomous_replan_recorded", "material_delivery_outcome"]}, + {"name": "OWNER_CORRECTION_RUN_PAYLOAD_FIELDS", "module": "loopx/control_plane/runtime/run_context_retention.py", "container": "tuple", "values": ["generated_at", "agent_id", "classification", "human_reward"]}, + {"name": "SEMANTIC_CONTEXT_RUN_FIELDS", "module": "loopx/control_plane/runtime/run_context_retention.py", "container": "tuple", "values": ["latest_agent_vision_run", "latest_vision_checkpoint_run", "latest_outcome_vision_checkpoint_run", "latest_autonomous_replan_ack_run", "latest_replan_ack_feedback_run", "latest_material_milestone_run", "latest_evidence_delivery_run"]}, + {"name": "REWARD_OVERLAY_IDENTITY_KEYS", "module": "loopx/control_plane/runtime/run_index_duplicates.py", "container": "tuple", "values": ["generated_at", "goal_id", "classification", "json_path", "markdown_path"]}, + {"name": "SESSION_RUNTIME_READONLY_PROJECTION_KEYS", "module": "loopx/control_plane/runtime/session_runtime.py", "container": "tuple", "values": ["session_runtime_readonly_projection", "session_runtime_projection"]}, + {"name": "MATERIAL_PROJECTION_KINDS", "module": "loopx/control_plane/runtime/shared_runtime_material_projection.py", "container": "set", "values": ["dreaming_decision", "operator_gate_decision", "read_only_project_map"]}, + {"name": "CODEX_READY_CLASSIFICATIONS", "module": "loopx/control_plane/runtime/status_classifications.py", "container": "set", "values": ["controller_opted_in_waiting_for_run", "design_next_experiment", "inspect_eval_result", "inspect_result", "needs_more_read_only_evidence", "needs_validation", "public_harness_healthy", "read_only_project_map", "run_validation", "state_refreshed", "operator_gate_approved", "monitor_todo_repeat_dedupe_deployed"]}, + {"name": "DREAMING_ADVISORY_CLASSIFICATIONS", "module": "loopx/control_plane/runtime/status_classifications.py", "container": "set", "values": ["dreaming_exploration_proposal", "dreaming_memory_consolidation", "dreaming_refactor_warning", "dreaming_archive_suggestion"]}, + {"name": "HANDOFF_READY_CLASSIFICATIONS", "module": "loopx/control_plane/runtime/status_classifications.py", "container": "set", "values": ["operator_gate_approved", "controller_opted_in_waiting_for_run"]}, + {"name": "AUTHORITY_CHANGE_CLASSIFICATIONS", "module": "loopx/control_plane/runtime/stride_observation.py", "container": "frozenset", "values": ["bounded_replan_progress", "operator_gate_approved", "operator_gate_rejected", "operator_gate_deferred"]}, + {"name": "GOAL_RUNTIME_DEFER_ACTIONS", "module": "loopx/control_plane/scheduler/execution_context.py", "container": "frozenset", "values": ["backoff_agent_monitor_only", "backoff_until_fresh_evidence", "backoff_until_material_transition", "backoff_until_reassigned", "backoff_until_state_change", "backoff_waiting_for_user", "repair_interaction_contract_projection"]}, + {"name": "DEFAULT_ACK_CAPABILITIES", "module": "loopx/control_plane/scheduler/scheduler_hint.py", "container": "set", "values": ["shell", "filesystem_read", "filesystem_write"]}, + {"name": "SCHEDULER_BASE_IDENTITY_KEYS", "module": "loopx/control_plane/scheduler/scheduler_hint.py", "container": "tuple", "values": ["goal_id", "agent_identity.agent_id", "effective_action", "heartbeat_recommendation.recommended_mode", "interaction_contract.mode"]}, + {"name": "SCHEDULER_FRONTIER_IDENTITY_KEYS", "module": "loopx/control_plane/scheduler/scheduler_hint.py", "container": "tuple", "values": ["selected_todo.todo_id", "selected_todo.action_kind", "selected_todo.target_key", "selected_todo.claimed_by", "selected_todo.capability_binding_ref"]}, + {"name": "BACKLOG_HYGIENE_SECTION_HEADINGS", "module": "loopx/control_plane/status/active_state_projection.py", "container": "tuple", "values": ["Next Action", "Operating Lessons"]}, + {"name": "AUTONOMOUS_RUN_HISTORY_NEUTRAL_CLASSIFICATIONS", "module": "loopx/control_plane/status/autonomous_replan_projection.py", "container": "set", "values": ["quota_slot_spent", "quota_slot_voided", "delivery_completion_spend_accounted_v0"]}, + {"name": "CONNECTED_ADAPTER_STATUSES", "module": "loopx/control_plane/status/goal_attention_projection.py", "container": "set", "values": ["connected", "connected-read-only", "pre-tick-runnable"]}, + {"name": "LEGACY_EXTERNAL_EVIDENCE_CLASSIFICATION_PREFIXES", "module": "loopx/control_plane/status/goal_attention_projection.py", "container": "tuple", "values": ["await_", "external_evidence_observation_"]}, + {"name": "REGISTRY_WAITING_ON_OVERRIDES", "module": "loopx/control_plane/status/goal_attention_projection.py", "container": "set", "values": ["user_or_controller", "controller", "codex", "external_evidence"]}, + {"name": "CONNECTED_ADAPTER_STATUSES", "module": "loopx/control_plane/status/lifecycle_projection.py", "container": "set", "values": ["connected", "connected-read-only", "pre-tick-runnable"]}, + {"name": "LIFECYCLE_PRIORITY", "module": "loopx/control_plane/status/lifecycle_projection.py", "container": "tuple", "values": ["controller_ready", "reward_judged", "operator_approved", "controller_gated", "operator_gated", "adapter_inspected", "mapped", "refreshed", "connected", "registered", "planned", "run_recorded"]}, + {"name": "SOURCE_REGISTRY_SHADOW_FINDINGS", "module": "loopx/control_plane/status/registry_health_projection.py", "container": "set", "values": ["source_registry_missing", "stale_source_registry"]}, + {"name": "PLANNING_HORIZON_STRATEGIC_CONTEXT_ATTENTION_IDS", "module": "loopx/control_plane/testing/action_portfolio_scenarios.py", "container": "tuple", "values": ["todo_per_model_tests", "todo_runtime_admission", "todo_allowlist_policy"]}, + {"name": "PLANNING_HORIZON_STRATEGIC_CONTEXT_TODO_IDS", "module": "loopx/control_plane/testing/action_portfolio_scenarios.py", "container": "tuple", "values": ["todo_regression_gate", "todo_per_model_tests", "todo_runtime_admission", "todo_allowlist_policy", "todo_facts_source"]}, + {"name": "DEFAULT_REGISTERED_AGENTS", "module": "loopx/control_plane/testing/authority_e2e_fixtures.py", "container": "tuple", "values": ["agent-a", "agent-b"]}, + {"name": "RUNTIME_ROOT_BINDINGS", "module": "loopx/control_plane/testing/authority_e2e_fixtures.py", "container": "tuple", "values": ["registry", "cli_override", "cli_override_divergent"]}, + {"name": "FILE_MATRIX_ROWS", "module": "loopx/control_plane/testing/authority_e2e_ladder.py", "container": "tuple", "values": ["same_todo_one_winner", "independent_todo_applies", "replay_returns_original_receipt", "identity_mismatch_rejected", "stale_revision_conflicts", "lost_response_recovers_receipt", "receipts_retained", "authority_revision_advanced_twice", "renew_extends_the_active_lease", "expired_lease_reclaimed_with_new_epoch", "superseded_executor_cannot_write_back", "complete_creates_claimable_successor_atomically"]}, + {"name": "GATES", "module": "loopx/control_plane/testing/authority_e2e_ladder.py", "container": "tuple", "values": ["deterministic", "env:postgresql", "env:nokv_authority", "env:nokv_legacy"]}, + {"name": "NOKV_SECRET_VARIABLES", "module": "loopx/control_plane/testing/authority_e2e_ladder.py", "container": "tuple", "values": ["NOKV_OBJECT_KEY", "NOKV_OBJECT_SECRET"]}, + {"name": "NOKV_STACK_VARIABLES", "module": "loopx/control_plane/testing/authority_e2e_ladder.py", "container": "tuple", "values": ["NOKV_ETCD", "NOKV_ETCD_PREFIX", "NOKV_ROOT_ID", "NOKV_BUCKET", "NOKV_OBJECT_ENDPOINT", "NOKV_OBJECT_ROOT", "NOKV_OBJECT_KEY", "NOKV_OBJECT_SECRET"]}, + {"name": "PRODUCT_PATHS", "module": "loopx/control_plane/testing/authority_e2e_ladder.py", "container": "tuple", "values": ["real_cli", "store_direct"]}, + {"name": "ROW_STATUSES", "module": "loopx/control_plane/testing/authority_e2e_ladder.py", "container": "tuple", "values": ["pass", "fail", "unverified"]}, + {"name": "STAGES", "module": "loopx/control_plane/testing/authority_e2e_ladder.py", "container": "tuple", "values": ["0", "1", "2a", "2b", "2c1", "2c2"]}, + {"name": "COMMITTED_OBSERVATION_OUTCOMES", "module": "loopx/control_plane/testing/authority_e2e_row_support.py", "container": "frozenset", "values": ["captured", "replayed", "ambiguous_reconciled"]}, + {"name": "DEFAULT_OFF_PARITY_FIELDS", "module": "loopx/control_plane/testing/authority_e2e_row_support.py", "container": "tuple", "values": ["ok", "added", "already_exists", "metadata_updated", "status_changed", "role", "status", "task_class", "action_kind", "continuation_policy"]}, + {"name": "ARCHIVE_PARITY_REQUIRED_WRITE_CLASSES", "module": "loopx/control_plane/testing/authority_e2e_rows_stage2c2.py", "container": "tuple", "values": ["todo_add", "todo_complete", "todo_archive_completed", "task_lease_acquire", "task_lease_fence_close"]}, + {"name": "DRAIN_CRASH_WINDOWS", "module": "loopx/control_plane/testing/authority_e2e_rows_stage2c2.py", "container": "tuple", "values": ["before_commit", "after_commit", "after_cursor", "between_unlinks"]}, + {"name": "PARITY_REQUIRED_WRITE_CLASSES", "module": "loopx/control_plane/testing/authority_e2e_rows_stage2c2.py", "container": "tuple", "values": ["todo_add", "todo_update", "todo_complete", "todo_supersede", "todo_capture_followups", "task_lease_acquire", "task_lease_renew", "task_lease_transfer", "task_lease_fence_close"]}, + {"name": "MODEL_BEHAVIOR_SEMANTIC_CONTRACT_FIELDS", "module": "loopx/control_plane/testing/model_behavior_qualification.py", "container": "tuple", "values": ["concrete_user_question", "required_reads", "gate_or_stop", "peer_route", "write_scope", "spend_rule", "scheduler_action", "vision_continuation", "planning_horizon", "actionable_warnings"]}, + {"name": "ONBOARDING_MODEL_BEHAVIOR_PHASES", "module": "loopx/control_plane/testing/onboarding_model_behavior_qualification.py", "container": "tuple", "values": ["entry", "postcondition"]}, + {"name": "ONBOARDING_REQUIRED_CONNECT_COMMAND_IDS", "module": "loopx/control_plane/testing/onboarding_model_behavior_qualification.py", "container": "tuple", "values": ["goal_start_connect_if_needed", "goal_start_refresh_state", "goal_start_host_loop_activation", "goal_start_quota_should_run"]}, + {"name": "REQUIRED_QUALIFICATION_IDS", "module": "loopx/control_plane/testing/release_commit_qualification.py", "container": "tuple", "values": ["pytest", "ruff", "mypy", "risk_canary", "full_public", "install_upgrade_host", "public_boundary", "doubao_actual_default"]}, + {"name": "TODO_ACTION_KIND_ADVANCEMENT_VALUES", "module": "loopx/control_plane/todos/contract.py", "container": "set", "values": ["advance", "analyze", "benchmark_run", "codex_run", "compact_blocker_writeback", "compare", "execute", "fix", "implement", "rebuild", "rebuild_score", "repair", "run", "run_eval", "test", "validate", "writeback"]}, + {"name": "TODO_ACTION_KIND_MONITOR_VALUES", "module": "loopx/control_plane/todos/contract.py", "container": "set", "values": ["external_evidence", "monitor", "observe", "poll", "watch"]}, + {"name": "TODO_DECISION_OUTCOME_VALUES", "module": "loopx/control_plane/todos/contract.py", "container": "set", "values": ["approve", "reject", "cancel"]}, + {"name": "TODO_DECISION_SCOPE_GRANULARITY_VALUES", "module": "loopx/control_plane/todos/contract.py", "container": "set", "values": ["action", "lane", "goal", "project", "global"]}, + {"name": "TODO_DECISION_SCOPE_KIND_VALUES", "module": "loopx/control_plane/todos/contract.py", "container": "set", "values": ["private_read", "write_scope", "resource", "production", "public_claim", "direction", "other"]}, + {"name": "TODO_LEGACY_TERMINAL_STATUS_VALUES", "module": "loopx/control_plane/todos/contract.py", "container": "set", "values": ["completed", "closed", "archived"]}, + {"name": "TODO_MONITOR_METADATA_FIELDS", "module": "loopx/control_plane/todos/contract.py", "container": "tuple", "values": ["target_key", "monitor_effect_id", "cadence", "next_due_at", "expires_at", "last_checked_at", "result_hash", "consecutive_no_change", "material_change", "material_change_generation", "max_no_change_before_replan", "watch_only"]}, + {"name": "TODO_REMOVED_REVIEW_CONTINUATION_POLICY_VALUES", "module": "loopx/control_plane/todos/contract.py", "container": "set", "values": ["primary_review", "review_handoff"]}, + {"name": "TODO_GATE_BLOCKING_STATES", "module": "loopx/control_plane/todos/decision_scope.py", "container": "frozenset", "values": ["gate_targets_todo", "gate_covers_action", "projection_repair_required"]}, + {"name": "TODO_FRONTIER_DEADLINE_LANES", "module": "loopx/control_plane/todos/frontier_deadline.py", "container": "tuple", "values": ["current_agent_claimed_monitor_items", "monitor_open_items", "gate_open_items", "deferred_resume_candidates", "current_agent_deferred_resume_candidates", "resume_blocked_items", "current_agent_monitor_blocked_resume_candidates", "current_agent_handoff_gates"]}, + {"name": "FRONTIER_REVISION_FIELDS", "module": "loopx/control_plane/todos/frontier_revision.py", "container": "tuple", "values": ["todo_id", "status", "done", "title", "text", "task_class", "claimed_by", "bound_agent", "blocks_agent", "excluded_agents", "priority", "action_kind", "task_domain", "task_repository", "capability_binding_ref", "required_capabilities", "target_capabilities", "target_key", "continuation_policy", "removed_continuation_policy", "decision_scope", "required_decision_scopes", "decision_outcome", "replan_obligation_id", "unblocks_todo_id", "depends_on_todo_id", "depends_on_todo_ids", "resume_when", "no_followup", "successor_todo_ids", "completion_continuation"]}, + {"name": "THIN_TODO_LIST_ITEM_FIELDS", "module": "loopx/control_plane/todos/list_projection.py", "container": "tuple", "values": ["todo_id", "role", "status", "priority", "text", "task_class", "action_kind", "claimed_by", "bound_agent", "goal_bound", "blocks_agent", "global_gate", "unblocks_todo_id", "decision_scope", "required_decision_scopes", "resume_when", "resume_ready", "target_key", "cadence", "next_due_at", "expires_at", "watch_only"]}, + {"name": "TODO_LIFECYCLE_AUTHORITY_ACTIONS", "module": "loopx/control_plane/todos/mutation_authority.py", "container": "frozenset", "values": ["complete", "reassign", "supersede", "update"]}, + {"name": "AGENT_LANE_STATUS_TODO_ITEM_FIELDS", "module": "loopx/control_plane/todos/quota_summary.py", "container": "tuple", "values": ["schema_version", "index", "todo_id", "text", "title", "status", "priority", "task_class", "action_kind", "task_domain", "claimed_by", "bound_agent", "blocks_agent", "global_gate", "unblocks_todo_id", "required_capabilities", "required_write_scopes", "missing_capabilities", "resume_ready", "next_due_at"]}, + {"name": "QUOTA_PAYLOAD_ITEM_FIELDS", "module": "loopx/control_plane/todos/quota_summary.py", "container": "tuple", "values": ["schema_version", "index", "text", "title", "todo_id", "status", "priority", "task_class", "action_kind", "task_domain", "decision_scope", "required_decision_scopes", "task_repository", "continuation_policy", "required_capabilities", "required_write_scopes", "missing_capabilities", "claimed_by", "bound_agent", "goal_bound", "blocks_agent", "excluded_agents", "global_gate", "unblocks_todo_id", "resume_when", "resume_monitor_generation", "resume_condition", "resume_ready", "blocking_monitor_todo_id", "no_followup", "successor_todo_ids", "completion_continuation", "completion_recovery", "replan_obligation_id", "target_key", "cadence", "next_due_at", "expires_at", "watch_only", "last_checked_at", "result_hash", "consecutive_no_change", "material_change", "material_change_generation", "max_no_change_before_replan", "route_continuation_replan_required", "route_continuation_reason", "route_id", "route_key", "completed_at", "updated_at", "gate_state", "reason"]}, + {"name": "TODO_PLANNING_SOURCE_KEYS", "module": "loopx/control_plane/todos/summary_item.py", "container": "tuple", "values": ["items", "deferred_items", "blocker_items", "monitor_open_items"]}, + {"name": "TODO_SUMMARY_COMPACT_FIELDS", "module": "loopx/control_plane/todos/summary_item.py", "container": "tuple", "values": ["schema_version", "todo_id", "role", "status", "priority", "title", "archive_state", "source_section", "task_class", "action_kind", "task_domain", "capability_binding_ref", "task_repository", "continuation_policy", "removed_continuation_policy", "required_write_scopes", "required_capabilities", "target_capabilities", "decision_scope", "required_decision_scopes", "decision_outcome", "decision_scope_outcomes", "claimed_by", "bound_agent", "goal_bound", "blocks_agent", "excluded_agents", "global_gate", "unblocks_todo_id", "resume_when", "resume_monitor_generation", "resume_condition", "resume_ready", "no_followup", "successor_todo_ids", "completion_continuation", "completion_recovery", "replan_obligation_id", "target_key", "cadence", "next_due_at", "expires_at", "watch_only", "last_checked_at", "result_hash", "consecutive_no_change", "material_change", "material_change_generation", "max_no_change_before_replan", "route_continuation_replan_required", "route_continuation_reason", "route_id", "route_key", "completed_at", "updated_at", "completion_turn_key", "superseded_by", "handoff_note"]}, + {"name": "TODO_SUMMARY_SOURCE_KEYS", "module": "loopx/control_plane/todos/summary_item.py", "container": "tuple", "values": ["active_next_action_items", "active_next_action_executable_items", "first_open_items", "backlog_items", "unclaimed_priority_open_items", "claimed_open_items", "claimed_advancement_open_items", "claimed_monitor_open_items", "monitor_open_items", "current_agent_claimed_open_items", "current_agent_claimed_advancement_items", "current_agent_claimed_monitor_items", "blocker_items", "resume_blocked_items", "monitor_blocked_resume_candidates", "current_agent_monitor_blocked_resume_candidates", "unclaimed_monitor_blocked_resume_candidates", "items"]}, + {"name": "TASK_ORCHESTRATION_CANDIDATE_FIELDS", "module": "loopx/control_plane/todos/todo_summary.py", "container": "tuple", "values": ["todo_id", "status", "done", "task_class", "action_kind", "task_domain", "task_repository", "required_write_scopes", "required_capabilities", "claimed_by", "excluded_agents", "resume_when", "resume_ready", "continuation_policy", "target_key", "completion_validation_required", "title", "text"]}, + {"name": "TASK_ORCHESTRATION_USER_BLOCKER_FIELDS", "module": "loopx/control_plane/todos/todo_summary.py", "container": "tuple", "values": ["todo_id", "status", "done", "task_class", "unblocks_todo_id"]}, + {"name": "USER_GATE_ACTION_KIND_HINTS", "module": "loopx/control_plane/todos/user_gate.py", "container": "tuple", "values": ["approval", "approve", "boundary", "gate", "blocker", "credential", "private", "production", "leaderboard", "submission", "public_claim"]}, + {"name": "CODEX_CLI_RESULT_KINDS", "module": "loopx/control_plane/turn_driver/codex_cli.py", "container": "tuple", "values": ["validated_progress", "repair_required", "replan_required", "user_action_required", "wait", "iteration_failed"]}, + {"name": "CODEX_CLI_SANDBOXES", "module": "loopx/control_plane/turn_driver/codex_cli.py", "container": "tuple", "values": ["read-only", "workspace-write"]}, + {"name": "SESSION_INVALIDATING_FAILURE_CATEGORIES", "module": "loopx/control_plane/turn_driver/codex_cli.py", "container": "frozenset", "values": ["model_requires_newer_codex", "output_schema_rejected", "session_missing"]}, + {"name": "DELIVERY_CONTINUITY_DECISIONS", "module": "loopx/control_plane/turn_driver/delivery_continuity.py", "container": "set", "values": ["resume_in_flight", "release_for_reselection", "preempt"]}, + {"name": "DELIVERY_CONTINUITY_PREEMPTIONS", "module": "loopx/control_plane/turn_driver/delivery_continuity.py", "container": "set", "values": ["heartbeat_receipt", "blocking_work_lane", "autonomous_replan", "control_repair", "delivery_not_allowed"]}, + {"name": "DELIVERY_ROUTING_SELECTIONS", "module": "loopx/control_plane/turn_driver/delivery_continuity.py", "container": "set", "values": ["continuity", "fallback", "none"]}, + {"name": "REPAIR_ACTIONS", "module": "loopx/control_plane/turn_driver/driver.py", "container": "set", "values": ["capability_repair", "projection_repair", "self_repair", "state_projection_repair", "workspace_repair"]}, + {"name": "REPLAN_ACTIONS", "module": "loopx/control_plane/turn_driver/driver.py", "container": "set", "values": ["autonomous_replan", "autonomous_replan_required", "successor_replan_required"]}, + {"name": "SUPPORTED_EXECUTION_MODES", "module": "loopx/control_plane/turn_driver/driver.py", "container": "set", "values": ["interactive-visible", "isolated-headless"]}, + {"name": "SUPPORTED_HOSTS", "module": "loopx/control_plane/turn_driver/driver.py", "container": "set", "values": ["codex-cli", "claude-code", "dsh", "generic-cli"]}, + {"name": "SUPPORTED_ITERATION_CONTEXT_POLICIES", "module": "loopx/control_plane/turn_driver/driver.py", "container": "set", "values": ["fresh", "resume_if_available"]}, + {"name": "HOST_PATH_DELTA_MODES", "module": "loopx/control_plane/turn_driver/executor.py", "container": "set", "values": ["", "unchanged", "material_replan"]}, + {"name": "HOST_RESULT_FIELDS", "module": "loopx/control_plane/turn_driver/executor.py", "container": "set", "values": ["schema_version", "turn_key", "result_kind", "completed_phases", "classification", "recommended_action", "next_action", "delivery_batch_scale", "delivery_outcome", "vision_unchanged_reason", "path_delta_mode", "agent_vision_json", "summary", "reward_memory_reflection_json"]}, + {"name": "HOST_FAILURE_KINDS", "module": "loopx/control_plane/turn_driver/host_failure.py", "container": "frozenset", "values": ["auth_failed", "contract_rejected", "executor_timeout", "provider_capacity", "provider_overloaded", "quota_exhausted", "rate_limited", "session_missing", "transport_lost", "unknown"]}, + {"name": "CHILD_CONTEXT_MODES", "module": "loopx/control_plane/turn_driver/subagent_execution_topology.py", "container": "frozenset", "values": ["fresh", "forked_snapshot", "resume"]}, + {"name": "CHILD_FALLBACK_ACTIONS", "module": "loopx/control_plane/turn_driver/subagent_execution_topology.py", "container": "tuple", "values": ["retry_fresh", "replace_child", "serial_takeover", "ignore_optional_result"]}, + {"name": "KNOWN_EFFECT_CLASSES", "module": "loopx/control_plane/turn_driver/subagent_execution_topology.py", "container": "frozenset", "values": ["local_read", "network_read", "held_workspace_write", "external_write", "production_action", "credential_use", "monitor"]}, + {"name": "RECEIPT_STATUSES", "module": "loopx/control_plane/turn_driver/subagent_execution_topology.py", "container": "frozenset", "values": ["running", "completed", "failed", "cancelled", "rejected"]}, + {"name": "ISSUE_META_SURFACE_SECTION_HEADINGS", "module": "loopx/control_plane/work_items/issue_meta_surface.py", "container": "tuple", "values": ["Issue Meta Surface", "Issue/PR Meta Surface"]}, + {"name": "CAPTURE_SCOPES", "module": "loopx/control_plane/work_items/operator_inbox.py", "container": "set", "values": ["addressed_only", "configured_chat_all"]}, + {"name": "FRESH_VISION_PATH_DISPOSITIONS", "module": "loopx/control_plane/work_items/progress_observation.py", "container": "frozenset", "values": ["continue", "no_change", "replan"]}, + {"name": "REPLAN_REQUIRED_OUTCOMES", "module": "loopx/control_plane/work_items/progress_observation.py", "container": "tuple", "values": ["new_surface", "new_hypothesis", "new_probe_family", "new_runnable_successor", "coverage_backed_exploration_exhausted", "new_concrete_blocker", "coverage_backed_no_followup"]}, + {"name": "SEMANTIC_DIMENSIONS", "module": "loopx/control_plane/work_items/progress_observation.py", "container": "tuple", "values": ["surface_id", "hypothesis_id", "probe_kind"]}, + {"name": "VISION_REPLAN_REQUIRED_OUTCOMES", "module": "loopx/control_plane/work_items/progress_observation.py", "container": "tuple", "values": ["fresh_vision_path_outcome", "new_runnable_successor", "new_concrete_blocker", "coverage_backed_exploration_exhausted", "coverage_backed_no_followup"]}, + {"name": "VISION_REPLAN_TRIGGER_KINDS", "module": "loopx/control_plane/work_items/progress_observation.py", "container": "frozenset", "values": ["vision_acceptance_gap", "vision_checkpoint_missing", "vision_outcome_checkpoint_required", "vision_successor_required", "required_agent_vision_missing"]}, + {"name": "PROJECT_ASSET_HANDOFF_STATE_TRACE_CHECK_KEYS", "module": "loopx/control_plane/work_items/project_asset.py", "container": "tuple", "values": ["project_asset_backed", "same_source_should_run", "handoff_has_next_action", "handoff_has_stop_condition", "handoff_sanitized_surface"]}, + {"name": "PROJECT_ASSET_TODO_DISPLAY_FIELDS", "module": "loopx/control_plane/work_items/project_asset.py", "container": "tuple", "values": ["index", "done", "schema_version", "todo_id", "role", "status", "priority", "archive_state", "source_section", "task_class", "action_kind", "task_domain", "task_repository", "required_write_scopes", "required_capabilities", "target_capabilities", "decision_scope", "required_decision_scopes", "claimed_by", "bound_agent", "goal_bound", "blocks_agent", "excluded_agents", "global_gate", "unblocks_todo_id", "resume_when", "resume_monitor_generation", "resume_condition", "resume_ready", "blocking_monitor_todo_id", "no_followup", "successor_todo_ids", "target_key", "cadence", "next_due_at", "expires_at", "last_checked_at", "result_hash", "consecutive_no_change", "material_change", "material_change_generation", "max_no_change_before_replan", "route_continuation_replan_required", "route_continuation_reason", "route_id", "route_key", "completed_at", "updated_at", "superseded_by"]}, + {"name": "ACCOUNTABLE_REPLAN_DELTA_KINDS", "module": "loopx/control_plane/work_items/repair_delta.py", "container": "frozenset", "values": ["blocker", "capability_gate", "goal_boundary_projection", "goal_vision_patch", "no_followup", "runnable_todo_set", "successor_or_supersede", "exploration_exhausted"]}, + {"name": "FRONTIER_REPLAN_ACK_DELTA_KINDS", "module": "loopx/control_plane/work_items/repair_delta.py", "container": "frozenset", "values": ["active_state_next_action", "blocker", "goal_vision_patch", "no_followup", "runnable_todo_set", "successor_or_supersede", "watch_lane_continuation", "exploration_exhausted"]}, + {"name": "REPAIR_DELTA_KIND_CHOICES", "module": "loopx/control_plane/work_items/repair_delta.py", "container": "tuple", "values": ["effective_action", "interaction_contract", "runnable_todo_set", "user_gate", "blocker", "successor_or_supersede", "capability_gate", "monitor_target", "active_state_next_action", "goal_vision_patch", "goal_boundary_projection", "no_followup", "watch_lane_continuation", "exploration_exhausted"]}, + {"name": "TASK_GRAPH_AUDIT_MARKERS", "module": "loopx/control_plane/work_items/task_graph.py", "container": "tuple", "values": ["audit", "audited"]}, + {"name": "TASK_GRAPH_CONTINUATION_MARKERS", "module": "loopx/control_plane/work_items/task_graph.py", "container": "tuple", "values": ["continuation", "continue", "continuing", "continued"]}, + {"name": "TASK_GRAPH_SOURCE_OF_TRUTH", "module": "loopx/control_plane/work_items/task_graph.py", "container": "list", "values": ["event_ledger", "active_goal_state", "todos", "gates", "leases", "run_history"]}, + {"name": "PRIVATE_BOUNDARY_MONITOR_ACTION_KIND_HINTS", "module": "loopx/control_plane/work_items/work_lane.py", "container": "tuple", "values": ["private", "local_department_doc"]}, + {"name": "WORK_LANE_TODO_ITEM_FIELDS", "module": "loopx/control_plane/work_items/work_lane.py", "container": "tuple", "values": ["index", "text", "todo_id", "status", "priority", "task_class", "action_kind", "task_repository", "claimed_by", "target_key", "next_due_at", "expires_at", "resume_when", "resume_ready", "blocking_monitor_todo_id", "result_hash"]}, + {"name": "DEPENDENCY_OBSERVATION_CLASSIFICATION_HINTS", "module": "loopx/control_plane/work_items/work_lane_context.py", "container": "tuple", "values": ["dependency_observed", "dependency_observation", "dependency_monitor"]}, + {"name": "AGENT_REASONING_CHECKLIST", "module": "loopx/diagnose.py", "container": "list", "values": ["判断 LoopX 本身是否健康:registry/status/quota 是否能读,是否存在 stale projection 或 contract error。", "判断当前 goal 是否已连接:若没有 registry goal 或 attention item,先接入而不是猜任务。", "判断是否存在 user/controller gate:开放 user todo、operator_question、interaction_contract.user_channel 都要纳入判断。", "判断是否可自主推进:只有在用户 gate 不阻塞所选路径、quota 允许、goal_boundary 允许、且有明确 agent todo/recommended_action 时才推进。", "判断是否应先自修复:state_projection_gap、boundary_projection_gap、stale action、todo 投影缺口优先于普通 delivery。", "向用户汇报时给出自己的结论,不要把 machine_signals 当成最终裁决;引用具体 evidence 字段说明理由。"]}, + {"name": "GUARDRAIL_STATUSES", "module": "loopx/domain_packs/ml_experiment.py", "container": "tuple", "values": ["clean", "warning", "failed", "unknown"]}, + {"name": "HYPOTHESIS_STATUSES", "module": "loopx/domain_packs/ml_experiment.py", "container": "tuple", "values": ["active", "supported", "weakened", "retired", "unknown"]}, + {"name": "VOLC_MLP_TASK_STATES", "module": "loopx/domain_packs/ml_experiment.py", "container": "tuple", "values": ["Creating", "Waiting", "Queueing", "Deploying", "Running", "Stopping", "Completed", "Failed", "Stopped", "Unknown"]}, + {"name": "DREAMING_PROPOSAL_DECISIONS", "module": "loopx/dreaming.py", "container": "set", "values": ["approve", "defer", "reject"]}, + {"name": "ACCEPTED_RESULT_KINDS", "module": "loopx/dsh_goal_mode/turn_host_adapter.py", "container": "set", "values": ["validated_progress", "repair_required", "replan_required", "user_action_required", "wait", "iteration_failed"]}, + {"name": "COMPLETED_PHASES", "module": "loopx/dsh_goal_mode/turn_host_adapter.py", "container": "list", "values": ["host_execute", "typed_result"]}, + {"name": "MATERIAL_KINDS", "module": "loopx/dsh_goal_mode/turn_host_adapter.py", "container": "set", "values": ["validated_progress", "repair_required", "replan_required"]}, + {"name": "PLANNER_WORKER_ACTION_KINDS", "module": "loopx/experiments/planner_worker/contract.py", "container": "frozenset", "values": ["edit", "create", "delete", "validate", "research", "design", "investigate"]}, + {"name": "PLANNER_WORKER_AUTONOMY", "module": "loopx/experiments/planner_worker/contract.py", "container": "frozenset", "values": ["narrow", "bounded", "open"]}, + {"name": "PLANNER_WORKER_EXECUTORS", "module": "loopx/experiments/planner_worker/contract.py", "container": "frozenset", "values": ["cheap_worker", "strong_worker", "planner_only"]}, + {"name": "PLANNER_WORKER_MODEL_TIERS", "module": "loopx/experiments/planner_worker/contract.py", "container": "frozenset", "values": ["cheap", "strong", "none"]}, + {"name": "DEFAULT_VALIDATION_EXECUTABLES", "module": "loopx/experiments/planner_worker/traex.py", "container": "frozenset", "values": ["python", "python3", "pytest", "go", "npm", "npx", "cargo"]}, + {"name": "TERMINAL_SETUP_STATES", "module": "loopx/extensions/lark/app_setup.py", "container": "set", "values": ["ready", "failed", "cancelled"]}, + {"name": "CORE_BOT_SCOPES", "module": "loopx/extensions/lark/bot_scopes.py", "container": "tuple", "values": ["im:message", "im:chat:read", "im:chat:create", "im:chat:update", "im:chat.members:read", "im:chat.members:write_only", "contact:user.base:readonly", "contact:contact.base:readonly", "application:application:self_manage", "application:bot.basic_info:read"]}, + {"name": "INBOX_BOT_SCOPES", "module": "loopx/extensions/lark/bot_scopes.py", "container": "tuple", "values": ["im:message:readonly", "im:message.group_msg", "im:message.group_msg.include_bot:read", "im:message.p2p_msg:readonly"]}, + {"name": "SINK_BOT_SCOPES", "module": "loopx/extensions/lark/bot_scopes.py", "container": "tuple", "values": ["cardkit:card:read", "cardkit:card:write", "docs:document.comment:read", "docs:document.comment:create", "docs:document.comment:delete"]}, + {"name": "SUPPORTED_SUPERVISORS", "module": "loopx/extensions/lark/event_collector.py", "container": "set", "values": ["launchd", "systemd"]}, + {"name": "ADDRESSING_SOURCES", "module": "loopx/extensions/lark/event_inbox.py", "container": "set", "values": ["provider_mention", "verified_reply", "legacy_text"]}, + {"name": "CAPTURE_SCOPES", "module": "loopx/extensions/lark/event_inbox.py", "container": "set", "values": ["addressed_only", "configured_chat_all"]}, + {"name": "REPLY_EDITORIAL_STYLES", "module": "loopx/extensions/lark/event_inbox.py", "container": "set", "values": ["concise", "bullet_points_preferred"]}, + {"name": "REPLY_PLACEMENT_POLICIES", "module": "loopx/extensions/lark/event_inbox.py", "container": "set", "values": ["source_thread", "source_context"]}, + {"name": "PRIVATE_PACKET_KEYS", "module": "loopx/extensions/lark/goal_channel_contracts.py", "container": "set", "values": ["base_token", "chat_id", "config_path", "message_id", "path", "profile", "sender_profile", "table_id"]}, + {"name": "REQUIRED_BOT_GROUP_HISTORY_SCOPES", "module": "loopx/extensions/lark/goal_channel_transport.py", "container": "tuple", "values": ["im:message.group_msg", "im:message.group_msg.include_bot:read"]}, + {"name": "REQUIRED_GOAL_TOPIC_SCOPES", "module": "loopx/extensions/lark/goal_channel_transport.py", "container": "tuple", "values": ["im:message", "im:message:readonly"]}, + {"name": "INCOMING_MODES", "module": "loopx/extensions/lark/goal_topic_connections.py", "container": "set", "values": ["mentions", "all"]}, + {"name": "REACTION_PHASES", "module": "loopx/extensions/lark/inbox_reactions.py", "container": "set", "values": ["received", "processing"]}, + {"name": "RECEIVED_OPERATION_PHASES", "module": "loopx/extensions/lark/inbox_reactions.py", "container": "set", "values": ["prepared", "created"]}, + {"name": "MENTION_ID_KEYS", "module": "loopx/extensions/lark/outbound.py", "container": "tuple", "values": ["open_id", "user_id", "union_id"]}, + {"name": "ISSUE_FIX_CARD_FIELDS", "module": "loopx/extensions/lark/presentation/issue_fix_surface.py", "container": "list", "values": ["Task", "Repository", "Issue", "Pull Request", "Route", "Stage", "Validation", "Outcome", "Context Tags", "Status"]}, + {"name": "ISSUE_FIX_METRIC_FIELDS", "module": "loopx/extensions/lark/presentation/issue_fix_surface.py", "container": "list", "values": ["Task", "Metric Group", "Metric", "Baseline", "Current", "Delta", "Numerator", "Denominator", "Metric Source", "Metric Updated At", "Missing Data"]}, + {"name": "ISSUE_FIX_STAGE_OPTIONS", "module": "loopx/extensions/lark/presentation/issue_fix_surface.py", "container": "list", "values": ["reproduction_planned", "fix_in_progress", "fix_review_ready", "ci_pending", "ci_failed", "review_wait", "changes_requested", "merge_ready", "reproduction_blocked", "fix_blocked", "delivery_blocked", "draft_pr", "branch_stale_or_conflicted", "pr_open", "merged", "closed_without_merge", "comment_packet", "comment_blocked", "comment_published", "triage_complete"]}, + {"name": "OPERATOR_CARD_FIELDS", "module": "loopx/extensions/lark/presentation/kanban.py", "container": "list", "values": ["Task", "Claim", "Priority", "User Gate", "Evidence", "Status"]}, + {"name": "HUMAN_REWARD_FIELDS", "module": "loopx/feedback.py", "container": "tuple", "values": ["recorded_at", "decision", "reward", "reason_summary", "follow_up", "lesson"]}, + {"name": "LESSON_KINDS", "module": "loopx/feedback.py", "container": "set", "values": ["route", "priority", "benchmark_protocol", "safety_boundary", "operating_rule"]}, + {"name": "REWARD_VALUES", "module": "loopx/feedback.py", "container": "set", "values": ["positive", "negative", "mixed", "neutral"]}, + {"name": "RUN_OVERLAY_FIELDS", "module": "loopx/feedback.py", "container": "tuple", "values": ["generated_at", "goal_id", "classification", "recommended_action", "health_check", "active_task_count", "active_priorities", "cache_check", "controller_readiness", "json_path", "markdown_path"]}, + {"name": "ATTENTION_OVERRIDE_FIELDS", "module": "loopx/global_registry.py", "container": "tuple", "values": ["waiting_on", "attention_status", "operator_question", "recommended_action", "next_handoff_condition"]}, + {"name": "ROUTE_FIELDS", "module": "loopx/global_registry.py", "container": "tuple", "values": ["source_registry", "repo", "state_file"]}, + {"name": "BOUNDARY_CODES", "module": "loopx/global_risks.py", "container": "set", "values": ["public_boundary_violation", "registry_boundary_risk"]}, + {"name": "SOURCE_SURFACES", "module": "loopx/global_risks.py", "container": "list", "values": ["status contract diagnostics", "global registry health findings", "status attention queue stale-run warnings", "status compact run-history coordination"]}, + {"name": "SOURCE_SURFACES", "module": "loopx/global_todos.py", "container": "list", "values": ["status attention queue", "quota should-run summaries", "active-state todo projections", "compact run-history projection consumed by status"]}, + {"name": "REGISTRY_DIRS", "module": "loopx/goal_mode_context.py", "container": "tuple", "values": [".loopx", ".goal-harness"]}, + {"name": "HELP_FLAGS", "module": "loopx/help_surface.py", "container": "set", "values": ["-h", "--help"]}, + {"name": "MANPAGE_COMMAND_HELP_ONLY", "module": "loopx/help_surface.py", "container": "frozenset", "values": ["agent-context", "archive-runtime", "automation-prompts", "authority-shadow", "backup-state", "capability", "chat-endpoint", "codex-cli-bounded-visible-pilot-adapter", "codex-cli-exec-handoff", "codex-cli-local-driver-plan", "codex-cli-local-scheduler-exec", "codex-cli-local-scheduler-tick", "codex-cli-one-message-loop-pilot", "codex-cli-runtime-idle-detector", "codex-cli-session-probe", "codex-cli-visible-driver-plan", "codex-cli-visible-driver-run", "codex-cli-visible-first-response-capture-plan", "codex-cli-visible-local-driver-pilot", "codex-cli-visible-session-proof", "configure-goal", "content-ops", "decision-context", "dash", "material-lifecycle", "demo", "dreaming", "global-gates", "global-risks", "global-summary", "global-todos", "goal-alignment", "amendment-proposal", "goal-amendment-proposal", "handoff-mode", "heartbeat-prequota", "import-doc-registry-authority", "lark-inbox", "migrate-state", "ml-experiment", "opencode2-goal-worker", "operator-gate", "pr-review", "promotion-gate", "read-only-map", "refresh-state", "reliability-diagnostics", "register-authority-source", "registry-boundary", "reward", "reward-memory", "semantic-preference", "serve-status", "shared-goal-alignment", "uninstall-project", "value-connectors", "version", "worker-bridge"]}, + {"name": "REGISTRY_ATTENTION_FIELDS", "module": "loopx/history.py", "container": "tuple", "values": ["waiting_on", "attention_status", "operator_question", "recommended_action", "next_handoff_condition"]}, + {"name": "HOST_MANAGED_SKILL_AGENT_TYPES", "module": "loopx/host_loop_activation.py", "container": "frozenset", "values": ["ark-managed-agent", "deepseek-harness-native", "trae_app", "traex-cli", "other-agent"]}, + {"name": "SUPPORTED_AGENT_TYPES", "module": "loopx/host_loop_activation.py", "container": "list", "values": ["ark-managed-agent", "codex-app", "codex-app-ssh", "codex-ide-plugin", "codex-cli", "trae_app", "claude-code", "kunluncode", "opencode", "opencode2", "traex-cli", "pi", "gemini-cli", "cursor-agent", "zcode", "agy", "kiro-cli", "deepseek-harness", "deepseek-harness-native", "manual", "other-agent"]}, + {"name": "KIRO_CLI_ACCEPTED_INPUTS", "module": "loopx/kiro_cli_goal_mode/__init__.py", "container": "tuple", "values": ["kiro-cli", "kiro_cli", "kiro cli", "kirocli", "kiro", "kiro-cli-tui", "kiro tui"]}, + {"name": "KIRO_CLI_HOOK_TRIGGERS", "module": "loopx/kiro_cli_goal_mode/__init__.py", "container": "tuple", "values": ["agentSpawn", "userPromptSubmit", "preToolUse", "postToolUse", "stop"]}, + {"name": "TERMINAL_GOAL_STATUSES", "module": "loopx/kunluncode_goal_mode/app_server.py", "container": "set", "values": ["blocked", "budget_limited", "complete", "paused", "usage_limited"]}, + {"name": "AVAILABLE_CAPABILITIES", "module": "loopx/kunluncode_goal_mode/control_plane.py", "container": "tuple", "values": ["shell", "filesystem_write"]}, + {"name": "BLOCKED_QUOTA_STATES", "module": "loopx/long_task_cadence.py", "container": "frozenset", "values": ["blocked", "blocked_health", "focus_wait", "monitor_only", "operator_gate", "paused", "throttled", "user_gate", "waiting"]}, + {"name": "MATERIAL_PROGRESS_GRANULARITIES", "module": "loopx/long_task_cadence.py", "container": "frozenset", "values": ["multi_surface", "implementation_plus_validation", "milestone"]}, + {"name": "SMALL_PROGRESS_GRANULARITIES", "module": "loopx/long_task_cadence.py", "container": "frozenset", "values": ["status_only", "single_surface"]}, + {"name": "MARKDOWN_SUFFIXES", "module": "loopx/materials.py", "container": "set", "values": [".md", ".markdown"]}, + {"name": "PROJECT_SIGNAL_FILES", "module": "loopx/onboarding.py", "container": "tuple", "values": ["GOAL.md", "README.md", "AGENTS.md", "CONTRIBUTING.md", "pyproject.toml", "package.json", "Cargo.toml", "go.mod", "Makefile", "justfile"]}, + {"name": "OPERATOR_GATE_DECISIONS", "module": "loopx/operator_gate.py", "container": "set", "values": ["approve", "reject", "defer"]}, + {"name": "EXPLORE_HARNESS_PROFILES", "module": "loopx/orchestration.py", "container": "tuple", "values": ["generic", "adaptive-resilient", "moe-router"]}, + {"name": "SUBAGENT_REASONING_EFFORTS", "module": "loopx/orchestration.py", "container": "tuple", "values": ["none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra"]}, + {"name": "CODE_EXTENSIONS", "module": "loopx/pr_review.py", "container": "tuple", "values": [".py", ".js", ".jsx", ".ts", ".tsx", ".go", ".rs", ".java", ".kt", ".kts", ".c", ".cc", ".cpp", ".h", ".hpp", ".cs", ".rb", ".php", ".swift", ".m", ".mm"]}, + {"name": "REQUIRED_REVIEW_SECTION_HEADINGS", "module": "loopx/pr_review.py", "container": "tuple", "values": ["动机", "改动思路", "具体改动", "对主干的风险", "我的整体评价"]}, + {"name": "RUNTIME_OR_CLI_PREFIXES", "module": "loopx/pr_review.py", "container": "tuple", "values": ["src/", "lib/", "pkg/", "packages/", "cmd/", "internal/", "server/", "backend/", "app/", "apps/", "scripts/", "bin/", "tools/"]}, + {"name": "SOURCE_SURFACES", "module": "loopx/pr_review.py", "container": "list", "values": ["GitHub pull request metadata", "GitHub pull request body summary", "GitHub pull request changed-file list", "GitHub pull request status check rollup"]}, + {"name": "UI_PREFIXES", "module": "loopx/pr_review.py", "container": "tuple", "values": ["apps/presentation/dashboard/", "apps/web/", "apps/frontend/", "apps/site/", "web/", "frontend/", "ui/", "components/", "pages/", "views/", "public/"]}, + {"name": "PUBLIC_SAFE_BOUNDARY_FIELDS", "module": "loopx/presentation/public_safety.py", "container": "tuple", "values": ["raw_logs_recorded", "raw_transcripts_recorded", "raw_connector_payloads_recorded", "credential_values_recorded", "absolute_paths_recorded", "private_source_bodies_recorded"]}, + {"name": "PROJECT_INVENTORY_PATHS", "module": "loopx/project_map.py", "container": "tuple", "values": ["README.md", "AGENTS.md", ".loopx/registry.json", ".codex/goals", "docs", "tests", "package.json", "pyproject.toml", "requirements.txt"]}, + {"name": "READ_ONLY_MAP_ADAPTER_STATUSES", "module": "loopx/project_map.py", "container": "set", "values": ["connected", "connected-read-only", "read-only-map-ready"]}, + {"name": "STATE_SECTIONS", "module": "loopx/project_map.py", "container": "tuple", "values": ["Authority Sources", "Operating Contract", "Work Clusters", "Validation Surfaces", "Private/Public Boundary", "Next Action", "Progress Ledger"]}, + {"name": "PRIVATE_REGISTRY_PARTS", "module": "loopx/registry.py", "container": "set", "values": [".loopx", ".local", ".codex", "runtime"]}, + {"name": "REPRESENTATIVE_CLI_IMPORTS", "module": "loopx/release_candidate.py", "container": "tuple", "values": ["loopx.cli", "loopx.history", "loopx.quota", "loopx.status"]}, + {"name": "REPRESENTATIVE_DISTRIBUTION_PATHS", "module": "loopx/release_candidate.py", "container": "tuple", "values": ["loopx/cli.py", "loopx/doctor.py", "loopx/history.py", "loopx/quota.py", "loopx/release_candidate.py", "loopx/status.py", "loopx/cli_commands/doctor.py", "loopx/cli_commands/quota.py", "loopx/cli_commands/status.py"]}, + {"name": "PRIVATE_SOURCE_KINDS", "module": "loopx/rollout_event_log.py", "container": "set", "values": ["codex_sessions_jsonl", "local_runtime_state", "private_runner_artifact", "unknown_private_source"]}, + {"name": "RAW_KEY_HINTS", "module": "loopx/rollout_event_log.py", "container": "tuple", "values": ["credential", "local_path", "log", "path", "raw", "secret", "stderr", "stdout", "task_text", "token", "trace", "trajectory", "transcript"]}, + {"name": "ROLLOUT_EVENT_KINDS", "module": "loopx/rollout_event_log.py", "container": "set", "values": ["codex_session_observed", "capability_gap", "compact_blocker", "compact_case_result", "evidence_log_read", "failure_attribution", "pr_merge", "pr_review_ack", "quota_monitor_poll", "quota_should_run", "quota_spend", "quota_void", "refresh_state", "refresh_external_delivery", "research_evidence", "research_hypothesis", "todo_add", "todo_archive_completed", "todo_claim", "todo_complete", "todo_supersede", "todo_update", "validation"]}, + {"name": "SKIP_PARTS", "module": "loopx/semantics/inventory.py", "container": "frozenset", "values": ["__pycache__", "node_modules"]}, + {"name": "SOURCE_SUFFIXES", "module": "loopx/semantics/inventory.py", "container": "tuple", "values": [".py", ".ts"]}, + {"name": "BLOCKED_STATUSES", "module": "loopx/session_runtime.py", "container": "set", "values": ["blocked", "error", "failed", "timed_out"]}, + {"name": "COMPACT_SUFFIX_WORDS", "module": "loopx/session_runtime.py", "container": "frozenset", "values": ["id", "ids", "ref", "refs", "count", "at"]}, + {"name": "EXPLICIT_COMPACT_COLLISION_KEYS", "module": "loopx/session_runtime.py", "container": "frozenset", "values": ["conversation_id", "log_count", "message_id", "prompt_token_count", "prompt_tokens", "trace_id"]}, + {"name": "HUMAN_GATE_ACTORS", "module": "loopx/session_runtime.py", "container": "set", "values": ["controller", "human", "operator", "owner", "user"]}, + {"name": "OPEN_GATE_STATUSES", "module": "loopx/session_runtime.py", "container": "set", "values": ["blocked", "needs_decision", "open", "pending", "requested", "requires_decision", "waiting"]}, + {"name": "SOURCE_ID_KEYS", "module": "loopx/session_runtime.py", "container": "tuple", "values": ["session_id", "event_id", "outcome_id", "gate_id", "approval_id", "artifact_id", "tool_call_id", "run_id", "ref_id"]}, + {"name": "TIMESTAMP_KEYS", "module": "loopx/session_runtime.py", "container": "tuple", "values": ["created_at", "event_at", "updated_at", "timestamp"]}, + {"name": "VALIDATED_STATUSES", "module": "loopx/session_runtime.py", "container": "set", "values": ["ok", "passed", "success", "validated"]}, + {"name": "PACKAGED_HOST_SKILL_IDS", "module": "loopx/skill_install_readback.py", "container": "list", "values": ["loopx-project", "loopx-pr-program", "loopx-pr-review", "loopx-doc-registry", "loopx-benchmark", "loopx-self-repair"]}, + {"name": "EXISTING_LOOPX_CAPABILITY_SKILL_SIGNATURES", "module": "loopx/slash_command_files.py", "container": "tuple", "values": ["# LoopX PR Review", "Run `loopx pr-review` first"]}, + {"name": "LEGACY_UPGRADABLE_SIGNATURES", "module": "loopx/slash_command_files.py", "container": "tuple", "values": ["loopx goal-mode setup (NOT Claude Code's built-in /goal)", "The output is loopx control-plane SETUP", "goalmode_cmd.py"]}, + {"name": "STAT_FIELDS", "module": "loopx/state_backup.py", "container": "tuple", "values": ["paths", "files", "directories", "symlinks", "bytes"]}, + {"name": "AGENT_TODO_HEADER_MARKERS", "module": "loopx/state_projection.py", "container": "tuple", "values": ["agent todo", "agent backlog", "agent action", "项目 agent", "agent 待办"]}, + {"name": "TODO_METADATA_KEYS", "module": "loopx/state_projection.py", "container": "tuple", "values": ["action_kind", "task_domain", "capability_binding_ref", "task_repository", "continuation_policy", "required_write_scopes", "required_capabilities", "target_capabilities", "decision_scope", "required_decision_scopes", "claimed_by", "bound_agent", "goal_bound", "blocks_agent", "excluded_agents", "global_gate", "unblocks_todo_id", "successor_todo_ids", "completion_continuation", "completion_recovery", "resume_when", "no_followup", "target_key", "cadence", "next_due_at", "last_checked_at", "result_hash", "consecutive_no_change", "material_change", "max_no_change_before_replan", "note", "evidence", "reason", "completed_at", "updated_at", "superseded_by"]}, + {"name": "USER_TODO_HEADER_MARKERS", "module": "loopx/state_projection.py", "container": "tuple", "values": ["user todo", "owner review", "owner todo", "user action", "用户", "人工", "owner"]}, + {"name": "AUTONOMOUS_RUN_HISTORY_NEUTRAL_CLASSIFICATIONS", "module": "loopx/status.py", "container": "set", "values": ["quota_slot_spent", "quota_slot_voided", "delivery_completion_spend_accounted_v0"]}, + {"name": "BACKLOG_HYGIENE_SECTION_HEADINGS", "module": "loopx/status.py", "container": "tuple", "values": ["Next Action", "Operating Lessons"]}, + {"name": "CONNECTED_ADAPTER_STATUSES", "module": "loopx/status.py", "container": "set", "values": ["connected", "connected-read-only", "pre-tick-runnable"]}, + {"name": "EVENT_LEDGER_EVIDENCE_CLASSIFICATIONS", "module": "loopx/status.py", "container": "set", "values": ["inspect_eval_result", "inspect_result", "needs_more_read_only_evidence", "read_only_project_map"]}, + {"name": "EVENT_LEDGER_EVIDENCE_HINTS", "module": "loopx/status.py", "container": "tuple", "values": ["artifact", "blocker", "ci", "data", "deploy", "done", "eval", "evidence", "failure", "fail", "metric", "monitor", "validation"]}, + {"name": "EVENT_LEDGER_STATE_CLASSIFICATIONS", "module": "loopx/status.py", "container": "set", "values": ["state_refreshed", "public_harness_healthy"]}, + {"name": "LEGACY_EXTERNAL_EVIDENCE_CLASSIFICATION_PREFIXES", "module": "loopx/status.py", "container": "tuple", "values": ["await_", "external_evidence_observation_"]}, + {"name": "LIFECYCLE_PRIORITY", "module": "loopx/status.py", "container": "tuple", "values": ["controller_ready", "reward_judged", "operator_approved", "controller_gated", "operator_gated", "adapter_inspected", "mapped", "refreshed", "connected", "registered", "planned", "run_recorded"]}, + {"name": "REGISTRY_WAITING_ON_OVERRIDES", "module": "loopx/status.py", "container": "set", "values": ["user_or_controller", "controller", "codex", "external_evidence"]}, + {"name": "SOURCE_REGISTRY_SHADOW_FINDINGS", "module": "loopx/status.py", "container": "set", "values": ["source_registry_missing", "stale_source_registry"]}, + {"name": "CONFIGURE_GOAL_REQUEST_FIELDS", "module": "loopx/status_server.py", "container": "set", "values": ["goal_id", "quota_compute", "quota_window_hours", "self_repair_enabled", "self_repair_health", "self_repair_waiting_projection", "multi_subagent_feature", "orchestration_mode", "spawn_allowed", "max_children", "allowed_domains", "clear_allowed_domains", "registered_agents", "clear_registered_agents", "peer_task_coordinator", "clear_peer_task_coordinator", "agent_profiles", "clear_agent_profiles", "agent_work_modes", "clear_agent_work_modes", "todo_lifecycle_authority", "clear_todo_lifecycle_authority", "agent_model", "supervisor_agent", "supervised_agents", "clear_supervisor", "write_scope", "replace_write_scope", "clear_write_scope", "boundary_authority_scopes", "boundary_authority_source", "boundary_authority_decision_id", "boundary_authority_recorded_at", "boundary_authority_expires_at", "clear_boundary_authority"]}, + {"name": "REWARD_REQUEST_FIELDS", "module": "loopx/status_server.py", "container": "set", "values": ["goal_id", "run_generated_at", "recorded_at", "decision", "reward", "reason_summary", "follow_up", "lesson_kind", "lesson_summary", "lesson_avoid", "lesson_prefer"]}, + {"name": "GLOBAL_GATES_SOURCE_SURFACES", "module": "loopx/summary_all.py", "container": "list", "values": ["status attention queue", "quota should-run summaries", "active-state todo projections", "compact run-history projection consumed by status"]}, + {"name": "SOURCE_SURFACES", "module": "loopx/summary_all.py", "container": "list", "values": ["global registry compact status", "status attention queue", "quota should-run summaries", "active-state todo projections", "run history index summaries"]}, + {"name": "CODEX_THREAD_HOST_SURFACES", "module": "loopx/thread_agent_binding.py", "container": "frozenset", "values": ["codex-app", "codex-app-ssh", "codex-ide-plugin", "codex-cli-tui"]}, + {"name": "ALLOWED_TODO_SUGGESTION_SOURCES", "module": "loopx/todo_suggestion_prompt.py", "container": "tuple", "values": ["recent-repo", "issues-prs", "failing-checks", "todo-markers", "complexity-hotspots", "loopx-deferred", "docs-smokes"]}, + {"name": "ALLOWED_TODO_SUGGESTION_TRIGGERS", "module": "loopx/todo_suggestion_prompt.py", "container": "tuple", "values": ["user-requested", "post-connect", "no-runnable-todo", "repo-changed", "quality-watch"]}, + {"name": "DEFAULT_TODO_SUGGESTION_SOURCES", "module": "loopx/todo_suggestion_prompt.py", "container": "tuple", "values": ["recent-repo", "issues-prs", "failing-checks", "todo-markers", "loopx-deferred", "docs-smokes"]}, + {"name": "HOST_LOOP_UPDATE_STATUSES", "module": "loopx/upgrade.py", "container": "set", "values": ["missing", "partial", "stale", "unknown", "error", "unavailable"]}, + {"name": "PROJECT_POLICY_MARKERS", "module": "loopx/upgrade.py", "container": "tuple", "values": ["Current controller policy:", "Primary stability objective:", "Current controller policy"]}, + {"name": "COPY_DIRECTORIES", "module": "loopx/windows_install.py", "container": "tuple", "values": ["loopx", "scripts", "skills", "docs", "man", "examples", "apps", ".github"]}, + {"name": "COPY_FILES", "module": "loopx/windows_install.py", "container": "tuple", "values": ["README.md", "README.zh-CN.md", "LICENSE", "pyproject.toml"]}, + {"name": "REQUIRED_DEEP_CHECKS", "module": "loopx/windows_install.py", "container": "set", "values": ["command_package_same_root", "representative_cli_commands", "representative_cli_imports", "representative_package_paths"]}, + {"name": "ACTIVE_USER_SIMULATOR_ALLOWED_EVIDENCE_BASIS", "module": "loopx/worker_bridge.py", "container": "tuple", "values": ["public task prompt visible to worker", "worker public artifacts", "compact LoopX status and run metadata"]}, + {"name": "ACTIVE_USER_SIMULATOR_NO_ORACLE_AUDIT_KEYS", "module": "loopx/worker_bridge.py", "container": "tuple", "values": ["hidden_tests_visible", "expected_solution_visible", "benchmark_answer_key_visible", "credential_values_visible", "private_material_visible", "solution_patch_visible"]}, + {"name": "MANAGED_ENTRY_STATUSES", "module": "loopx/workflow_skill_install.py", "container": "set", "values": ["created", "updated", "unchanged", "upgraded_legacy_managed"]} + ], + "python_literal_aliases": [ + {"name": "CommandQualification", "module": "loopx/control_plane/testing/cli_output_budget.py", "values": ["qualified_default", "explicit_cold_path_exception"]}, + {"name": "OutputFormat", "module": "loopx/control_plane/testing/cli_output_budget.py", "values": ["json", "markdown"]}, + {"name": "QualificationPolicy", "module": "loopx/control_plane/testing/cli_output_budget.py", "values": ["absolute_hot_path", "baseline_and_growth", "explicit_limit_cold_path"]}, + {"name": "Metric", "module": "loopx/control_plane/testing/cli_output_differential.py", "values": ["chars", "utf8_bytes", "lines", "compact_payload_chars"]}, + {"name": "TodoCompletionProjectionSource", "module": "loopx/control_plane/todos/durable_completion.py", "values": ["materialized", "event_log"]}, + {"name": "TodoListProjectionView", "module": "loopx/control_plane/todos/list_projection.py", "values": ["agent_lane_hot_path", "explicit_limit_cold_path"]}, + {"name": "WorkspaceFileType", "module": "loopx/experiments/planner_worker/runtime.py", "values": ["regular", "symlink", "directory", "special", "deleted"]}, + {"name": "MentionIdentityKind", "module": "loopx/extensions/lark/outbound.py", "values": ["user_id", "open_id", "union_id"]} + ], + "typescript_const_arrays": [ + {"name": "AGENT_CONTEXT_PHASES", "module": "loopx/control_plane/agent_context.ts", "values": ["before_plan", "before_delegate", "after_delegate_result"]}, + {"name": "DELIVERY_WORKSPACE_IDENTITY_KINDS", "module": "loopx/control_plane/agents/delivery_workspace.ts", "values": ["git_repository", "local_goal"]}, + {"name": "DELIVERY_WORKSPACE_KINDS", "module": "loopx/control_plane/agents/delivery_workspace.ts", "values": ["canonical_checkout", "independent_git_worktree", "local_goal_workspace"]}, + {"name": "AUTHORITY_STORE_REQUIRED_GUARANTEES", "module": "loopx/control_plane/coordination/authority_store.ts", "values": ["atomic_event_projection_receipt_commit", "conditional_provider_revision", "durable_same_key_readback", "explicit_ambiguous_commit", "ordered_cursor_scan", "stable_store_lineage"]}, + {"name": "HANDOFF_MODES", "module": "loopx/control_plane/coordination/handoff_mode_policy.ts", "values": ["legacy", "soft_claim", "hard_lease"]}, + {"name": "SETTLEMENT_BINDING_KINDS", "module": "loopx/control_plane/effect_program.ts", "values": ["todo", "autonomous_replan", "unbound"]}, + {"name": "SETTLEMENT_FAILURE_KINDS", "module": "loopx/control_plane/effect_program.ts", "values": ["invalid_identity", "receipt_missing", "identity_mismatch", "writeback_missing", "writeback_rejected", "quota_spend_rejected", "terminal_closeout_rejected", "cancelled", "permission_denied", "budget_rejected", "effect_outcome_unknown"]}, + {"name": "SETTLEMENT_STEP_KINDS", "module": "loopx/control_plane/effect_program.ts", "values": ["validation", "durable_writeback", "quota_spend", "terminal_closeout"]}, + {"name": "EFFECT_RUNTIME_ERROR_KINDS", "module": "loopx/control_plane/effect_runtime_errors.ts", "values": ["request_rejected", "conflict", "io_transient", "io_permanent", "lock_timeout", "internal_failure"]}, + {"name": "GOAL_AMENDMENT_CLASSES", "module": "loopx/control_plane/goals/goal_amendment_proposal.ts", "values": ["lane_route", "shared_work_graph", "shared_acceptance", "protected_authority"]}, + {"name": "GOAL_AMENDMENT_PROPOSAL_ADMISSIONS", "module": "loopx/control_plane/goals/goal_amendment_proposal.ts", "values": ["admitted", "needs_rebase"]}, + {"name": "GOAL_AMENDMENT_PROPOSAL_ADMISSION_FACTS", "module": "loopx/control_plane/goals/goal_amendment_proposal.ts", "values": ["base_state_event_basis_sequence_behind_derived_head", "base_source_basis_digest_mismatch", "base_source_basis_unverifiable", "base_revision_basis_superseded"]}, + {"name": "REVISION_BASIS_VALUES", "module": "loopx/control_plane/goals/goal_amendment_proposal.ts", "values": ["state_event_log", "markdown_active_state", "canonical_todo_snapshot"]}, + {"name": "SHARED_GOAL_ALIGNMENT_CONFLICT_FACTS", "module": "loopx/control_plane/goals/shared_goal_alignment.ts", "values": ["frontier_basis_unverifiable", "lease_owner_mismatch", "open_lane_replan_obligation", "peer_claimed_lane_conflict"]}, + {"name": "SHARED_GOAL_ALIGNMENT_DRIFT_FACTS", "module": "loopx/control_plane/goals/shared_goal_alignment.ts", "values": ["frontier_basis_behind"]}, + {"name": "RECEIPT_BOUND_MONITOR_PHASES", "module": "loopx/control_plane/quota/settlement_phase.ts", "values": ["poll_due", "settlement_pending", "settled"]}, + {"name": "RECEIPT_BOUND_REPLAY_PHASES", "module": "loopx/control_plane/quota/settlement_phase.ts", "values": ["open", "settlement_pending", "settled"]}, + {"name": "DELIVERY_WORKSPACE_REQUIREMENTS", "module": "loopx/control_plane/quota/settlement_workspace_causality.ts", "values": ["required", "not_required", "unknown"]}, + {"name": "QUOTA_SPEND_SOURCES", "module": "loopx/control_plane/quota/spend_commit.ts", "values": ["heartbeat", "controller", "adapter", "visible-goal"]}, + {"name": "SCHEDULER_HEARTBEAT_COMMIT_OPERATIONS", "module": "loopx/control_plane/scheduler/heartbeat_commit.ts", "values": ["ack", "host_failure"]}, + {"name": "SCHEDULER_STATE_OPERATIONS", "module": "loopx/control_plane/scheduler/state_store.ts", "values": ["rrule_for_minutes", "normalize_rrule", "rrule_interval_minutes", "normalize_failure", "normalize_failures", "retain_failures", "merge_failure", "normalize_state", "build_state", "state_path"]}, + {"name": "SCHEDULER_CADENCE_TRANSITIONS", "module": "loopx/control_plane/scheduler/state_transition_rules.ts", "values": ["initial", "identity_reset", "retry_unacknowledged_failure", "hold_active_initial", "advance_after_interval", "hold_until_interval"]}, + {"name": "SCHEDULER_HOST_TRANSITIONS", "module": "loopx/control_plane/scheduler/state_transition_rules.ts", "values": ["apply_required", "host_match_ack_required", "recorded_failure_suppressed", "settled"]}, + {"name": "TODO_OWNERSHIP_INTENT_FIELDS", "module": "loopx/control_plane/todos/authoring_scope.ts", "values": ["claimed_by", "clear_claim", "excluded_agents"]}, + {"name": "TODO_COMPLETION_CONTINUATIONS", "module": "loopx/control_plane/todos/completion_state.ts", "values": ["active_goal", "successor", "no_followup"]}, + {"name": "TODO_COMPLETION_RECOVERIES", "module": "loopx/control_plane/todos/completion_state.ts", "values": ["same_turn_terminal_closeout", "lifecycle_reentry_terminal_closeout"]}, + {"name": "TODO_DECISION_METADATA_FIELDS", "module": "loopx/control_plane/todos/decision_metadata.ts", "values": ["decision_scope", "required_decision_scopes"]}, + {"name": "TODO_DECISION_SCOPE_GRANULARITIES", "module": "loopx/control_plane/todos/decision_metadata.ts", "values": ["action", "lane", "goal", "project", "global"]}, + {"name": "TODO_DECISION_SCOPE_KINDS", "module": "loopx/control_plane/todos/decision_metadata.ts", "values": ["private_read", "write_scope", "resource", "production", "public_claim", "direction", "other"]}, + {"name": "MONITOR_CONFIGURATION_FIELDS", "module": "loopx/control_plane/todos/monitor_metadata.ts", "values": ["target_key", "cadence", "next_due_at", "expires_at", "watch_only"]}, + {"name": "MONITOR_METADATA_FIELDS", "module": "loopx/control_plane/todos/monitor_metadata.ts", "values": ["target_key", "monitor_effect_id", "cadence", "next_due_at", "expires_at", "last_checked_at", "result_hash", "consecutive_no_change", "material_change", "material_change_generation", "max_no_change_before_replan", "watch_only"]}, + {"name": "TODO_RESUME_KINDS", "module": "loopx/control_plane/todos/resume_condition.ts", "values": ["todo_done", "pr_merged", "capacity_available", "monitor_changed", "resume_at"]}, + {"name": "TODO_WORK_REQUIREMENT_FIELDS", "module": "loopx/control_plane/todos/work_requirements.ts", "values": ["action_kind", "task_domain", "task_repository", "required_write_scopes", "required_capabilities", "target_capabilities", "explore_result_node_refs"]}, + {"name": "DELIVERY_BOUNDARIES", "module": "loopx/control_plane/turn_driver/delivery_continuity.ts", "values": ["in_flight_continuation", "semantic_closeout"]}, + {"name": "DELIVERY_CONTINUITY_PREEMPTIONS", "module": "loopx/control_plane/turn_driver/delivery_continuity.ts", "values": ["heartbeat_receipt", "blocking_work_lane", "autonomous_replan", "control_repair", "delivery_not_allowed"]}, + {"name": "TURN_RESULT_KINDS", "module": "loopx/control_plane/turn_driver/settlement.ts", "values": ["validated_progress", "validated_completion", "repair_required", "replan_required", "user_action_required", "wait", "iteration_failed", "host_failure", "validation_failed", "writeback_failed", "quota_spend_failed", "terminal_closeout_failed"]}, + {"name": "DELIVERY_OUTCOMES", "module": "loopx/control_plane/work_items/delivery_outcome.ts", "values": ["surface_only", "outcome_gap", "outcome_progress", "primary_goal_outcome"]}, + {"name": "MATERIAL_DELIVERY_OUTCOMES", "module": "loopx/control_plane/work_items/delivery_outcome.ts", "values": ["outcome_gap", "outcome_progress", "primary_goal_outcome"]}, + {"name": "TASK_LEASE_LIFECYCLE_OPERATIONS", "module": "loopx/control_plane/work_items/task_lease_lifecycle.ts", "values": ["renew", "transfer", "release", "terminal_verify", "holder_verify", "fence_close"]}, + {"name": "TASK_LEASE_LIFECYCLE_DECISION_OPERATIONS", "module": "loopx/control_plane/work_items/task_lease_lifecycle_decision.ts", "values": ["renew", "transfer", "release"]} + ], + "duplicate_definitions": { + "cross_runtime_twins": [ + {"name": "ACTION_PORTFOLIO_PLANNING_PACKET_REQUEST_SCHEMA", "is_schema_version": false, "value": "quota_planning_packet_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "ACTION_PORTFOLIO_PLANNING_PACKET_RESULT_SCHEMA", "is_schema_version": false, "value": "quota_planning_packet_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "ACTION_PORTFOLIO_SELECTION_REQUEST_SCHEMA", "is_schema_version": false, "value": "action_selection_qualification_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "ACTION_PORTFOLIO_SELECTION_RESULT_SCHEMA", "is_schema_version": false, "value": "action_selection_qualification_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "ACTION_SIGNATURE_COVERAGE_V0", "is_schema_version": false, "value": "turn_envelope_action_dimensions_v0", "modules": ["loopx/control_plane/quota/turn_envelope.py", "loopx/control_plane/quota/turn_envelope.ts"]}, + {"name": "ACTION_SIGNATURE_COVERAGE_V1", "is_schema_version": false, "value": "turn_envelope_action_dimensions_v1", "modules": ["loopx/control_plane/quota/turn_envelope.py", "loopx/control_plane/quota/turn_envelope.ts"]}, + {"name": "ACTION_SIGNATURE_COVERAGE_V2", "is_schema_version": false, "value": "turn_envelope_action_dimensions_v2", "modules": ["loopx/control_plane/quota/turn_envelope.py", "loopx/control_plane/quota/turn_envelope.ts"]}, + {"name": "ACTION_SIGNATURE_COVERAGE_V3", "is_schema_version": false, "value": "turn_envelope_action_dimensions_v3", "modules": ["loopx/control_plane/quota/turn_envelope.py", "loopx/control_plane/quota/turn_envelope.ts"]}, + {"name": "ACTION_SIGNATURE_COVERAGE_V4", "is_schema_version": false, "value": "turn_envelope_action_dimensions_v4", "modules": ["loopx/control_plane/quota/turn_envelope.py", "loopx/control_plane/quota/turn_envelope.ts"]}, + {"name": "ACTION_SIGNATURE_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_action_signature_v0", "modules": ["loopx/control_plane/quota/turn_envelope.py", "loopx/control_plane/quota/turn_envelope.ts"]}, + {"name": "APP_AUTOMATION_STATEFUL_BACKOFF_STATE_KEY", "is_schema_version": false, "value": "scheduler_hint.app_automation.stateful_backoff", "modules": ["loopx/control_plane/scheduler/state.py", "loopx/control_plane/scheduler/state_store.ts"]}, + {"name": "CAPABILITY_HOOK_INTENT_SCHEMA", "is_schema_version": false, "value": "loopx_capability_intent_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "CAPABILITY_HOOK_INTERACTION_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_interaction_projection_hook_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "CAPABILITY_HOOK_POST_WRITEBACK_INPUT_SCHEMA", "is_schema_version": false, "value": "loopx_post_writeback_capability_hook_input_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "CAPABILITY_HOOK_POST_WRITEBACK_RECEIPT_SCHEMA", "is_schema_version": false, "value": "loopx_post_writeback_capability_hook_receipt_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "CAPABILITY_HOOK_POST_WRITEBACK_REGISTRATION_SCHEMA", "is_schema_version": false, "value": "loopx_post_writeback_capability_hook_registration_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "CAPABILITY_HOOK_POST_WRITEBACK_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_post_writeback_capability_hook_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "CAPABILITY_HOOK_REGISTRATION_SCHEMA", "is_schema_version": false, "value": "loopx_capability_hook_registration_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "CAPABILITY_HOOK_TURN_START_REGISTRATION_SCHEMA", "is_schema_version": false, "value": "loopx_turn_start_capability_hook_registration_v1", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "CAPABILITY_HOOK_TURN_START_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_turn_start_capability_hook_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "CODEX_APP_SURFACE", "is_schema_version": false, "value": "codex_app", "modules": ["loopx/control_plane/scheduler/state.py", "loopx/control_plane/scheduler/state_store.ts"]}, + {"name": "CONTRACT_CAPSULE_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_contract_capsule_v0", "modules": ["loopx/control_plane/quota/turn_envelope.py", "loopx/control_plane/quota/turn_envelope.ts"]}, + {"name": "COORDINATION_RUNTIME_SHADOW_BOOTSTRAP_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_bootstrap_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "COORDINATION_RUNTIME_SHADOW_BOOTSTRAP_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_bootstrap_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "COORDINATION_RUNTIME_SHADOW_COMMIT_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_commit_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "COORDINATION_RUNTIME_SHADOW_COMMIT_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "COORDINATION_RUNTIME_SHADOW_INSPECT_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_inspect_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "COORDINATION_RUNTIME_SHADOW_INSPECT_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_inspection_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "COORDINATION_RUNTIME_SHADOW_QUALIFY_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_qualify_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "COORDINATION_RUNTIME_SHADOW_QUALIFY_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_qualification_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "COORDINATION_RUNTIME_SHADOW_RECEIPT_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_receipt_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "COORDINATION_RUNTIME_SHADOW_ROLLBACK_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_rollback_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "COORDINATION_RUNTIME_SHADOW_ROLLBACK_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_rollback_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "COORDINATION_RUNTIME_SHADOW_TODO_READ_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_todo_read_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "COORDINATION_RUNTIME_SHADOW_TODO_READ_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_todo_read_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_BOUNDARY_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_delivery_boundary_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_CONTINUITY_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_delivery_continuity_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_ROUTING_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_delivery_routing_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_ROUTING_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_delivery_routing_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_WORKSPACE_CAUSALITY_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_delivery_workspace_causality_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_WORKSPACE_CAUSALITY_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_delivery_workspace_causality_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_WORKSPACE_CAUSALITY_SCHEMA", "is_schema_version": false, "value": "delivery_workspace_causality_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_WORKSPACE_LEGACY_RECEIPT_EVIDENCE_SCHEMA", "is_schema_version": false, "value": "legacy_settlement_receipt_evidence_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_WORKSPACE_RESOLUTION_SCHEMA", "is_schema_version": false, "value": "delivery_workspace_resolution_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_WORKSPACE_SETTLEMENT_REQUIREMENT_SCHEMA", "is_schema_version": false, "value": "settlement_workspace_requirement_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_WORKSPACE_SNAPSHOT_LEGACY_SNAPSHOT_SCHEMA", "is_schema_version": false, "value": "delivery_workspace_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_WORKSPACE_SNAPSHOT_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_delivery_workspace_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_WORKSPACE_SNAPSHOT_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_delivery_workspace_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "DELIVERY_WORKSPACE_SNAPSHOT_SNAPSHOT_SCHEMA", "is_schema_version": false, "value": "delivery_workspace_v1", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "GOAL_ACTION_CATALOG_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_goal_action_catalog_v1", "modules": ["loopx/control_plane/goals/operator_actions.py", "loopx/control_plane/goals/operator_actions.ts"]}, + {"name": "GOAL_ACTION_PROJECTION_REQUEST_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_goal_action_projection_request_v2", "modules": ["loopx/control_plane/goals/operator_actions.py", "loopx/control_plane/goals/operator_actions.ts"]}, + {"name": "GOAL_AMENDMENT_PROPOSAL_ADMISSION_SCHEMA_VERSION", "is_schema_version": true, "value": "goal_amendment_proposal_admission_v0", "modules": ["loopx/control_plane/goals/goal_amendment_proposal.py", "loopx/control_plane/goals/goal_amendment_proposal.ts"]}, + {"name": "GOAL_AMENDMENT_PROPOSAL_REQUEST_SCHEMA_VERSION", "is_schema_version": true, "value": "goal_amendment_proposal_request_v0", "modules": ["loopx/control_plane/goals/goal_amendment_proposal.py", "loopx/control_plane/goals/goal_amendment_proposal.ts"]}, + {"name": "GOAL_AMENDMENT_PROPOSAL_SCHEMA_VERSION", "is_schema_version": true, "value": "goal_amendment_proposal_v0", "modules": ["loopx/control_plane/goals/goal_amendment_proposal.py", "loopx/control_plane/goals/goal_amendment_proposal.ts"]}, + {"name": "GOVERNED_CAPABILITY_LIFECYCLE_PACKET_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_governed_capability_lifecycle_packet_v0", "modules": ["loopx/control_plane/governed_capability.ts", "loopx/extensions/governed_capability_execution.py"]}, + {"name": "GOVERNED_CAPABILITY_LIFECYCLE_REDUCTION_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_governed_capability_lifecycle_reduction_v0", "modules": ["loopx/control_plane/governed_capability.ts", "loopx/extensions/governed_capability_execution.py"]}, + {"name": "GOVERNED_CAPABILITY_RECEIPT_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_governed_capability_execution_receipt_v0", "modules": ["loopx/control_plane/governed_capability.ts", "loopx/extensions/governed_capability_execution.py"]}, + {"name": "GOVERNED_CAPABILITY_RUN_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_governed_capability_run_v0", "modules": ["loopx/control_plane/governed_capability.ts", "loopx/extensions/governed_capability_execution.py"]}, + {"name": "HOST_ADAPTER_SETTLEMENT_SCHEMA_VERSION", "is_schema_version": true, "value": "host_adapter_todo_settlement_v0", "modules": ["loopx/control_plane/host_adapter_settlement.py", "loopx/control_plane/turn_driver/host_todo_completion.ts"]}, + {"name": "HOST_TODO_COMPLETION_REDUCTION_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_host_todo_completion_reduction_v0", "modules": ["loopx/control_plane/host_adapter_settlement.py", "loopx/control_plane/turn_driver/host_todo_completion.ts"]}, + {"name": "HOST_TODO_COMPLETION_TRANSACTION_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_host_todo_completion_transaction_v0", "modules": ["loopx/control_plane/host_adapter_settlement.py", "loopx/control_plane/turn_driver/host_todo_completion.ts"]}, + {"name": "INTERACTION_CONTRACT_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_interaction_contract_v0", "modules": ["loopx/control_plane/work_items/interaction_contract.py", "loopx/control_plane/work_items/interaction_contract.ts"]}, + {"name": "LEASE_PARTITION", "is_schema_version": false, "value": "leases", "modules": ["loopx/control_plane/coordination/local_authority_shadow_outbox.ts", "loopx/control_plane/coordination/local_authority_shadow_projection.py"]}, + {"name": "LEGACY_CODEX_APP_STATEFUL_BACKOFF_STATE_KEY", "is_schema_version": false, "value": "scheduler_hint.codex_app.stateful_backoff", "modules": ["loopx/control_plane/scheduler/state.py", "loopx/control_plane/scheduler/state_store.ts"]}, + {"name": "LEGACY_COORDINATION_WRITER_FENCE_ENGAGE_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_legacy_coordination_writer_fence_engage_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LEGACY_COORDINATION_WRITER_FENCE_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_legacy_coordination_writer_fence_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LEGACY_COORDINATION_WRITER_FENCE_SCHEMA", "is_schema_version": false, "value": "loopx_legacy_coordination_writer_fence_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LEGACY_COORDINATION_WRITE_CHECK_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_legacy_coordination_write_check_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LEGACY_COORDINATION_WRITE_CHECK_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_legacy_coordination_write_check_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LEGACY_WRITER_FENCED_REMEDIATION", "is_schema_version": false, "value": "legacy coordination writer is fenced; use the promoted canonical authority ({authority_mode}) for goal {goal_id}; fence {fence_id}; the primary record was not changed", "modules": ["loopx/control_plane/coordination/legacy_writer_fence.py", "loopx/control_plane/coordination/legacy_writer_fence.ts"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_BINDING_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_binding_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_COMMIT_ENTRY_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_commit_entry_request_v1", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_COMMIT_ENTRY_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_commit_entry_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_CONFIG_SCHEMA", "is_schema_version": false, "value": "loopx_local_authority_shadow_config_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_DRAIN_CURSOR_SCHEMA", "is_schema_version": false, "value": "loopx_local_authority_shadow_drain_cursor_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_EVENT_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_outbox_event_v1", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_EVIDENCE_SCHEMA", "is_schema_version": false, "value": "loopx_local_authority_shadow_evidence_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_OBSERVATION_RECEIPT_SCHEMA", "is_schema_version": false, "value": "loopx_local_authority_shadow_observation_receipt_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_OUTBOX_COMMIT_SCHEMA", "is_schema_version": false, "value": "loopx_local_authority_shadow_outbox_commit_v1", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_OUTBOX_ENTRY_SCHEMA", "is_schema_version": false, "value": "loopx_local_authority_shadow_outbox_entry_v1", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_PROJECTION_SCHEMA", "is_schema_version": false, "value": "loopx_local_authority_shadow_projection_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_READ_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_outbox_read_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_READ_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_outbox_read_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_local_authority_shadow_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_TRANSACTION_EVIDENCE_SCHEMA", "is_schema_version": false, "value": "loopx_local_authority_shadow_evidence_v1", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_TRANSACTION_PROJECTION_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_projection_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_AUTHORITY_SHADOW_TRANSACTION_RECEIPT_SCHEMA", "is_schema_version": false, "value": "loopx_coordination_runtime_shadow_outbox_receipt_v1", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_COORDINATION_MUTATION_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_local_coordination_mutation_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_COORDINATION_MUTATION_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_local_coordination_mutation_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_COORDINATION_PROMOTION_RECEIPT_SCHEMA", "is_schema_version": false, "value": "loopx_local_coordination_promotion_receipt_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_COORDINATION_PROMOTION_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_local_coordination_promotion_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_COORDINATION_PROMOTION_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_local_coordination_promotion_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_COORDINATION_TODO_CLAIM_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_local_coordination_todo_claim_request_v0", "modules": ["loopx/control_plane/coordination/local_authority.py", "loopx/control_plane/coordination/local_authority_runtime.ts"]}, + {"name": "LOCAL_COORDINATION_TODO_LIST_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_local_coordination_todo_list_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_COORDINATION_TODO_LIST_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_local_coordination_todo_list_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_COORDINATION_TODO_READ_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_local_coordination_todo_read_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "LOCAL_COORDINATION_TODO_READ_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_local_coordination_todo_read_result_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "POST_WRITEBACK_HOOK_DISPATCH_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_post_writeback_capability_hook_dispatch_v0", "modules": ["loopx/control_plane/capability_hooks.py", "loopx/control_plane/post_writeback_hook_transaction.ts"]}, + {"name": "QUOTA_MONITOR_POLL_CLASSIFICATION", "is_schema_version": false, "value": "quota_monitor_poll", "modules": ["loopx/control_plane/quota/monitor_poll.py", "loopx/control_plane/quota/monitor_poll_commit.ts"]}, + {"name": "QUOTA_MONITOR_POLL_COMMIT_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_quota_monitor_poll_commit_request_v0", "modules": ["loopx/control_plane/quota/monitor_poll.py", "loopx/control_plane/quota/monitor_poll_commit.ts"]}, + {"name": "QUOTA_MONITOR_POLL_COMMIT_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_quota_monitor_poll_commit_result_v0", "modules": ["loopx/control_plane/quota/monitor_poll.py", "loopx/control_plane/quota/monitor_poll_commit.ts"]}, + {"name": "QUOTA_SETTLEMENT_READBACK_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_quota_settlement_readback_request_v0", "modules": ["loopx/control_plane/quota/settlement.py", "loopx/control_plane/quota/settlement_readback.ts"]}, + {"name": "QUOTA_SETTLEMENT_READBACK_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_quota_settlement_readback_result_v0", "modules": ["loopx/control_plane/quota/settlement.py", "loopx/control_plane/quota/settlement_readback.ts"]}, + {"name": "QUOTA_SLOT_SPENT_CLASSIFICATION", "is_schema_version": false, "value": "quota_slot_spent", "modules": ["loopx/control_plane/quota/slot_accounting.py", "loopx/control_plane/quota/spend_commit.ts"]}, + {"name": "QUOTA_SLOT_VOIDED_CLASSIFICATION", "is_schema_version": false, "value": "quota_slot_voided", "modules": ["loopx/control_plane/quota/slot_accounting.py", "loopx/control_plane/quota/void_commit.ts"]}, + {"name": "QUOTA_SPEND_COMMIT_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_quota_spend_commit_request_v0", "modules": ["loopx/control_plane/quota/spend_commit.py", "loopx/control_plane/quota/spend_commit.ts"]}, + {"name": "QUOTA_SPEND_COMMIT_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_quota_spend_commit_result_v0", "modules": ["loopx/control_plane/quota/spend_commit.py", "loopx/control_plane/quota/spend_commit.ts"]}, + {"name": "QUOTA_VOID_COMMIT_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_quota_void_commit_request_v0", "modules": ["loopx/control_plane/quota/void_commit.py", "loopx/control_plane/quota/void_commit.ts"]}, + {"name": "QUOTA_VOID_COMMIT_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_quota_void_commit_result_v0", "modules": ["loopx/control_plane/quota/void_commit.py", "loopx/control_plane/quota/void_commit.ts"]}, + {"name": "REFRESH_RECOMMENDATION_REQUEST_SCHEMA_VERSION", "is_schema_version": true, "value": "refresh_recommendation_request_v0", "modules": ["loopx/control_plane/work_items/refresh_recommendation.py", "loopx/control_plane/work_items/refresh_recommendation.ts"]}, + {"name": "REFRESH_RECOMMENDATION_SCHEMA_VERSION", "is_schema_version": true, "value": "refresh_recommendation_v0", "modules": ["loopx/control_plane/work_items/refresh_recommendation.py", "loopx/control_plane/work_items/refresh_recommendation.ts"]}, + {"name": "REPLAN_SETTLEMENT_LIFECYCLE_REENTRY_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_todo_lifecycle_reentry_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "REPLAN_SETTLEMENT_LIFECYCLE_REENTRY_RESULT_SCHEMA", "is_schema_version": false, "value": "todo_lifecycle_settlement_reentry_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "REPLAN_SETTLEMENT_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_replan_settlement_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "REPLAN_SETTLEMENT_RESULT_SCHEMA", "is_schema_version": false, "value": "replan_settlement_contract_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "SCHEDULER_HOST_UPDATE_FAILURE_SCHEMA_VERSION", "is_schema_version": true, "value": "scheduler_host_update_failure_v0", "modules": ["loopx/control_plane/scheduler/state.py", "loopx/control_plane/scheduler/state_store.ts"]}, + {"name": "SCHEDULER_STATE_OPERATION_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_scheduler_state_operation_request_v0", "modules": ["loopx/control_plane/scheduler/state.py", "loopx/control_plane/scheduler/state_store.ts"]}, + {"name": "SCHEDULER_STATE_OPERATION_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_scheduler_state_operation_result_v0", "modules": ["loopx/control_plane/scheduler/state.py", "loopx/control_plane/scheduler/state_store.ts"]}, + {"name": "SCHEDULER_STATE_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_scheduler_state_v0", "modules": ["loopx/control_plane/scheduler/state.py", "loopx/control_plane/scheduler/state_store.ts"]}, + {"name": "SCHEDULER_STATE_STORE_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_scheduler_state_store_request_v0", "modules": ["loopx/control_plane/scheduler/state.py", "loopx/control_plane/scheduler/state_store.ts"]}, + {"name": "SCHEDULER_STATE_STORE_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_scheduler_state_store_result_v0", "modules": ["loopx/control_plane/scheduler/state.py", "loopx/control_plane/scheduler/state_store.ts"]}, + {"name": "SCHEDULER_STATE_TRANSITION_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_scheduler_state_transition_request_v0", "modules": ["loopx/control_plane/scheduler/state_transition_rules.py", "loopx/control_plane/scheduler/state_transition_rules.ts"]}, + {"name": "SCHEDULER_STATE_TRANSITION_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_scheduler_state_transition_result_v0", "modules": ["loopx/control_plane/scheduler/state_transition_rules.py", "loopx/control_plane/scheduler/state_transition_rules.ts"]}, + {"name": "SCOPED_SETTLEMENT_IDENTITY_SCHEMA_VERSION", "is_schema_version": true, "value": "quota_settlement_identity_v1", "modules": ["loopx/control_plane/effect_program.py", "loopx/control_plane/effect_program.ts"]}, + {"name": "SEMANTIC_REPLAN_GUARD_SCHEMA", "is_schema_version": false, "value": "semantic_replan_guard_v0", "modules": ["loopx/control_plane/quota/settlement.py", "loopx/control_plane/quota/settlement_readback.ts"]}, + {"name": "SETTLEMENT_IDENTITY_SCHEMA_VERSION", "is_schema_version": true, "value": "quota_settlement_identity_v0", "modules": ["loopx/control_plane/effect_program.py", "loopx/control_plane/effect_program.ts"]}, + {"name": "SETTLEMENT_PLAN_SCHEMA_VERSION", "is_schema_version": true, "value": "quota_settlement_plan_v1", "modules": ["loopx/control_plane/effect_program.py", "loopx/control_plane/effect_program.ts"]}, + {"name": "SETTLEMENT_RECEIPT_SCHEMA_VERSION", "is_schema_version": true, "value": "quota_settlement_receipt_v1", "modules": ["loopx/control_plane/effect_program.py", "loopx/control_plane/effect_program.ts"]}, + {"name": "SHADOW_CAPTURE_PROFILE", "is_schema_version": false, "value": "file_outbox_v1", "modules": ["loopx/control_plane/coordination/shadow_management.py", "loopx/control_plane/coordination/shadow_management.ts"]}, + {"name": "SHADOW_MANAGEMENT_MANIFEST_SCHEMA", "is_schema_version": false, "value": "loopx_shadow_management_manifest_v1", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "SHADOW_MANAGEMENT_STATE_SCHEMA", "is_schema_version": false, "value": "loopx_shadow_management_state_v1", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "SHADOW_OUTBOX_MANIFEST_SCHEMA", "is_schema_version": false, "value": "loopx_shadow_outbox_manifest_v1", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "SHARED_GOAL_ALIGNMENT_REQUEST_SCHEMA_VERSION", "is_schema_version": true, "value": "shared_goal_alignment_request_v0", "modules": ["loopx/control_plane/goals/shared_goal_alignment.py", "loopx/control_plane/goals/shared_goal_alignment.ts"]}, + {"name": "SHARED_GOAL_ALIGNMENT_SCHEMA_VERSION", "is_schema_version": true, "value": "shared_goal_alignment_v0", "modules": ["loopx/control_plane/goals/shared_goal_alignment.py", "loopx/control_plane/goals/shared_goal_alignment.ts"]}, + {"name": "TASK_LEASE_ACQUIRE_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_task_lease_acquire_native_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "TASK_LEASE_CANONICAL_RENEW_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_canonical_task_lease_renew_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "TASK_LEASE_LIFECYCLE_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_task_lease_lifecycle_native_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "TASK_LEASE_SCHEMA_VERSION", "is_schema_version": true, "value": "task_lease_v0", "modules": ["loopx/control_plane/work_items/local_lease_record.py", "loopx/control_plane/work_items/task_lease_acquire.ts"]}, + {"name": "TODO_COMPLETION_FENCE_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_todo_completion_fence_request_v0", "modules": ["loopx/control_plane/todos/completion_fence.py", "loopx/control_plane/todos/completion_fence.ts"]}, + {"name": "TODO_COMPLETION_FENCE_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_todo_completion_fence_result_v0", "modules": ["loopx/control_plane/todos/completion_fence.py", "loopx/control_plane/todos/completion_fence.ts"]}, + {"name": "TODO_COMPLETION_POLICY_FAILURE_SCHEMA", "is_schema_version": false, "value": "loopx_todo_completion_policy_failure_v0", "modules": ["loopx/control_plane/todos/completion_policy.py", "loopx/control_plane/todos/completion_transaction.ts"]}, + {"name": "TODO_COMPLETION_POLICY_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_todo_completion_policy_request_v0", "modules": ["loopx/control_plane/todos/completion_policy.py", "loopx/control_plane/todos/completion_policy.ts"]}, + {"name": "TODO_COMPLETION_POLICY_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_todo_completion_policy_result_v0", "modules": ["loopx/control_plane/todos/completion_policy.py", "loopx/control_plane/todos/completion_policy.ts"]}, + {"name": "TODO_COMPLETION_STATE_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_todo_completion_state_request_v0", "modules": ["loopx/control_plane/todos/completion_state.py", "loopx/control_plane/todos/completion_state.ts"]}, + {"name": "TODO_COMPLETION_STATE_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_todo_completion_state_result_v0", "modules": ["loopx/control_plane/todos/completion_state.py", "loopx/control_plane/todos/completion_state.ts"]}, + {"name": "TODO_COMPLETION_TRANSACTION_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_todo_completion_transaction_v0", "modules": ["loopx/control_plane/todos/completion_transaction.py", "loopx/control_plane/todos/completion_transaction.ts"]}, + {"name": "TODO_COMPLETION_TRANSACTION_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_todo_completion_transaction_result_v0", "modules": ["loopx/control_plane/todos/completion_transaction.py", "loopx/control_plane/todos/completion_transaction.ts"]}, + {"name": "TODO_DECISION_SCOPE_SCHEMA_VERSION", "is_schema_version": true, "value": "decision_scope_v0", "modules": ["loopx/control_plane/todos/contract.py", "loopx/control_plane/todos/decision_metadata.ts"]}, + {"name": "TODO_NEXT_ACTION_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_todo_next_action_transition_v1", "modules": ["loopx/control_plane/todos/next_action.ts", "loopx/control_plane/todos/next_action_runtime.py"]}, + {"name": "TODO_NEXT_ACTION_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_todo_next_action_result_v0", "modules": ["loopx/control_plane/todos/next_action.ts", "loopx/control_plane/todos/next_action_runtime.py"]}, + {"name": "TODO_PLANNING_INVENTORY_REQUEST_SCHEMA_VERSION", "is_schema_version": true, "value": "todo_planning_inventory_request_v0", "modules": ["loopx/control_plane/work_items/planning_inventory.py", "loopx/control_plane/work_items/planning_inventory.ts"]}, + {"name": "TODO_PRESENTATION_METADATA_SCHEMA", "is_schema_version": false, "value": "loopx_todo_presentation_metadata_v0", "modules": ["loopx/control_plane/coordination/todo_presentation.ts", "loopx/control_plane/todos/todo_semantics.py"]}, + {"name": "TODO_RESUME_EVALUATION_REQUEST_SCHEMA", "is_schema_version": false, "value": "todo_resume_evaluation_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "TODO_RESUME_EVALUATION_RESULT_SCHEMA", "is_schema_version": false, "value": "todo_resume_evaluation_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "TODO_RESUME_EXTERNAL_WAIT_REQUEST_SCHEMA", "is_schema_version": false, "value": "todo_external_wait_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "TODO_RESUME_EXTERNAL_WAIT_RESULT_SCHEMA", "is_schema_version": false, "value": "todo_external_wait_transition_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "TODO_RESUME_NORMALIZE_REQUEST_SCHEMA", "is_schema_version": false, "value": "todo_resume_normalize_request_v0", "modules": ["loopx/control_plane/coordination/coordination_state_contract.generated.ts", "loopx/control_plane/coordination/coordination_state_contract_generated.py"]}, + {"name": "TODO_SUCCESSOR_DERIVATION_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_todo_successor_derivation_request_v0", "modules": ["loopx/control_plane/coordination/todo_successor_derivation.ts", "loopx/control_plane/todos/successor_derivation.py"]}, + {"name": "TODO_SUCCESSOR_DERIVATION_RESULT_SCHEMA", "is_schema_version": false, "value": "loopx_todo_successor_derivation_result_v0", "modules": ["loopx/control_plane/coordination/todo_successor_derivation.ts", "loopx/control_plane/todos/successor_derivation.py"]}, + {"name": "TURN_ENVELOPE_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_turn_envelope_v0", "modules": ["loopx/control_plane/quota/turn_envelope.py", "loopx/control_plane/quota/turn_envelope.ts"]}, + {"name": "TURN_JOURNAL_INSPECTION_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_turn_journal_inspection_v1", "modules": ["loopx/control_plane/turn_driver/turn_journal.ts", "loopx/control_plane/turn_driver/turn_journal_runtime.py"]}, + {"name": "TURN_SETTLEMENT_REDUCTION_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_turn_settlement_reduction_v0", "modules": ["loopx/control_plane/turn_driver/settlement.py", "loopx/control_plane/turn_driver/settlement.ts"]}, + {"name": "TURN_SETTLEMENT_TRANSACTION_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_turn_settlement_transaction_v0", "modules": ["loopx/control_plane/turn_driver/settlement.py", "loopx/control_plane/turn_driver/settlement.ts"]}, + {"name": "VISION_CHECKPOINT_SCHEMA_VERSION", "is_schema_version": true, "value": "vision_checkpoint_v0", "modules": ["loopx/control_plane/goals/vision_checkpoint.py", "loopx/control_plane/goals/vision_checkpoint.ts"]}, + {"name": "VISION_REFRESH_PREPARED_SCHEMA_VERSION", "is_schema_version": true, "value": "vision_refresh_prepared_v0", "modules": ["loopx/control_plane/goals/vision_checkpoint.py", "loopx/control_plane/goals/vision_checkpoint.ts"]}, + {"name": "VISION_REFRESH_REQUEST_SCHEMA", "is_schema_version": false, "value": "loopx_vision_refresh_request_v0", "modules": ["loopx/control_plane/goals/vision_checkpoint.py", "loopx/control_plane/goals/vision_checkpoint.ts"]} + ], + "same_runtime_forks": [ + {"name": "AGENT_LANE_PROGRESS_SCOPE", "is_schema_version": false, "value": "agent_lane", "modules": ["loopx/control_plane/agents/agent_lane_recommendation.py", "loopx/control_plane/status/run_projection.py", "loopx/history.py", "loopx/state_refresh.py", "loopx/status.py"]}, + {"name": "AUTONOMOUS_REPLAN_SCHEMA_VERSION", "is_schema_version": true, "value": "autonomous_replan_obligation_v0", "modules": ["loopx/control_plane/status/autonomous_replan_projection.py", "loopx/status.py"]}, + {"name": "CHAT_CAPABILITIES_PATH", "is_schema_version": false, "value": "/api/chat/capabilities", "modules": ["loopx/chat_server.py", "loopx/dashboard_launcher.py"]}, + {"name": "DEAD_MONITOR_REPEAT_SCHEMA_VERSION", "is_schema_version": true, "value": "dead_monitor_repeat_v0", "modules": ["loopx/control_plane/status/autonomous_replan_projection.py", "loopx/status.py"]}, + {"name": "DELIVERY_INTENT_SCHEMA", "is_schema_version": false, "value": "periodic_report_delivery_intent_v0", "modules": ["loopx/extensions/lark/miaoda_report.py", "loopx/extensions/lark/periodic_report_delivery.py"]}, + {"name": "MONITOR_DISPLAY_FALLBACK_ACTION", "is_schema_version": false, "value": "No immediate agent work; keep the monitor quiet until a material monitor transition, regression, or concrete blocker appears.", "modules": ["loopx/control_plane/status/monitor_display_projection.py", "loopx/status.py"]}, + {"name": "MONITOR_DISPLAY_SCHEMA_VERSION", "is_schema_version": true, "value": "monitor_quiet_display_v0", "modules": ["loopx/control_plane/status/monitor_display_projection.py", "loopx/status.py"]}, + {"name": "MONITOR_DISPLAY_STOP_CONDITION", "is_schema_version": false, "value": "stop until a material monitor transition, regression, or concrete blocker appears", "modules": ["loopx/control_plane/status/monitor_display_projection.py", "loopx/status.py"]}, + {"name": "MONITOR_SIGNAL_WAITING_ON", "is_schema_version": false, "value": "monitor_signal", "modules": ["loopx/control_plane/status/attention_projection.py", "loopx/control_plane/status/goal_attention_projection.py", "loopx/control_plane/status/monitor_display_projection.py", "loopx/status.py"]}, + {"name": "PLANNED_CONTROLLER_OPT_IN_RECOMMENDED_ACTION", "is_schema_version": false, "value": "先在 LoopX 完成 operator 判断;同意后项目 Agent 只执行 read-only map dry-run", "modules": ["loopx/control_plane/status/goal_attention_projection.py", "loopx/status.py"]}, + {"name": "QUALIFIED_NOKV_SDK_VERSION", "is_schema_version": false, "value": "0.11.0", "modules": ["loopx/control_plane/coordination/nokv_jsonl_helper.py", "loopx/control_plane/testing/authority_e2e_ladder.py"]}, + {"name": "RECEIPT_SCHEMA_VERSION", "is_schema_version": true, "value": "loopx_authority_receipt_v0", "modules": ["loopx/control_plane/coordination/executor.py", "loopx/control_plane/coordination/head.py"]}, + {"name": "RESPONSE_SCHEMA", "is_schema_version": false, "value": "semantic_preference_provider_response_v0", "modules": ["loopx/capabilities/semantic_preference/contract.py", "loopx/extensions/openviking_semantic_preference/provider.py"]}, + {"name": "SINK_VISIBILITY_OWNER_ONLY", "is_schema_version": false, "value": "owner-only", "modules": ["loopx/extensions/lark/presentation/explore_results.py", "loopx/extensions/lark/presentation/kanban.py"]}, + {"name": "SINK_VISIBILITY_SHARED", "is_schema_version": false, "value": "shared", "modules": ["loopx/extensions/lark/presentation/explore_results.py", "loopx/extensions/lark/presentation/kanban.py"]}, + {"name": "SKILLS_SUBDIR", "is_schema_version": false, "value": "skills", "modules": ["loopx/agy_goal_mode/__init__.py", "loopx/kiro_cli_goal_mode/__init__.py", "loopx/zcode_goal_mode/__init__.py"]}, + {"name": "SNAPSHOT_SCHEMA_VERSION", "is_schema_version": true, "value": "issue_fix_repository_reporting_snapshot_v0", "modules": ["loopx/capabilities/issue_fix/metrics_projection.py", "loopx/capabilities/issue_fix/repository_snapshot.py"]}, + {"name": "STATE_EVENT_LOG_BASENAME", "is_schema_version": false, "value": "events.jsonl", "modules": ["loopx/control_plane/status/active_state_projection.py", "loopx/status.py"]}, + {"name": "STATUS_CONTRACT_RELOAD_HINT", "is_schema_version": false, "value": "scripts/macos-dashboard-launchagent.sh restart", "modules": ["loopx/control_plane/status/contract_projection.py", "loopx/status.py"]}, + {"name": "SUPPLEMENT_SCHEMA_VERSION", "is_schema_version": true, "value": "issue_fix_metrics_supplement_v0", "modules": ["loopx/capabilities/issue_fix/metrics_projection.py", "loopx/capabilities/issue_fix/metrics_supplement.py"]}, + {"name": "TODO_ARCHIVE_STATE_ACTIVE", "is_schema_version": false, "value": "active", "modules": ["loopx/control_plane/todos/handoff_gate.py", "loopx/control_plane/todos/todo_summary.py"]}, + {"name": "TODO_TASK_CLASS_ADVANCEMENT", "is_schema_version": false, "value": "advancement_task", "modules": ["loopx/control_plane/goals/goal_frontier/__init__.py", "loopx/control_plane/goals/goal_frontier/long_todo_chain.py", "loopx/control_plane/todos/contract.py", "loopx/control_plane/todos/frontier_revision.py"]}, + {"name": "TODO_TASK_CLASS_MONITOR", "is_schema_version": false, "value": "continuous_monitor", "modules": ["loopx/control_plane/goals/goal_frontier/__init__.py", "loopx/control_plane/todos/contract.py"]}, + {"name": "TRIGGER_DECISION_SCHEMA", "is_schema_version": false, "value": "periodic_report_trigger_decision_v0", "modules": ["loopx/capabilities/periodic_report/core.py", "loopx/capabilities/periodic_report/triggers.py"]}, + {"name": "WORK_LANE_CONTRACT_SCHEMA_VERSION", "is_schema_version": true, "value": "work_lane_contract_v1", "modules": ["loopx/control_plane/work_items/capability_monitor_fallback.py", "loopx/control_plane/work_items/work_lane.py"]} + ], + "conflicting_values": [ + {"name": "BINDING_SCHEMA_VERSION", "is_schema_version": true, "definitions": [{"module": "loopx/control_plane/operator_inbox_binding.py", "value": "operator_inbox_binding_v0"}, {"module": "loopx/kunluncode_goal_mode/context.py", "value": "loopx_kunluncode_binding_v0"}]}, + {"name": "CAPABILITY_ID", "is_schema_version": false, "definitions": [{"module": "loopx/capabilities/periodic_report/pending_intent.py", "value": "periodic-report"}, {"module": "loopx/capabilities/reliability_diagnostics/envelope.py", "value": "reliability-diagnostics"}, {"module": "loopx/capabilities/repository_change_window/interaction_hook.py", "value": "repository-change-window"}]}, + {"name": "COMMAND", "is_schema_version": false, "definitions": [{"module": "loopx/capabilities/deep_research/runtime.py", "value": "/loopx-deepresearch"}, {"module": "loopx/global_risks.py", "value": "/loopx-global-risks"}, {"module": "loopx/global_todos.py", "value": "/loopx-global-todos"}, {"module": "loopx/pr_review.py", "value": "/loopx-pr-review"}, {"module": "loopx/summary_all.py", "value": "/loopx-global-summary"}]}, + {"name": "CONFIG_SCHEMA_VERSION", "is_schema_version": true, "definitions": [{"module": "loopx/extensions/lark/event_collector.py", "value": "lark_event_collector_config_v1"}, {"module": "loopx/extensions/lark/event_inbox.py", "value": "lark_event_inbox_config_v0"}]}, + {"name": "CURSOR_SCHEMA_VERSION", "is_schema_version": true, "definitions": [{"module": "loopx/extensions/lark/group_history_cursor.py", "value": "lark_group_history_cursor_v1"}, {"module": "loopx/extensions/lark/turn_start_sync.py", "value": "lark_turn_start_sync_cursor_v0"}]}, + {"name": "DECISION_CONTEXT_CAPABILITY_ID", "is_schema_version": false, "definitions": [{"module": "loopx/capabilities/decision_context/extension_provider.py", "value": "decision-context"}, {"module": "loopx/capabilities/decision_context/packets.py", "value": "decision_context"}]}, + {"name": "DEFAULT_AGENT_ID", "is_schema_version": false, "definitions": [{"module": "loopx/extensions/lark/presentation/kanban.py", "value": "codex-kanban-worker"}, {"module": "loopx/kunluncode_goal_mode/__init__.py", "value": "kunlun"}]}, + {"name": "EVENT_SCHEMA_VERSION", "is_schema_version": true, "definitions": [{"module": "loopx/capabilities/repository_change_window/ledger.py", "value": "repository_pending_change_event_v0"}, {"module": "loopx/extensions/external_connector_runtime.py", "value": "agent_external_connector_event_v0"}, {"module": "loopx/extensions/lark/event_inbox.py", "value": "lark_event_inbox_event_v0"}]}, + {"name": "HOOK_ID", "is_schema_version": false, "definitions": [{"module": "loopx/capabilities/periodic_report/pending_intent.py", "value": "periodic_report.pending_intent"}, {"module": "loopx/capabilities/repository_change_window/interaction_hook.py", "value": "repository_change_window.repository_delivery"}]}, + {"name": "MCP_REQUIREMENT", "is_schema_version": false, "definitions": [{"module": "loopx/claude_goal_mode/scripts/install.py", "value": "mcp<2"}, {"module": "loopx/kunluncode_goal_mode/cli.py", "value": "mcp==1.28.1"}]}, + {"name": "PLAN_SCHEMA_VERSION", "is_schema_version": true, "definitions": [{"module": "loopx/capabilities/integration_branch/core.py", "value": "loopx_integration_branch_plan_v0"}, {"module": "loopx/extensions/lark/event_collector.py", "value": "lark_event_collector_plan_v0"}]}, + {"name": "PROJECTION_SCHEMA_VERSION", "is_schema_version": true, "definitions": [{"module": "loopx/capabilities/issue_fix/metrics_projection.py", "value": "issue_fix_metrics_projection_v0"}, {"module": "loopx/capabilities/issue_fix/metrics_supplement.py", "value": "issue_fix_metrics_supplement_projection_v0"}]}, + {"name": "REQUEST_SCHEMA", "is_schema_version": false, "definitions": [{"module": "loopx/capabilities/periodic_report/core.py", "value": "periodic_report_run_request_v0"}, {"module": "loopx/capabilities/semantic_preference/contract.py", "value": "semantic_preference_provider_request_v0"}, {"module": "loopx/control_plane/handoff/review_batch.py", "value": "review_batch_request_v0"}, {"module": "loopx/extensions/openviking_periodic_report/provider.py", "value": "openviking_periodic_report_archive_request_v0"}, {"module": "loopx/extensions/openviking_semantic_preference/provider.py", "value": "semantic_preference_provider_request_v0"}]}, + {"name": "SCHEMA_VERSION", "is_schema_version": true, "definitions": [{"module": "loopx/agent_onboarding.py", "value": "loopx_agent_onboarding_v0"}, {"module": "loopx/bootstrap_command_pack.py", "value": "loopx_bootstrap_command_pack_v0"}, {"module": "loopx/capabilities/explore/source_history_reconcile.py", "value": "loopx_explore_source_history_reconcile_v0"}, {"module": "loopx/capabilities/pr_review_queue/merge_readiness.py", "value": "pull_request_merge_readiness_v0"}, {"module": "loopx/capabilities/public_safe_outbound/scanner.py", "value": "public_safe_outbound_scan_v0"}, {"module": "loopx/control_plane/runtime/agent_scoped_evidence_log.py", "value": "agent_scoped_evidence_log_v0"}, {"module": "loopx/extensions/lark/manager_reply_delivery.py", "value": "lark_manager_reply_delivery_v0"}, {"module": "loopx/global_risks.py", "value": "global_manager_command_response_v0"}, {"module": "loopx/global_todos.py", "value": "global_manager_command_response_v0"}, {"module": "loopx/host_loop_activation.py", "value": "loopx_host_loop_activation_v1"}, {"module": "loopx/host_mode_planner.py", "value": "host_mode_plan_v0"}, {"module": "loopx/pr_review.py", "value": "loopx_pr_review_command_response_v0"}, {"module": "loopx/presentation/projection_source_reconcile.py", "value": "projection_source_reconcile_plan_v0"}, {"module": "loopx/slash_command_install.py", "value": "loopx_slash_command_install_v0"}, {"module": "loopx/slash_commands.py", "value": "loopx_slash_command_catalog_v0"}, {"module": "loopx/summary_all.py", "value": "global_manager_command_response_v0"}]}, + {"name": "SKILLS_ROOT_LABEL", "is_schema_version": false, "definitions": [{"module": "loopx/agy_goal_mode/__init__.py", "value": "~/.gemini/antigravity-cli/skills"}, {"module": "loopx/kiro_cli_goal_mode/__init__.py", "value": "KIRO_HOME/skills"}, {"module": "loopx/zcode_goal_mode/__init__.py", "value": "ZCODE_HOME/skills"}]}, + {"name": "STATUS_SCHEMA_VERSION", "is_schema_version": true, "definitions": [{"module": "loopx/capabilities/integration_branch/core.py", "value": "loopx_integration_branch_status_v0"}, {"module": "loopx/extensions/lark/event_collector.py", "value": "lark_event_collector_status_v0"}]}, + {"name": "SURFACE", "is_schema_version": false, "definitions": [{"module": "loopx/capabilities/issue_fix/pr_description.py", "value": "issue_fix.pr_description"}, {"module": "loopx/capabilities/reward_memory/outbound.py", "value": "outbound_message.before_send"}]}, + {"name": "SYNC_SCHEMA_VERSION", "is_schema_version": true, "definitions": [{"module": "loopx/capabilities/integration_branch/core.py", "value": "loopx_integration_branch_sync_v0"}, {"module": "loopx/extensions/lark/turn_start_sync.py", "value": "lark_turn_start_inbox_sync_v0"}]} + ], + "multi_value_twins": [ + {"name": "AUTONOMOUS_RUN_HISTORY_NEUTRAL_CLASSIFICATIONS", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/status/autonomous_replan_projection.py", "values": ["quota_slot_spent", "quota_slot_voided", "delivery_completion_spend_accounted_v0"]}, {"kind": "python_closed_set", "module": "loopx/status.py", "values": ["quota_slot_spent", "quota_slot_voided", "delivery_completion_spend_accounted_v0"]}], "values": ["quota_slot_spent", "quota_slot_voided", "delivery_completion_spend_accounted_v0"], "modules": ["loopx/control_plane/status/autonomous_replan_projection.py", "loopx/status.py"]}, + {"name": "BACKLOG_HYGIENE_SECTION_HEADINGS", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/status/active_state_projection.py", "values": ["Next Action", "Operating Lessons"]}, {"kind": "python_closed_set", "module": "loopx/status.py", "values": ["Next Action", "Operating Lessons"]}], "values": ["Next Action", "Operating Lessons"], "modules": ["loopx/control_plane/status/active_state_projection.py", "loopx/status.py"]}, + {"name": "BRANCH_REPLAN_MERGE_STATES", "definitions": [{"kind": "python_closed_set", "module": "loopx/capabilities/issue_fix/outcome_projection.py", "values": ["BEHIND", "DIRTY"]}, {"kind": "python_closed_set", "module": "loopx/capabilities/issue_fix/pr_lifecycle.py", "values": ["BEHIND", "DIRTY"]}], "values": ["BEHIND", "DIRTY"], "modules": ["loopx/capabilities/issue_fix/outcome_projection.py", "loopx/capabilities/issue_fix/pr_lifecycle.py"]}, + {"name": "CAPTURE_SCOPES", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/work_items/operator_inbox.py", "values": ["addressed_only", "configured_chat_all"]}, {"kind": "python_closed_set", "module": "loopx/extensions/lark/event_inbox.py", "values": ["addressed_only", "configured_chat_all"]}], "values": ["addressed_only", "configured_chat_all"], "modules": ["loopx/control_plane/work_items/operator_inbox.py", "loopx/extensions/lark/event_inbox.py"]}, + {"name": "CONNECTED_ADAPTER_STATUSES", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/status/goal_attention_projection.py", "values": ["connected", "connected-read-only", "pre-tick-runnable"]}, {"kind": "python_closed_set", "module": "loopx/control_plane/status/lifecycle_projection.py", "values": ["connected", "connected-read-only", "pre-tick-runnable"]}, {"kind": "python_closed_set", "module": "loopx/status.py", "values": ["connected", "connected-read-only", "pre-tick-runnable"]}], "values": ["connected", "connected-read-only", "pre-tick-runnable"], "modules": ["loopx/control_plane/status/goal_attention_projection.py", "loopx/control_plane/status/lifecycle_projection.py", "loopx/status.py"]}, + {"name": "DELIVERY_CONTINUITY_PREEMPTIONS", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/turn_driver/delivery_continuity.py", "values": ["heartbeat_receipt", "blocking_work_lane", "autonomous_replan", "control_repair", "delivery_not_allowed"]}, {"kind": "typescript_const_array", "module": "loopx/control_plane/turn_driver/delivery_continuity.ts", "values": ["heartbeat_receipt", "blocking_work_lane", "autonomous_replan", "control_repair", "delivery_not_allowed"]}], "values": ["heartbeat_receipt", "blocking_work_lane", "autonomous_replan", "control_repair", "delivery_not_allowed"], "modules": ["loopx/control_plane/turn_driver/delivery_continuity.py", "loopx/control_plane/turn_driver/delivery_continuity.ts"]}, + {"name": "DELIVERY_WORKSPACE_IDENTITY_KINDS", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/agents/delivery_workspace.py", "values": ["git_repository", "local_goal"]}, {"kind": "typescript_const_array", "module": "loopx/control_plane/agents/delivery_workspace.ts", "values": ["git_repository", "local_goal"]}], "values": ["git_repository", "local_goal"], "modules": ["loopx/control_plane/agents/delivery_workspace.py", "loopx/control_plane/agents/delivery_workspace.ts"]}, + {"name": "DELIVERY_WORKSPACE_KINDS", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/agents/delivery_workspace.py", "values": ["canonical_checkout", "independent_git_worktree", "local_goal_workspace"]}, {"kind": "typescript_const_array", "module": "loopx/control_plane/agents/delivery_workspace.ts", "values": ["canonical_checkout", "independent_git_worktree", "local_goal_workspace"]}], "values": ["canonical_checkout", "independent_git_worktree", "local_goal_workspace"], "modules": ["loopx/control_plane/agents/delivery_workspace.py", "loopx/control_plane/agents/delivery_workspace.ts"]}, + {"name": "DELIVERY_WORKSPACE_REQUIREMENTS", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/quota/settlement_workspace_causality.py", "values": ["required", "not_required", "unknown"]}, {"kind": "typescript_const_array", "module": "loopx/control_plane/quota/settlement_workspace_causality.ts", "values": ["required", "not_required", "unknown"]}], "values": ["required", "not_required", "unknown"], "modules": ["loopx/control_plane/quota/settlement_workspace_causality.py", "loopx/control_plane/quota/settlement_workspace_causality.ts"]}, + {"name": "GOAL_AMENDMENT_CLASSES", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/goals/goal_amendment_proposal.py", "values": ["lane_route", "shared_work_graph", "shared_acceptance", "protected_authority"]}, {"kind": "typescript_const_array", "module": "loopx/control_plane/goals/goal_amendment_proposal.ts", "values": ["lane_route", "shared_work_graph", "shared_acceptance", "protected_authority"]}], "values": ["lane_route", "shared_work_graph", "shared_acceptance", "protected_authority"], "modules": ["loopx/control_plane/goals/goal_amendment_proposal.py", "loopx/control_plane/goals/goal_amendment_proposal.ts"]}, + {"name": "GOAL_AMENDMENT_PROPOSAL_ADMISSIONS", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/goals/goal_amendment_proposal.py", "values": ["admitted", "needs_rebase"]}, {"kind": "typescript_const_array", "module": "loopx/control_plane/goals/goal_amendment_proposal.ts", "values": ["admitted", "needs_rebase"]}], "values": ["admitted", "needs_rebase"], "modules": ["loopx/control_plane/goals/goal_amendment_proposal.py", "loopx/control_plane/goals/goal_amendment_proposal.ts"]}, + {"name": "GOAL_AMENDMENT_PROPOSAL_ADMISSION_FACTS", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/goals/goal_amendment_proposal.py", "values": ["base_state_event_basis_sequence_behind_derived_head", "base_source_basis_digest_mismatch", "base_source_basis_unverifiable", "base_revision_basis_superseded"]}, {"kind": "typescript_const_array", "module": "loopx/control_plane/goals/goal_amendment_proposal.ts", "values": ["base_state_event_basis_sequence_behind_derived_head", "base_source_basis_digest_mismatch", "base_source_basis_unverifiable", "base_revision_basis_superseded"]}], "values": ["base_state_event_basis_sequence_behind_derived_head", "base_source_basis_digest_mismatch", "base_source_basis_unverifiable", "base_revision_basis_superseded"], "modules": ["loopx/control_plane/goals/goal_amendment_proposal.py", "loopx/control_plane/goals/goal_amendment_proposal.ts"]}, + {"name": "LEGACY_EXTERNAL_EVIDENCE_CLASSIFICATION_PREFIXES", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/status/goal_attention_projection.py", "values": ["await_", "external_evidence_observation_"]}, {"kind": "python_closed_set", "module": "loopx/status.py", "values": ["await_", "external_evidence_observation_"]}], "values": ["await_", "external_evidence_observation_"], "modules": ["loopx/control_plane/status/goal_attention_projection.py", "loopx/status.py"]}, + {"name": "LIFECYCLE_PRIORITY", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/status/lifecycle_projection.py", "values": ["controller_ready", "reward_judged", "operator_approved", "controller_gated", "operator_gated", "adapter_inspected", "mapped", "refreshed", "connected", "registered", "planned", "run_recorded"]}, {"kind": "python_closed_set", "module": "loopx/status.py", "values": ["controller_ready", "reward_judged", "operator_approved", "controller_gated", "operator_gated", "adapter_inspected", "mapped", "refreshed", "connected", "registered", "planned", "run_recorded"]}], "values": ["controller_ready", "reward_judged", "operator_approved", "controller_gated", "operator_gated", "adapter_inspected", "mapped", "refreshed", "connected", "registered", "planned", "run_recorded"], "modules": ["loopx/control_plane/status/lifecycle_projection.py", "loopx/status.py"]}, + {"name": "REGISTRY_DIRS", "definitions": [{"kind": "python_closed_set", "module": "loopx/claude_goal_mode/hooks/goal_state.py", "values": [".loopx", ".goal-harness"]}, {"kind": "python_closed_set", "module": "loopx/goal_mode_context.py", "values": [".loopx", ".goal-harness"]}], "values": [".loopx", ".goal-harness"], "modules": ["loopx/claude_goal_mode/hooks/goal_state.py", "loopx/goal_mode_context.py"]}, + {"name": "REGISTRY_WAITING_ON_OVERRIDES", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/status/goal_attention_projection.py", "values": ["user_or_controller", "controller", "codex", "external_evidence"]}, {"kind": "python_closed_set", "module": "loopx/status.py", "values": ["user_or_controller", "controller", "codex", "external_evidence"]}], "values": ["user_or_controller", "controller", "codex", "external_evidence"], "modules": ["loopx/control_plane/status/goal_attention_projection.py", "loopx/status.py"]}, + {"name": "SOURCE_REGISTRY_SHADOW_FINDINGS", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/status/registry_health_projection.py", "values": ["source_registry_missing", "stale_source_registry"]}, {"kind": "python_closed_set", "module": "loopx/status.py", "values": ["source_registry_missing", "stale_source_registry"]}], "values": ["source_registry_missing", "stale_source_registry"], "modules": ["loopx/control_plane/status/registry_health_projection.py", "loopx/status.py"]}, + {"name": "SUPPORT_ASPECTS", "definitions": [{"kind": "python_closed_set", "module": "loopx/capabilities/issue_fix/repository_context.py", "values": ["architecture", "ownership", "change_scope", "reproduction", "validation"]}, {"kind": "python_closed_set", "module": "loopx/capabilities/issue_fix/repository_memory.py", "values": ["architecture", "ownership", "change_scope", "reproduction", "validation"]}], "values": ["architecture", "ownership", "change_scope", "reproduction", "validation"], "modules": ["loopx/capabilities/issue_fix/repository_context.py", "loopx/capabilities/issue_fix/repository_memory.py"]}, + {"name": "TERMINAL_PR_STATES", "definitions": [{"kind": "python_closed_set", "module": "loopx/capabilities/issue_fix/pr_gate_reconcile.py", "values": ["MERGED", "CLOSED"]}, {"kind": "python_closed_set", "module": "loopx/capabilities/issue_fix/pr_lifecycle.py", "values": ["MERGED", "CLOSED"]}], "values": ["MERGED", "CLOSED"], "modules": ["loopx/capabilities/issue_fix/pr_gate_reconcile.py", "loopx/capabilities/issue_fix/pr_lifecycle.py"]} + ], + "multi_value_forks": [ + {"name": "AGENT_TODO_HEADER_MARKERS", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/goals/active_state_metadata.py", "values": ["agent todo", "codex todo", "project agent todo"]}, {"kind": "python_closed_set", "module": "loopx/state_projection.py", "values": ["agent todo", "agent backlog", "agent action", "项目 agent", "agent 待办"]}]}, + {"name": "RAW_MATERIAL_KEY_HINTS", "definitions": [{"kind": "python_closed_set", "module": "loopx/capabilities/content_ops/surface.py", "values": ["body", "chat", "credential", "dm", "local_path", "log", "message", "raw", "secret", "token", "transcript"]}, {"kind": "python_closed_set", "module": "loopx/control_plane/goals/goal_channel_projection.py", "values": ["credential", "local_path", "log", "raw", "secret", "stderr", "stdout", "token", "trace", "transcript"]}]}, + {"name": "SOURCE_SURFACES", "definitions": [{"kind": "python_closed_set", "module": "loopx/global_risks.py", "values": ["status contract diagnostics", "global registry health findings", "status attention queue stale-run warnings", "status compact run-history coordination"]}, {"kind": "python_closed_set", "module": "loopx/global_todos.py", "values": ["status attention queue", "quota should-run summaries", "active-state todo projections", "compact run-history projection consumed by status"]}, {"kind": "python_closed_set", "module": "loopx/pr_review.py", "values": ["GitHub pull request metadata", "GitHub pull request body summary", "GitHub pull request changed-file list", "GitHub pull request status check rollup"]}, {"kind": "python_closed_set", "module": "loopx/summary_all.py", "values": ["global registry compact status", "status attention queue", "quota should-run summaries", "active-state todo projections", "run history index summaries"]}]}, + {"name": "USER_TODO_HEADER_MARKERS", "definitions": [{"kind": "python_closed_set", "module": "loopx/control_plane/goals/active_state_metadata.py", "values": ["user todo", "owner review reading queue", "owner reading queue"]}, {"kind": "python_closed_set", "module": "loopx/state_projection.py", "values": ["user todo", "owner review", "owner todo", "user action", "用户", "人工", "owner"]}]} + ] + }, + "summary": { + "source_files": 1174, + "python_enums": 103, + "python_closed_sets": 495, + "python_literal_aliases": 8, + "typescript_const_arrays": 40, + "named_string_constants": 2030, + "schema_version_names": 756, + "schema_version_same_runtime_forks": 7, + "cross_runtime_twins": 166, + "same_runtime_forks": 25, + "same_runtime_fork_definitions": 58, + "conflicting_values": 18, + "conflicting_definitions": 59, + "multi_value_twins": 19, + "multi_value_forks": 4, + "multi_value_fork_definitions": 10, + "same_runtime_forks_semantic": 18, + "conflicting_values_semantic": 2 + } +} diff --git a/loopx/semantics/vocabulary_v0.json b/loopx/semantics/vocabulary_v0.json new file mode 100644 index 0000000000..f571a16438 --- /dev/null +++ b/loopx/semantics/vocabulary_v0.json @@ -0,0 +1,670 @@ +{ + "schema_version": "loopx_semantic_vocabulary_v0", + "rfc": "docs/architecture/rfcs/semantic-vocabulary-convergence-v0.md", + "inventory": "loopx/semantics/inventory_v0.json", + "policy": { + "scope": "Repository-wide. The curated vocabularies below are the kernel and cross-runtime sets; the generated inventory maps every other closed-set carrier under loopx/ so additions are visible in a diff.", + "closed_sets": "Every value a registered vocabulary may carry is listed here. Adding, renaming, or removing a value is a registry edit reviewed with the code change; an unregistered literal fails the drift smoke.", + "owner_exclusivity": "A registered symbol is defined only in its listed owner modules. Any other module imports it instead of redefining the literal. An owner is always module::Symbol or null; a null owner requires a literal_scan.", + "budgets_only_decrease": "Retirement, twin, and inventory-ratchet budgets only fall. Lowering a budget is a routine edit; raising one needs the maintainer approval recorded in the RFC decision log. Each budget must equal its BUDGET_ANCHOR or RETIREMENT_ANCHOR literal in the drift smoke, so tightening edits the JSON and the code literal in one diff, and a later diff cannot raise the JSON back toward a stale anchor.", + "coverage_only_grows": "coverage_floor counts only rise. Removing a vocabulary, owner, projection, relation, or scan suffix must lower the floor in the same diff, which is a schema reduction under AGENTS.md. Each floor must equal its COVERAGE_ANCHOR literal in the drift smoke, so growing coverage edits the JSON and the code literal in one diff, and the floor cannot be lowered in the same diff that removes the coverage it counts.", + "value_shape": "Registered values are lower snake_case tokens (^[a-z][a-z0-9_]*$). The literal scan captures any quoted string so a malformed or versioned spelling is reported, not skipped.", + "literal_scan_forms": "The dispatch forms the scan recognises are fixed in the smoke, not in this file: comparison or assignment against a literal (== != === !== : = is), a JS/TS ternary, membership in an inline collection, and a Python conditional expression." + }, + "coverage_floor": { + "vocabularies": 26, + "owner_symbols": 46, + "literal_scan_fields": 1, + "projections": 1, + "relations": 9, + "schema_versions": 1, + "literal_scan_suffixes": [ + ".py", + ".ts" + ] + }, + "vocabularies": { + "turn_result_kind": { + "meaning": "Typed public outcome of one executed Turn as settled by the Turn Journal.", + "tier": "kernel", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/turn_driver/transaction.py::LoopXTurnResultKind", + "typescript": "loopx/control_plane/turn_driver/settlement.ts::TURN_RESULT_KINDS" + }, + "values": [ + "validated_progress", + "validated_completion", + "repair_required", + "replan_required", + "user_action_required", + "wait", + "iteration_failed", + "host_failure", + "validation_failed", + "writeback_failed", + "quota_spend_failed", + "terminal_closeout_failed" + ], + "value_notes": { + "host_failure": "Routed by the controller protocol as a retryable or legacy failure class; retention is decided in RFC Section 12.", + "validation_failed": "Legacy failure class per turn-loop-controller-v0; always routes to repair.", + "writeback_failed": "Legacy failure class per turn-loop-controller-v0; always routes to repair.", + "quota_spend_failed": "Legacy failure class per turn-loop-controller-v0; always routes to repair." + } + }, + "turn_route": { + "meaning": "Typed delivery route derived from a fresh should-run decision before a Host is engaged.", + "tier": "kernel", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/turn_driver/driver.py::LoopXTurnRoute", + "typescript": null + }, + "values": [ + "ready_for_host", + "capability_action_required", + "repair_required", + "replan_required", + "user_action_required", + "wait", + "blocked", + "contract_error" + ] + }, + "loop_disposition": { + "meaning": "Pure controller verdict for the outer loop after combining the last Turn receipt with the fresh route.", + "tier": "kernel", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/turn_driver/loop_controller.py::LoopDisposition", + "typescript": null + }, + "values": [ + "run_now", + "capability_action_required", + "wait", + "stop", + "user_action_required", + "repair", + "replan", + "terminal" + ] + }, + "agent_scope_frontier_action": { + "meaning": "Frontier verdict for an agent-scoped lane; its value is written into the agent_scope_frontier.effective_action slot of the Turn Envelope.", + "tier": "kernel", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/agents/agent_scope_frontier.py::AgentScopeFrontierAction", + "typescript": null + }, + "values": [ + "agent_scope_exhausted", + "agent_scope_wait", + "reassignment_required", + "successor_replan_required" + ] + }, + "lease_action": { + "meaning": "Authority-core lease mutation verb.", + "tier": "kernel", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/coordination/authority_core.py::LeaseAction", + "typescript": null + }, + "values": [ + "acquire", + "renew", + "transfer", + "release" + ] + }, + "effective_action": { + "meaning": "Compacted should-run verdict carried by status/should-run payloads and the Turn Envelope; consumers dispatch on it by string comparison. No enum exists on either runtime, so the owner is null and the literal scan is the only check.", + "tier": "kernel", + "status": "merge_candidate", + "owners": { + "python": null, + "typescript": null + }, + "literal_scan": { + "field": "effective_action", + "roots": [ + "loopx" + ], + "suffixes": [ + ".py", + ".ts" + ] + }, + "values": [ + "agent_monitor_only", + "agent_workspace_repair", + "automation_prompt_upgrade_required", + "autonomous_replan_required", + "block_replay", + "boundary_projection_repair", + "capability_bridge_repair", + "control_plane_health_repair", + "control_plane_projection_repair", + "coordinate_task_bundle", + "external_evidence_observe", + "governed_capability_intent", + "heartbeat_receipt_write_failed", + "heartbeat_settled_skip", + "lark_inbox_reply_due", + "monitor_due", + "monitor_quiet_skip", + "normal_run", + "observe_replay", + "operator_gate", + "operator_inbox_material_review_due", + "outcome_floor_recovery", + "peer_coordination_blocked", + "quota_action_selection_deferred", + "quota_action_selection_rejected", + "quota_skip", + "runtime_user_gate_projection_repair", + "scoped_user_gate_fallback", + "skip", + "state_projection_gap_repair", + "terminal_no_followup", + "todo_decision_scope_projection_repair", + "unsettled_host_turn_recovery" + ], + "variable_sourced_values": { + "quota_action_selection_deferred": "loopx/cli_commands/quota.py", + "quota_action_selection_rejected": "loopx/cli_commands/quota.py" + }, + "value_notes": { + "skip": "Compared in loopx/control_plane/todos/user_gate.py; no producer writes it into effective_action. Candidate dead value (decision-level skip lives in the decision field).", + "observe_replay": "Written only by turn_journal.ts into the replay observation slot; not a should-run verdict. Slot split is RFC Section 12 Q6.", + "block_replay": "Written only by turn_journal.ts into the replay observation slot; not a should-run verdict. Slot split is RFC Section 12 Q6.", + "quota_action_selection_deferred": "Reaches the slot through the error_code variable in cli_commands/quota.py; an error code doubling as a verdict.", + "quota_action_selection_rejected": "Reaches the slot through the error_code variable in cli_commands/quota.py; an error code doubling as a verdict." + } + }, + "settlement_step_kind": { + "meaning": "Effect-program settlement step executed for one Turn.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/effect_program.py::SettlementStepKind", + "typescript": "loopx/control_plane/effect_program.ts::SETTLEMENT_STEP_KINDS" + }, + "values": [ + "validation", + "durable_writeback", + "quota_spend", + "terminal_closeout" + ] + }, + "settlement_binding_kind": { + "meaning": "How a settlement step binds to its receipt.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/effect_program.py::SettlementBindingKind", + "typescript": "loopx/control_plane/effect_program.ts::SETTLEMENT_BINDING_KINDS" + }, + "values": [ + "todo", + "autonomous_replan", + "unbound" + ] + }, + "settlement_failure_kind": { + "meaning": "Typed failure class of a settlement step.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/effect_program.py::SettlementFailureKind", + "typescript": "loopx/control_plane/effect_program.ts::SETTLEMENT_FAILURE_KINDS" + }, + "values": [ + "invalid_identity", + "receipt_missing", + "identity_mismatch", + "writeback_missing", + "writeback_rejected", + "quota_spend_rejected", + "terminal_closeout_rejected", + "cancelled", + "permission_denied", + "budget_rejected", + "effect_outcome_unknown" + ] + }, + "receipt_bound_monitor_phase": { + "meaning": "Receipt-bound phase of a monitor poll settlement.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/effect_program.py::ReceiptBoundMonitorPhase", + "typescript": "loopx/control_plane/quota/settlement_phase.ts::RECEIPT_BOUND_MONITOR_PHASES" + }, + "values": [ + "poll_due", + "settlement_pending", + "settled" + ] + }, + "receipt_bound_replay_phase": { + "meaning": "Receipt-bound phase of a Turn journal replay settlement.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/effect_program.py::ReceiptBoundReplayPhase", + "typescript": "loopx/control_plane/quota/settlement_phase.ts::RECEIPT_BOUND_REPLAY_PHASES" + }, + "values": [ + "open", + "settlement_pending", + "settled" + ] + }, + "handoff_mode": { + "meaning": "Authority handoff mode between agents.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/coordination/authority_core.py::HandoffMode", + "typescript": "loopx/control_plane/coordination/handoff_mode_policy.ts::HANDOFF_MODES" + }, + "values": [ + "legacy", + "soft_claim", + "hard_lease" + ] + }, + "scheduler_cadence_transition": { + "meaning": "Legal scheduler cadence state transition.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/scheduler/state_transition_rules.py::SchedulerCadenceTransition", + "typescript": "loopx/control_plane/scheduler/state_transition_rules.ts::SCHEDULER_CADENCE_TRANSITIONS" + }, + "values": [ + "initial", + "identity_reset", + "retry_unacknowledged_failure", + "hold_active_initial", + "advance_after_interval", + "hold_until_interval" + ] + }, + "scheduler_host_transition": { + "meaning": "Legal scheduler host state transition.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/scheduler/state_transition_rules.py::SchedulerHostTransition", + "typescript": "loopx/control_plane/scheduler/state_transition_rules.ts::SCHEDULER_HOST_TRANSITIONS" + }, + "values": [ + "apply_required", + "host_match_ack_required", + "recorded_failure_suppressed", + "settled" + ] + }, + "todo_completion_continuation": { + "meaning": "Continuation declared by a completing Todo.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/todos/completion_state.py::TodoCompletionContinuation", + "typescript": "loopx/control_plane/todos/completion_state.ts::TODO_COMPLETION_CONTINUATIONS" + }, + "values": [ + "active_goal", + "successor", + "no_followup" + ] + }, + "todo_completion_recovery": { + "meaning": "Recovery path when a Todo completion cannot continue.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/todos/completion_state.py::TodoCompletionRecovery", + "typescript": "loopx/control_plane/todos/completion_state.ts::TODO_COMPLETION_RECOVERIES" + }, + "values": [ + "same_turn_terminal_closeout", + "lifecycle_reentry_terminal_closeout" + ] + }, + "delivery_outcome": { + "meaning": "Outcome class of a delivered work item.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/work_items/delivery_outcome.py::DeliveryOutcome", + "typescript": "loopx/control_plane/work_items/delivery_outcome.ts::DELIVERY_OUTCOMES" + }, + "values": [ + "surface_only", + "outcome_gap", + "outcome_progress", + "primary_goal_outcome" + ] + }, + "delivery_workspace_kind": { + "meaning": "Workspace kind a delivery runs in.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/agents/delivery_workspace.py::DELIVERY_WORKSPACE_KINDS", + "typescript": "loopx/control_plane/agents/delivery_workspace.ts::DELIVERY_WORKSPACE_KINDS" + }, + "values": [ + "canonical_checkout", + "independent_git_worktree", + "local_goal_workspace" + ] + }, + "delivery_workspace_identity_kind": { + "meaning": "How a delivery workspace is identified.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/agents/delivery_workspace.py::DELIVERY_WORKSPACE_IDENTITY_KINDS", + "typescript": "loopx/control_plane/agents/delivery_workspace.ts::DELIVERY_WORKSPACE_IDENTITY_KINDS" + }, + "values": [ + "git_repository", + "local_goal" + ] + }, + "delivery_workspace_requirement": { + "meaning": "Workspace requirement a settlement asserts before delivery.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/quota/settlement_workspace_causality.py::DELIVERY_WORKSPACE_REQUIREMENTS", + "typescript": "loopx/control_plane/quota/settlement_workspace_causality.ts::DELIVERY_WORKSPACE_REQUIREMENTS" + }, + "values": [ + "required", + "not_required", + "unknown" + ] + }, + "goal_amendment_class": { + "meaning": "Class of a proposed Goal amendment.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/goals/goal_amendment_proposal.py::GOAL_AMENDMENT_CLASSES", + "typescript": "loopx/control_plane/goals/goal_amendment_proposal.ts::GOAL_AMENDMENT_CLASSES" + }, + "values": [ + "lane_route", + "shared_work_graph", + "shared_acceptance", + "protected_authority" + ] + }, + "goal_amendment_proposal_admission": { + "meaning": "Admission verdict for a Goal amendment proposal.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/goals/goal_amendment_proposal.py::GOAL_AMENDMENT_PROPOSAL_ADMISSIONS", + "typescript": "loopx/control_plane/goals/goal_amendment_proposal.ts::GOAL_AMENDMENT_PROPOSAL_ADMISSIONS" + }, + "values": [ + "admitted", + "needs_rebase" + ] + }, + "goal_amendment_proposal_admission_fact": { + "meaning": "Fact recorded with a Goal amendment admission verdict.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/goals/goal_amendment_proposal.py::GOAL_AMENDMENT_PROPOSAL_ADMISSION_FACTS", + "typescript": "loopx/control_plane/goals/goal_amendment_proposal.ts::GOAL_AMENDMENT_PROPOSAL_ADMISSION_FACTS" + }, + "values": [ + "base_state_event_basis_sequence_behind_derived_head", + "base_source_basis_digest_mismatch", + "base_source_basis_unverifiable", + "base_revision_basis_superseded" + ] + }, + "todo_decision_scope_kind": { + "meaning": "Scope kind of a Todo decision.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/todos/contract.py::TODO_DECISION_SCOPE_KIND_VALUES", + "typescript": "loopx/control_plane/todos/decision_metadata.ts::TODO_DECISION_SCOPE_KINDS" + }, + "values": [ + "private_read", + "write_scope", + "resource", + "production", + "public_claim", + "direction", + "other" + ] + }, + "todo_decision_scope_granularity": { + "meaning": "Granularity of a Todo decision scope.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/todos/contract.py::TODO_DECISION_SCOPE_GRANULARITY_VALUES", + "typescript": "loopx/control_plane/todos/decision_metadata.ts::TODO_DECISION_SCOPE_GRANULARITIES" + }, + "values": [ + "action", + "lane", + "goal", + "project", + "global" + ] + }, + "delivery_continuity_preemption": { + "meaning": "Reason a delivery continuity is preempted.", + "tier": "cross_runtime", + "status": "canonical", + "owners": { + "python": "loopx/control_plane/turn_driver/delivery_continuity.py::DELIVERY_CONTINUITY_PREEMPTIONS", + "typescript": "loopx/control_plane/turn_driver/delivery_continuity.ts::DELIVERY_CONTINUITY_PREEMPTIONS" + }, + "values": [ + "heartbeat_receipt", + "blocking_work_lane", + "autonomous_replan", + "control_repair", + "delivery_not_allowed" + ] + } + }, + "relations": { + "same_concept": [ + { + "concept": "repair", + "members": [ + "turn_result_kind.repair_required", + "turn_route.repair_required", + "loop_disposition.repair" + ], + "note": "Three spellings for one verdict across the three Turn vocabularies." + }, + { + "concept": "replan", + "members": [ + "turn_result_kind.replan_required", + "turn_route.replan_required", + "loop_disposition.replan" + ], + "note": "Same." + }, + { + "concept": "wait", + "members": [ + "turn_result_kind.wait", + "turn_route.wait", + "loop_disposition.wait" + ] + }, + { + "concept": "user_action_required", + "members": [ + "turn_result_kind.user_action_required", + "turn_route.user_action_required", + "loop_disposition.user_action_required" + ] + }, + { + "concept": "capability_action_required", + "members": [ + "turn_route.capability_action_required", + "loop_disposition.capability_action_required" + ] + }, + { + "concept": "terminal_no_followup", + "members": [ + "effective_action.terminal_no_followup", + "loop_disposition.terminal" + ], + "note": "The controller reads the effective_action literal directly to decide terminal." + } + ], + "shared_field_names": [ + { + "field": "effective_action", + "slots": [ + { + "slot": "decision.effective_action", + "vocabulary": "effective_action" + }, + { + "slot": "agent_scope_frontier.effective_action", + "vocabulary": "agent_scope_frontier_action" + }, + { + "slot": "turn_journal_replay.observation.effective_action", + "values": [ + "observe_replay", + "block_replay" + ] + } + ], + "note": "One field name, three vocabularies, inside one Turn Envelope. The literal scan cannot tell slots apart, so the decision vocabulary lists the replay values with notes until Q6 splits them." + } + ], + "subsets": [ + { + "name": "material_delivery_outcome", + "superset": "delivery_outcome", + "excluded": [ + "surface_only" + ], + "owners": { + "python": "loopx/control_plane/goals/goal_frontier/outcome_continuity.py::VISION_OUTCOME_CHECKPOINT_MATERIAL_OUTCOMES", + "typescript": "loopx/control_plane/work_items/delivery_outcome.ts::MATERIAL_DELIVERY_OUTCOMES" + }, + "note": "Identical set under two names across runtimes; a rename candidate." + }, + { + "name": "task_lease_lifecycle_decision_operation", + "superset": "lease_action", + "excluded": [ + "acquire" + ], + "owners": { + "python": null, + "typescript": "loopx/control_plane/work_items/task_lease_lifecycle_decision.ts::TASK_LEASE_LIFECYCLE_DECISION_OPERATIONS" + }, + "note": "TypeScript-only decision operations are the lease verbs minus acquire." + } + ] + }, + "projections": { + "turn_route_to_loop_disposition": { + "meaning": "Total mapping the pure controller applies to a typed route; null means the route is rejected before projection.", + "owner": "loopx/control_plane/turn_driver/loop_controller.py::_route_to_disposition", + "mapping": { + "ready_for_host": "run_now", + "capability_action_required": "capability_action_required", + "replan_required": "replan", + "repair_required": "repair", + "user_action_required": "user_action_required", + "wait": "wait", + "blocked": "wait", + "contract_error": null + } + } + }, + "schema_versions": { + "turn_envelope": { + "constant": "TURN_ENVELOPE_SCHEMA_VERSION", + "value": "loopx_turn_envelope_v0", + "owner_modules": [ + "loopx/control_plane/quota/turn_envelope.py", + "loopx/control_plane/quota/turn_envelope.ts" + ] + } + }, + "retirement_ledger": { + "should_run_legacy_decision_fields": { + "meaning": "Decision fields the should-run documentation already calls legacy. Budgets count modules under loopx/ that still mention the field.", + "fields": { + "execution_obligation": { + "python_module_budget": 21, + "typescript_module_budget": 1 + }, + "heartbeat_recommendation": { + "python_module_budget": 18, + "typescript_module_budget": 1 + }, + "work_lane_contract": { + "python_module_budget": 32, + "typescript_module_budget": 3 + }, + "external_evidence_observation": { + "python_module_budget": 11, + "typescript_module_budget": 1 + }, + "goal_boundary": { + "python_module_budget": 35, + "typescript_module_budget": 2 + }, + "protocol_action_packet": { + "python_module_budget": 7, + "typescript_module_budget": 2 + } + } + } + }, + "dual_runtime_twins": { + "meaning": "Same-basename .py/.ts module pairs under the control plane. The TypeScript migration RFC is replacement-first, so this count may only fall.", + "root": "loopx/control_plane", + "module_budget": 43 + }, + "inventory_ratchets": { + "meaning": "Counts read from the generated inventory. A same-runtime fork is one constant name with one value defined in two or more modules of the same runtime; a conflicting value is one name with different values. Both the number of affected names and the number of definitions are budgets, so a third spelling of an already-conflicting name is still a regression.", + "same_runtime_forks": 25, + "same_runtime_fork_definitions": 58, + "conflicting_values": 18, + "conflicting_definitions": 59, + "schema_version_same_runtime_forks": 7, + "multi_value_twins": 19, + "multi_value_forks": 4, + "multi_value_fork_definitions": 10, + "same_runtime_forks_semantic": 18, + "conflicting_values_semantic": 2, + "multi_value_meaning": "Enums, named closed sets, Literal aliases, and TypeScript as-const arrays are vocabulary exactly as a NAME = \"value\" constant is, so they get the same collision rule. One name defined in two modules with identical values is a twin; with different values it is a fork.", + "semantic_meaning": "same_runtime_forks_semantic and conflicting_values_semantic exclude module-local convention names such as SCHEMA_VERSION, COMMAND, or *_LABEL, which every module legitimately names for itself. The remaining names are shared vocabulary, where a duplicate is real drift rather than local naming; the unfiltered totals stay visible in the generated inventory summary." + } +} diff --git a/pyproject.toml b/pyproject.toml index 48da747bf5..418ffcb541 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ include = ["loopx*"] [tool.setuptools.package-data] "loopx" = ["web/chat/*.html", "web/chat/assets/*", "web/chat/manifest.webmanifest", "web/chat/pwa/*"] "loopx.control_plane" = ["*.json", "*.ts", "presentation/*.ts"] +"loopx.semantics" = ["*.json"] "loopx.control_plane.agents" = ["*.ts"] "loopx.control_plane.collaboration" = ["*.ts"] "loopx.control_plane.coordination" = ["*.ts", "*.json"] diff --git a/scripts/generate_semantic_inventory.py b/scripts/generate_semantic_inventory.py new file mode 100755 index 0000000000..ca254b2e24 --- /dev/null +++ b/scripts/generate_semantic_inventory.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +"""Generate or check the repository-wide semantic inventory. + +Usage: + python3.11 scripts/generate_semantic_inventory.py # rewrite inventory_v0.json + python3.11 scripts/generate_semantic_inventory.py --check # exit 1 when the file is stale + python3.11 scripts/generate_semantic_inventory.py --report # print advisory consumer ranking +""" + +from __future__ import annotations + +import argparse +import json +from pathlib import Path +import sys + +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + +from loopx.semantics.inventory import ( # noqa: E402 + build_inventory, + consumer_ranking, + load_sources, + render_inventory, +) + +INVENTORY_PATH = ROOT / "loopx" / "semantics" / "inventory_v0.json" + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("--check", action="store_true", help="fail when the committed inventory is stale") + parser.add_argument("--report", action="store_true", help="print the advisory consumer ranking") + parser.add_argument("--top", type=int, default=25, help="rows to print with --report") + args = parser.parse_args() + + inventory = build_inventory(ROOT) + content = render_inventory(inventory) + if args.report: + rows = consumer_ranking(inventory, load_sources(ROOT))[: args.top] + width = max(len(row["name"]) for row in rows) + print("external_consumer_modules values name module") + for row in rows: + print(f"{row['external_consumer_modules']:>25} {row['values']:>6} {row['name']:<{width}} {row['module']}") + return 0 + current = INVENTORY_PATH.read_text(encoding="utf-8") if INVENTORY_PATH.exists() else None + if current == content: + print(f"semantic inventory up to date: {INVENTORY_PATH.relative_to(ROOT)}") + return 0 + if args.check: + print( + f"stale semantic inventory: {INVENTORY_PATH.relative_to(ROOT)}; " + "run scripts/generate_semantic_inventory.py and commit the result", + file=sys.stderr, + ) + return 1 + INVENTORY_PATH.write_text(content, encoding="utf-8") + print(f"generated {INVENTORY_PATH.relative_to(ROOT)}") + print(json.dumps(inventory["summary"], indent=2)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/architecture/test_semantic_inventory.py b/tests/architecture/test_semantic_inventory.py new file mode 100644 index 0000000000..2855793771 --- /dev/null +++ b/tests/architecture/test_semantic_inventory.py @@ -0,0 +1,226 @@ +"""Semantics of the repository-wide vocabulary inventory scanner. + +The inventory is the map behind the semantic vocabulary registry. These tests +pin the classification rules from the RFC rather than from scanner output: +which carriers count as closed sets, how duplicate constants split into +cross-runtime twins, same-runtime forks, and conflicting values, and that the +committed inventory is regenerated with the code it describes. +""" + +from __future__ import annotations + +import json +from pathlib import Path +import subprocess +import sys + +import pytest + +from loopx.semantics.inventory import ( + INVENTORY_SCHEMA_VERSION, + SourceFile, + build_inventory, + load_sources, + python_facts, + render_inventory, +) + +REPO_ROOT = Path(__file__).resolve().parents[2] + + +def _write(root: Path, relative: str, text: str) -> None: + path = root / relative + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(text, encoding="utf-8") + + +@pytest.fixture +def repo(tmp_path: Path) -> Path: + _write( + tmp_path, + "loopx/a.py", + 'from enum import Enum\n' + 'from typing import Literal\n' + 'class Kind(str, Enum):\n ONE = "one"\n TWO = "two"\n _private = "ignored"\n' + 'class Mixed(Enum):\n A = "a"\n B = 2\n' + 'STATES = frozenset({"open", "closed"})\n' + 'SINGLE = ("only",)\n' + 'NOT_STRINGS = (1, 2)\n' + 'Mode = Literal["fast", "slow"]\n' + 'FOO_SCHEMA_VERSION = "foo_v0"\n' + 'SHARED = "same"\n' + 'CLASHING = "left"\n', + ) + _write( + tmp_path, + "loopx/b.py", + 'SHARED = "same"\n' + 'CLASHING = "right"\n' + 'FOO_SCHEMA_VERSION = "foo_v0"\n' + 'PAIRED_SCHEMA_VERSION = "paired_v0"\n', + ) + _write( + tmp_path, + "loopx/b.ts", + 'export const KINDS = ["one", "two"] as const;\n' + 'export const PAIRED_SCHEMA_VERSION = "paired_v0";\n' + 'export const NOT_CLOSED = ["x"];\n', + ) + _write(tmp_path, "loopx/__pycache__/junk.py", 'IGNORED = ("a", "b")\n') + _write(tmp_path, "loopx/node_modules/dep.ts", 'export const IGNORED = ["a", "b"] as const;\n') + subprocess.run(["git", "init", "-q", str(tmp_path)], check=True) + subprocess.run( + ["git", "-C", str(tmp_path), "add", "loopx/a.py", "loopx/b.py", "loopx/b.ts"], + check=True, + ) + return tmp_path + + +def test_python_carriers_are_classified_by_shape(repo: Path) -> None: + inventory = build_inventory(repo) + enums = {entry["name"]: entry["values"] for entry in inventory["python_enums"]} + assert enums == {"Kind": ["one", "two"]}, "only string-valued members of string enums are vocabularies" + closed = {entry["name"]: entry for entry in inventory["python_closed_sets"]} + assert set(closed) == {"STATES"}, "a closed set needs two or more string members" + assert closed["STATES"]["container"] == "frozenset" + assert [entry["values"] for entry in inventory["python_literal_aliases"]] == [["fast", "slow"]] + + +def test_typescript_as_const_arrays_only(repo: Path) -> None: + inventory = build_inventory(repo) + assert [entry["name"] for entry in inventory["typescript_const_arrays"]] == ["KINDS"] + + +def test_duplicate_constants_split_into_twin_fork_conflict(repo: Path) -> None: + inventory = build_inventory(repo)["duplicate_definitions"] + assert [entry["name"] for entry in inventory["cross_runtime_twins"]] == ["PAIRED_SCHEMA_VERSION"] + assert [entry["name"] for entry in inventory["same_runtime_forks"]] == ["FOO_SCHEMA_VERSION", "SHARED"] + assert [entry["name"] for entry in inventory["conflicting_values"]] == ["CLASHING"] + fork = inventory["same_runtime_forks"][0] + assert fork["is_schema_version"] is True + assert fork["modules"] == ["loopx/a.py", "loopx/b.py"] + + +def test_summary_counts_and_skipped_directories(repo: Path) -> None: + summary = build_inventory(repo)["summary"] + assert summary["source_files"] == 3, "__pycache__ and node_modules are never scanned" + assert summary["schema_version_names"] == 2 + assert summary["schema_version_same_runtime_forks"] == 1 + assert summary["cross_runtime_twins"] == 1 + assert summary["same_runtime_forks"] == 2 + assert summary["conflicting_values"] == 1 + + +@pytest.fixture +def collision_repo(tmp_path: Path) -> Path: + """A tree where multi-value carriers collide and local names look like drift. + + ``STATES`` is a closed set under two divergent value sets, ``TWIN_SET`` is one + closed set written twice, and ``SCHEMA_VERSION`` / ``FOO_SCHEMA_VERSION`` are + per-module names that must not be counted as shared vocabulary. + """ + _write( + tmp_path, + "loopx/a.py", + 'STATES = frozenset({"open", "closed"})\n' + 'TWIN_SET = ("p", "q")\n' + 'SCHEMA_VERSION = "a_v1"\n' + 'FOO_SCHEMA_VERSION = "foo_v0"\n' + 'SHARED = "same"\n', + ) + _write( + tmp_path, + "loopx/b.py", + 'STATES = frozenset({"open", "shut"})\n' + 'TWIN_SET = ("p", "q")\n' + 'SCHEMA_VERSION = "b_v1"\n' + 'FOO_SCHEMA_VERSION = "foo_v0"\n' + 'SHARED = "same"\n', + ) + subprocess.run(["git", "init", "-q", str(tmp_path)], check=True) + subprocess.run( + ["git", "-C", str(tmp_path), "add", "loopx/a.py", "loopx/b.py"], check=True, + ) + return tmp_path + + +def test_multi_value_carriers_collide_like_string_constants(collision_repo: Path) -> None: + """An enum or closed set carries vocabulary, so a duplicate name is drift. + + Before this rule the scanner listed multi-value carriers but never compared + them, so a closed set defined in two modules with divergent values was + invisible to every budget. + """ + duplicates = build_inventory(collision_repo)["duplicate_definitions"] + assert [entry["name"] for entry in duplicates["multi_value_forks"]] == ["STATES"] + assert [entry["name"] for entry in duplicates["multi_value_twins"]] == ["TWIN_SET"] + fork = duplicates["multi_value_forks"][0] + assert [item["values"] for item in fork["definitions"]] == [ + ["open", "closed"], + ["open", "shut"], + ], "the fork keeps both value sets so a reviewer sees the divergence" + assert [item["kind"] for item in fork["definitions"]] == [ + "python_closed_set", + "python_closed_set", + ] + + +def test_module_local_convention_names_stay_out_of_semantic_budgets(collision_repo: Path) -> None: + """``SCHEMA_VERSION`` and ``FOO_SCHEMA_VERSION`` are per-module names, not drift. + + Counting them as conflicts measured local naming; the unfiltered totals stay + visible, while only the shared-vocabulary subset is budgeted. + """ + summary = build_inventory(collision_repo)["summary"] + assert summary["conflicting_values"] == 1, "SCHEMA_VERSION still counts in the raw total" + assert summary["conflicting_values_semantic"] == 0, "neither name is shared vocabulary" + assert summary["same_runtime_forks"] == 2 + assert summary["same_runtime_forks_semantic"] == 1, "only SHARED is shared vocabulary" + assert summary["multi_value_forks"] == 1 + assert summary["multi_value_twins"] == 1 + + +def test_render_is_deterministic_valid_json(repo: Path) -> None: + inventory = build_inventory(repo) + rendered = render_inventory(inventory) + assert rendered == render_inventory(build_inventory(repo)) + assert json.loads(rendered) == inventory + assert inventory["schema_version"] == INVENTORY_SCHEMA_VERSION + # one entry per line keeps diffs reviewable + assert ' {"name": "Kind", "module": "loopx/a.py", "values": ["one", "two"]}' in rendered + + +def test_committed_inventory_matches_the_tree() -> None: + result = subprocess.run( + [sys.executable, str(REPO_ROOT / "scripts" / "generate_semantic_inventory.py"), "--check"], + capture_output=True, + text=True, + cwd=REPO_ROOT, + ) + assert result.returncode == 0, result.stderr + + +def test_untracked_sources_do_not_change_inventory(repo: Path) -> None: + before = render_inventory(build_inventory(repo)) + _write(repo, "loopx/local_notes.py", 'PRIVATE_CONTEXT = ("synthetic", "local")\n') + assert render_inventory(build_inventory(repo)) == before + + +def test_tracked_symlink_cannot_read_untracked_source(repo: Path) -> None: + _write(repo, "private.py", 'PRIVATE_CONTEXT = ("synthetic", "local")\n') + (repo / "loopx/link.py").symlink_to(repo / "private.py") + subprocess.run(["git", "-C", str(repo), "add", "loopx/link.py"], check=True) + with pytest.raises(ValueError, match="symlink"): + load_sources(repo) + + +def test_invalid_python_source_is_not_reported_as_empty() -> None: + with pytest.raises(ValueError, match="loopx/broken.py"): + python_facts(SourceFile("loopx/broken.py", ".py", 'STATES = ("open",\n')) + + +def test_typescript_single_quoted_carriers_are_visible(repo: Path) -> None: + _write(repo, "loopx/b.ts", "export const KINDS = ['one', 'two'] as const;\nexport const SHARED = 'same';\n") + inventory = build_inventory(repo) + assert inventory["typescript_const_arrays"][0]["values"] == ["one", "two"] + assert any(item["name"] == "SHARED" for item in inventory["duplicate_definitions"]["same_runtime_forks"]) diff --git a/tests/architecture/test_semantic_vocabulary_drift.py b/tests/architecture/test_semantic_vocabulary_drift.py new file mode 100644 index 0000000000..50d9434045 --- /dev/null +++ b/tests/architecture/test_semantic_vocabulary_drift.py @@ -0,0 +1,65 @@ +"""Run the semantic vocabulary drift smoke inside the pull-request pytest sweep. + +The canary fleet discovers ``examples/**/*-smoke.py`` on its own, but the fleet +runs after merge and on a schedule, and ``loopx canary premerge`` selects smokes +by changed-path tokens. Neither is a commit-time check for a diff that only +touches ``loopx/``. This wrapper is the PR-path obligation named in the RFC +``docs/architecture/rfcs/semantic-vocabulary-convergence-v0.md`` (Section 10): +the smoke fails closed here on every pull request that runs the Python tests. +""" + +from __future__ import annotations + +import copy +import runpy +import subprocess +import sys +from pathlib import Path + +import pytest + +REPO_ROOT = Path(__file__).resolve().parents[2] +SMOKE = REPO_ROOT / "examples" / "semantic-vocabulary-drift-smoke.py" + + +def test_semantic_vocabulary_registry_matches_the_code() -> None: + completed = subprocess.run( + [sys.executable, "-B", str(SMOKE)], + cwd=REPO_ROOT, + capture_output=True, + text=True, + timeout=180, + check=False, + ) + assert completed.returncode == 0, ( + "semantic vocabulary drift smoke failed; the registry, the inventory, or an " + "anchor no longer matches the code:\n" + completed.stdout + completed.stderr + ) + assert completed.stdout.startswith("semantic-vocabulary-drift-smoke: ok"), ( + completed.stdout + ) + + +@pytest.mark.parametrize("mutation", ["twin_budget", "twin_root", "scan_root"]) +def test_registry_cannot_relax_scan_scope_or_twin_budget(mutation: str) -> None: + smoke = runpy.run_path(str(SMOKE)) + registry = copy.deepcopy(smoke["load_registry"]()) + if mutation == "twin_budget": + registry["dual_runtime_twins"]["module_budget"] += 1 + elif mutation == "twin_root": + registry["dual_runtime_twins"]["root"] = "loopx/semantics" + else: + registry["vocabularies"]["effective_action"]["literal_scan"]["roots"] = ["loopx/control_plane"] + with pytest.raises(smoke["Drift"]): + smoke["check_coverage_floor"](registry) + smoke["check_dual_runtime_twins"](registry) + + +@pytest.mark.parametrize("suffix", [".py", ".ts"]) +@pytest.mark.parametrize("quote", ["'", '\"']) +def test_literal_scan_rejects_unknown_value_with_either_quote(suffix: str, quote: str) -> None: + smoke = runpy.run_path(str(SMOKE)) + text = f"effective_action = {quote}unregistered_action{quote}" + sources = [smoke["SourceFile"]("loopx/probe" + suffix, suffix, text)] + with pytest.raises(smoke["Drift"], match="unregistered_action"): + smoke["check_literal_vocabularies"](smoke["load_registry"](), sources)