Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions docs/architecture/rfcs/semantic-vocabulary-convergence-v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,10 +315,10 @@ definitions in `global_risks.py`, `global_todos.py`, `summary_all.py`, and
`pr_review.py` each list the data sources of that one CLI command, and the
value sets are meant to differ. It is counted in `multi_value_forks` today and
must not be "fixed" by renaming, because a rename lowers the number without
changing the code's meaning. M0.5 adds a `scope` field to the registry with at
least `global` and `bounded_context`, lets a bounded-context name be declared
once with its owning contexts, and removes declared names from the fork
budget (I14, the schema rows below, and the M0.5 row in Section 11). Until
changing the code's meaning. The M0.5 scope slice adds top-level `scope_declarations` with at
least `global` and `bounded_context`; a bounded-context name is declared once
with its owning contexts, and declared names are removed from the semantic
fork budget while the raw inventory count remains visible (I14, the schema rows below, and the M0.5 row in Section 11). Until
then the fork budget is a ceiling that contains this one known
misclassification, recorded in the registry's `inventory_ratchets` note.

Expand Down Expand Up @@ -417,7 +417,7 @@ vocabulary key fails the smoke.
| `vocabularies.<name>.tier`, `status` | `kernel`, `cross_runtime`, `cross_module`; `canonical`, `legacy`, `merge_candidate` | Closed enumerations |
| `vocabularies.<name>.literal_scan` | `field`, roots, suffixes | Every literal the fixed dispatch forms capture is registered; every registered value is captured or variable-sourced (I2) |
| `vocabularies.<name>.variable_sourced_values` | value to producer module | The producer still contains the quoted value |
| `vocabularies.<name>.scope` (M0.5) | `global` or `bounded_context`; a `bounded_context` entry lists `contexts`, each with one owner symbol | Closed enumeration; declared bounded-context names are excluded from `multi_value_forks`; an undeclared multi-module name stays a fork (I14) |
| `scope_declarations.<name>` (M0.5a) | `bounded_context` and its context IDs, each with one `module::Symbol` owner | Every declared name resolves to one inventory fork, names every defining module exactly once, and is excluded only from `multi_value_forks_semantic`; undeclared forks remain visible (I14) |
| `vocabularies.<name>.producers` (M0.5) | `path::Symbol` sites that write the field, required for `kernel` | Every site writes registered values only; every value not under `compatibility_only` has at least one site or a variable-sourced entry (I12, I13) |
| `vocabularies.<name>.compatibility_only` (M0.5) | values kept so readers of persisted records still resolve them | Subset of `values`; zero production sites; each carries a `value_notes` reason and a retirement milestone |
| `formal_model` | finite universes, role relations and hierarchy, semantic obligations, and established/bounded/unproved claims | Exact schema, role hierarchy, and invariant ids are checked by the drift smoke; enforcement stages cannot be mistaken for completed proofs |
Expand Down Expand Up @@ -534,11 +534,11 @@ inventory in the same PR.
| 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 |
| Retirement budgets count substrings, not identifiers | `goal_boundary` counted with `in file.text` and with `\bgoal_boundary\b` | 35 vs 30 Python modules on the baseline | Known boundary; M3's zero-reader gate needs the identifier count, tracked in Section 12 |
| Retirement budgets use standalone field tokens | `count_identifier_modules()` uses identifier boundaries for the six fields | `goal_boundary`: 30 Python modules under the new metric; the old substring metric was 35 | Conservative lexical measure; it removes compound-name false positives but does not prove semantic reader absence |
| The module-local convention filter is a code edit | Widen `MODULE_LOCAL_CONVENTION` in `inventory.py` and regenerate | `*_semantic` budgets fall with no code change elsewhere | Known boundary; the regex is in code so the widening is a reviewed diff, and the unfiltered totals stay budgeted |
| A registered value nobody produces fails (M0.5) | Run the production-form scan on the baseline | Fails naming `effective_action` and `skip`; passes after `skip` is removed or listed `compatibility_only` | First expected I12 failure; a compared-only value is not carried |
| A producer of an unregistered value fails (M0.5) | Write `effective_action: "brand_new"` in a listed producer site | Fails naming the site and the value even though no consumer compares it | I13; production is stricter than comparison |
| A bounded-context name leaves the fork budget only by declaration (M0.5) | Declare `SOURCE_SURFACES` with its four contexts; separately, rename one definition without declaring | The declaration lowers `multi_value_forks` to 3; the rename alone does not | I14; the honest fix is a registry edit a reviewer sees, the rename is code without registry change |
| A bounded-context name leaves only the semantic fork budget by declaration (M0.5a) | Declare `SOURCE_SURFACES` with its four contexts; separately, rename one definition without declaring | Raw `multi_value_forks` stays 4, `multi_value_forks_semantic` is 3; a rename alone changes neither semantic accounting nor declaration | I14; the honest fix is a registry edit a reviewer sees, the rename is not a repair |
| An upstream merge can stale the committed inventory | Replay the scanner over the first parent and the merge of the last twenty `upstream/main` merge commits | 8 of 20 merges change at least one carrier | Measured cost of committing a snapshot; the handling rule is Section 10 and Section 12 Q9 |
| The formal model cannot silently lose a proof obligation | Remove an invariant, role, relation, or proof-boundary category from `formal_model` | The drift smoke fails on the exact formal-model shape | The model is a finite contract and proof ledger; it does not prove the listed properties by itself |

Expand Down Expand Up @@ -614,7 +614,8 @@ commands as `python3.11` for that reason, and the planner entry is left as
| 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 |
| M0.5 | `scope` with `global` and `bounded_context` and per-context owners; `producers` and `compatibility_only` on `kernel` vocabularies; production-form scan with the two role checks (I12, I13); retirement budgets counted by identifier with all six anchors lowered in one diff (Q11); merge-order rule from Q9 written into Section 10 | M0 merged; Q9 decided or its interim rule accepted | Smoke green with I11 to I14 enforced; `skip` resolved; `multi_value_forks` at 3 by declaration; Section 9 role rows green; `turn_route` persistence answered for Q2 | Remove the three fields and the role checks; budgets return to the M0 anchors |
| M0.5a | `scope_declarations` with `bounded_context` and per-context owners; semantic fork count separated from raw inventory count | M0 merged | Smoke checks every declared context owner; raw `multi_value_forks` remains 4 and `multi_value_forks_semantic` is 3; undeclared forks still fail the budget | Remove the scope declarations and semantic-fork budget |
| M0.5b | `producers` and `compatibility_only` on `kernel` vocabularies; production-form scan with the two role checks (I12, I13); retirement budgets counted by identifier with all six anchors lowered in one diff (Q11); merge-order rule from Q9 written into Section 10 | M0.5a complete; Q9 decided or its interim rule accepted | Smoke green with I11 to I14 enforced; `skip` resolved; Section 9 producer rows green; `turn_route` persistence answered for Q2 | Remove producer fields and role checks; budgets return to the pre-M0.5b anchors |
| 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.5 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 |
Expand Down Expand Up @@ -760,11 +761,11 @@ introduce a competing target state.
write, then retire) to one spelling per concept. Without this decision the
RFC has budgets but no definition of done for its headline problem.
Owner: Turn driver owner. Needed before M2 closes.
11. **Retirement budgets by identifier.** The six legacy-field budgets count
`field in file.text`; `goal_boundary` matches `goal_boundary_repair`. M3's
zero-external-reader gate needs word-boundary counting, which lowers all six
anchors in one diff. Recommendation: do it before the first M3 PR.
Owner: kernel maintainers.
11. **Retirement budgets by identifier.** The six legacy-field budgets now use
`count_identifier_modules()`, so `goal_boundary_repair` is not counted as
`goal_boundary`. This is a conservative lexical metric, not proof of zero
semantic readers; computed accesses remain an evidence gap. Owner: kernel
maintainers.

## Appendix A: Execution ledger (non-normative)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,9 @@ todos、capabilities 与 TypeScript 运行时各自拥有同一想法的一种
个案例:它在 `global_risks.py`、`global_todos.py`、`summary_all.py`、
`pr_review.py` 的四处定义各自列出那一个 CLI 命令的数据来源,值集本来就该不
同。它今天被计入 `multi_value_forks`,且不得用改名来"修",因为改名只让数字
下降、不改变代码含义。M0.5 给注册表加 `scope` 字段,至少含 `global` 与
`bounded_context`,允许一个有界上下文名字连同其所属上下文声明一次,并把已
声明的名字从分叉预算移出(I14、下方 schema 表与第 11 节的 M0.5 行)。在此之
下降、不改变代码含义。M0.5 的作用域子阶段增加顶层 `scope_declarations`,至少支持 `global` 与
`bounded_context`;有界上下文名字只声明一次并列出其 owner,同时从语义分叉预算
中移除,原始清单计数仍保留(I14、下方 schema 表与第 11 节的 M0.5 行)。在此之
前分叉预算是一个包含这一处已知误分类的上
限,记在注册表 `inventory_ratchets` 的备注里。

Expand Down Expand Up @@ -341,7 +341,7 @@ R ⊆ S × V × Version 将值持久化
| `vocabularies.<name>.tier`、`status` | `kernel`、`cross_runtime`、`cross_module`;`canonical`、`legacy`、`merge_candidate` | 封闭枚举 |
| `vocabularies.<name>.literal_scan` | `field`、根目录、后缀 | 固定分发形式捕获的每个字面量都已注册;每个注册值被捕获或来自变量(I2) |
| `vocabularies.<name>.variable_sourced_values` | 值到生产者模块 | 生产者仍包含带引号的该值 |
| `vocabularies.<name>.scope`(M0.5) | `global` 或 `bounded_context`;`bounded_context` 条目列出 `contexts`,每个含一个 owner 符号 | 封闭枚举;已声明的有界上下文名字从 `multi_value_forks` 排除;未声明的多模块名字仍是分叉(I14) |
| `scope_declarations.<name>`(M0.5a) | `bounded_context` 及上下文 ID,每个上下文含一个 `module::Symbol` owner | 每个声明名对应一个 inventory 分叉,并且一次且仅一次列出全部定义模块;只从 `multi_value_forks_semantic` 排除,未声明分叉仍可见(I14) |
| `vocabularies.<name>.producers`(M0.5) | 写入该字段的 `path::Symbol` 位点,`kernel` 必填 | 每个位点只写注册值;未列入 `compatibility_only` 的每个值至少有一个位点或一条变量来源条目(I12、I13) |
| `vocabularies.<name>.compatibility_only`(M0.5) | 为让已持久化记录的读者仍能解析而保留的值 | `values` 的子集;零生产位点;每个值带 `value_notes` 理由与退休里程碑 |
| `formal_model` | 有限的集合、角色关系与层次、语义义务,以及已建立/有界/未证明的声明 | 漂移 smoke 校验精确 schema、角色层次和不变量 ID;属性实施阶段不能冒充已完成证明 |
Expand Down Expand Up @@ -444,7 +444,7 @@ PR 中重新生成清单。
| 退休预算按子串而非标识符计数 | 分别以 `in file.text` 与 `\bgoal_boundary\b` 统计 `goal_boundary` | 基线上 35 对 30 个 Python 模块 | 已知边界;M3 的零读者门需要标识符计数,见第 12 节 |
| 模块局部约定过滤器是一次代码修改 | 扩宽 `inventory.py` 的 `MODULE_LOCAL_CONVENTION` 并重新生成 | `*_semantic` 预算下降而别处无代码改动 | 已知边界;正则在代码里,扩宽是可评审的 diff,未过滤总数仍在预算内 || 无人生产的注册值失败(M0.5) | 在基线上运行生产形式扫描 | 失败并点名 `effective_action` 与 `skip`;删除 `skip` 或列入 `compatibility_only` 后通过 | 第一个预期的 I12 失败;只被比较的值不算已携带 |
| 生产未注册值失败(M0.5) | 在某个已列生产位点写 `effective_action: "brand_new"` | 即使无消费者比较它也失败,并点名位点与值 | I13;生产比比较更严 |
| 有界上下文名字只能靠声明离开分叉预算(M0.5) | 为 `SOURCE_SURFACES` 声明四个上下文;另行只改名其中一处定义而不声明 | 声明把 `multi_value_forks` 降到 3;单独改名不降 | I14;诚实的修法是评审者看得见的注册表修改,改名是不碰注册表的代码改动 |
| 有界上下文名字只能靠声明离开语义分叉预算(M0.5a) | 为 `SOURCE_SURFACES` 声明四个上下文;另行只改名其中一处定义而不声明 | 原始 `multi_value_forks` 保持 4,`multi_value_forks_semantic` 为 3;单独改名既不改变语义计数,也不构成声明 | I14;诚实的修法是评审者看得见的注册表修改,改名不是修复 |

| 上游合并会让已提交清单过期 | 对 `upstream/main` 最近二十个合并提交,在第一父提交与合并结果之间重放扫描器 | 20 次合并中 8 次至少改变一个载体 | 提交快照的实测成本;处理规则见第 10 节与第 12 节 Q9 |
| 形式模型不能静默丢失证明义务 | 从 `formal_model` 删除不变量、角色、关系或证明边界分类 | 漂移 smoke 针对形式模型结构失败 | 该模型是有限契约和证明账本,本身不等于这些性质已经被证明 |
Expand Down Expand Up @@ -507,7 +507,8 @@ planner 条目则有意保留 `python3`。
| 里程碑 | 交付行为 | 进入门 | 退出证据 | 回滚 |
| --- | --- | --- | --- | --- |
| M0 | 含 26 个词表与 9 条关系的注册表、带 `--check` 的生成清单、带固定分发形式与覆盖下限的漂移 smoke、删除两处 owner 分叉、RFC 索引条目 | 本 RFC 开启 | 第 9 节各行全绿;20 类突变失败关闭 | 删除 smoke、`loopx/semantics/`、生成器及其测试 |
| M0.5 | 含 `global` 与 `bounded_context` 及每上下文 owner 的 `scope`;`kernel` 词表上的 `producers` 与 `compatibility_only`;带两条角色检查(I12、I13)的生产形式扫描;退休预算改按标识符计数并在一个 diff 里调低全部六个锚点(Q11);Q9 的合并序规则写入第 10 节 | M0 合入;Q9 已决或其临时规则被接受 | smoke 在 I11 到 I14 强制下全绿;`skip` 已处理;`multi_value_forks` 靠声明降到 3;第 9 节角色行全绿;为 Q2 回答 `turn_route` 是否持久化 | 删除三个字段与角色检查;预算回到 M0 锚点 |
| M0.5a | `scope_declarations` 的 `bounded_context` 与每上下文 owner;把语义分叉计数与原始清单计数分开 | M0 合入 | smoke 校验每个声明的上下文 owner;原始 `multi_value_forks` 仍为 4,`multi_value_forks_semantic` 为 3;未声明分叉仍受预算约束 | 删除作用域声明和语义分叉预算 |
| M0.5b | `kernel` 词表的 `producers` 与 `compatibility_only`;带两条角色检查(I12、I13)的生产形式扫描;退休预算改按标识符计数并在一个 diff 里调整六个锚点(Q11);Q9 的合并序规则写入第 10 节 | M0.5a 完成;Q9 已决或其临时规则被接受 | smoke 在 I11 到 I14 强制下全绿;`skip` 已处理;第 9 节生产者行全绿;为 Q2 回答 `turn_route` 是否持久化 | 删除生产者字段和角色检查;预算回到 M0.5b 前的锚点 |
| M1 | 单一 owner 模块中的 `EffectiveAction` 类型化枚举;replay observation 与 frontier 槽位拆出(Q6);生产者与消费者 import 它;注册表 `literal_scan` 收紧到枚举 | M0.5 合入;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 条目 | 从最后一个写方恢复字段 |
Expand Down Expand Up @@ -621,10 +622,10 @@ planner 条目则有意保留 `python3`。
应在 (a) 三套加生成投影(现行计划)与 (b) 两阶段合并(先双写、后退休)到
每个概念一种拼法之间选择。没有这个决定,RFC 对其标题问题只有预算、没有
完成定义。Owner:Turn driver owner。M2 关闭前需定。
11. **退休预算按标识符计数。** 六个旧字段预算用 `field in file.text` 统计;
`goal_boundary` 会匹配 `goal_boundary_repair`。M3 的零外部读者门需要词边界
计数,这会在一个 diff 里调低全部六个锚点。建议:在第一个 M3 PR 之前做。
Owner:内核维护者。
11. **退休预算使用独立字段 token。** 六个旧字段预算现在使用
`count_identifier_modules()`,因此 `goal_boundary_repair` 不会被算作
`goal_boundary`。这是保守的词法指标,不等于证明不存在语义读者;计算式访问
仍然是证据缺口。Owner:内核维护者。

## 附录 A:执行账本(非规范)

Expand Down
Loading