From 0eaf6576cfc437b149dae2e2bcd3c871892da2af Mon Sep 17 00:00:00 2001 From: wchwawa Date: Tue, 22 Sep 2026 17:37:31 +1000 Subject: [PATCH] docs(rfc): record NoKV v0 envelope capacity and the 0.11.1 fence live qualification in the ledger Two non-normative entries in the shared-goal-authority execution ledger (Appendix D), each with its Chinese mirror: - 2026-09-19: the measured capacity of the NoKV v0 single-envelope layout. The 21,858-byte production-scale history projection reaches the 16 MiB cap at commit 739 (about 0.86 days at the 864 commits/day continuity load) and a 64 KiB projection at commit 252 (0.29 days); live commit latency grows from 341 ms to 3,460 ms and reads are O(history). It also records the NoKV replay and admission facts that bound the bounded-layout design in #4727. - 2026-09-22: the live re-measurement of the incarnation fence connected by #4774 on a stack NoKV-Lab/NoKV#518 brings up from one command: LoopX main 4bed6ed3d, NoKV 590d3a4bdc (v0.11.1) owner built from that commit, the released 0.11.1 wheel; the complete 23-row ladder passes 22 rows with PostgreSQL unverified and the soak pending; the 0.11.0 wheel is refused typed at admission; the moto fallback passes; the macOS symlinked-TMPDIR condition that fails the s2c2 rows is recorded as a LoopX condition. Neither entry moves a qualification hold or edits an RFC clause; both end with what they do not establish. Signed-off-by: wchwawa --- .../2026-09-19-nokv-v0-envelope-capacity.md | 56 ++++++++++++++++ ...6-09-19-nokv-v0-envelope-capacity.zh-CN.md | 36 +++++++++++ ...-1-incarnation-fence-live-qualification.md | 64 +++++++++++++++++++ ...arnation-fence-live-qualification.zh-CN.md | 40 ++++++++++++ 4 files changed, 196 insertions(+) create mode 100644 docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-19-nokv-v0-envelope-capacity.md create mode 100644 docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-19-nokv-v0-envelope-capacity.zh-CN.md create mode 100644 docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-22-nokv-0-11-1-incarnation-fence-live-qualification.md create mode 100644 docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-22-nokv-0-11-1-incarnation-fence-live-qualification.zh-CN.md diff --git a/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-19-nokv-v0-envelope-capacity.md b/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-19-nokv-v0-envelope-capacity.md new file mode 100644 index 0000000000..11f2c38c2f --- /dev/null +++ b/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-19-nokv-v0-envelope-capacity.md @@ -0,0 +1,56 @@ +# NoKV v0 single-envelope capacity, measured + +Non-normative for the shared Goal authority model: it changes no code and no +profile. It records what the current NoKV candidate layout can hold before it +fails closed, so that §7.2's bounded-head discussion and the bounded-layout +design in [#4727](https://github.com/loopx-project/loopx/issues/4727) argue from +a measurement instead of an estimate. + +- **What was measured.** `NoKVAuthorityStore` keeps one JSON envelope per goal + and republishes the whole retained journal on every commit; the envelope is + capped at 16 MiB (`DEFAULT_MAX_ENVELOPE_BYTES`), after which `commitAuthority` + returns `failed/authority_envelope_too_large` before any CAS. A probe outside + the repository committed one transaction after another through the real + store (`commitAuthority`, then `readReceipt` of the first and last operation + and `loadAuthority`, sampled every 50 commits) until that refusal, once over + an in-memory transport and once over the real JSON-lines helper against a + single-node NoKV 0.11.1 owner. Every transaction carried a fixed projection + plus about 0.6 KiB of events and receipts. The projection sizes were the + production-scale history fixture as it is (21,858 bytes) and a 64 KiB + synthetic one. Measured on LoopX `da6d79778` (2026-09-19, before the + incarnation fence landed; the envelope layout is unchanged on `main`). +- **Where the envelope stops.** In memory the 21,858-byte projection reached + the cap at commit 739 (final envelope 16,758,084 bytes, about 22.7 KB added per + commit); the 64 KiB projection at commit 252 (16,762,707 bytes, about 66.7 KB + per commit). Live, the 64 KiB profile stopped at the same commit 252 with + 16,762,708 bytes. The cap is therefore reached by retained projections, not + by receipts: every committed row keeps its full projection. +- **What that means in days.** Against §7.2's minimum continuity load of 864 + commits per day, the 21,858-byte profile lasts about 0.86 days and the 64 KiB + profile about 0.29 days; at 10,000 commits per day, 1.8 hours and 0.6 hours. +- **Latency grows with history.** Live, commit latency went from 341 ms at + commit 2 to 3,460 ms at commit 251 (p50 1,340 ms, p95 3,139 ms over 251 + commits); `readReceipt` of the first operation from 66 ms to 1,307 ms; + `loadAuthority` from 57 ms to 1,334 ms. Reading is O(history) because every + read decodes and re-verifies the whole journal. +- **Traffic.** Reaching the cap live moved 2,128,646,475 bytes of writes and + 4,627,769,098 bytes of reads over 409.6 s for 252 commits; the 739-commit + in-memory run accounted 6,208,337,638 bytes written and 12,526,179,676 read. + Each commit reads the envelope twice and each read carries one + `find_workspaces` identity check. +- **NoKV facts that bound the design space.** Re-publishing the same bytes + under the same `operation_id`/`artifact_revision_id` is `applied` (idempotent + replay); a create-only publish with fresh ids on an existing path is + `conflict`; reusing ids with different bytes or a stale generation is refused + in a way the helper can only report as `ambiguous`, so publication ids are + terminal after the first attempt. Single objects of 4, 8, 16 and 24 MiB were + accepted and read back through the same transport (24 MiB needs the + transport's response limit raised above its 32 MiB default), so 16 MiB is a + LoopX constant, not a NoKV limit. +- **What this does not establish.** No bounded layout exists yet; #4727 is a + design, not a delivery. The measurement covers one owner, one workbench and + one goal; it says nothing about restart or restore recovery, availability, + HA, or retention policy, and it does not move any qualification hold. The + reason code stays `authority_envelope_too_large`; whether the NoKV plane + adopts Appendix C's `store_capacity_exhausted` is an owner decision recorded + in #4727. diff --git a/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-19-nokv-v0-envelope-capacity.zh-CN.md b/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-19-nokv-v0-envelope-capacity.zh-CN.md new file mode 100644 index 0000000000..865bfaa191 --- /dev/null +++ b/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-19-nokv-v0-envelope-capacity.zh-CN.md @@ -0,0 +1,36 @@ +# NoKV v0 单信封容量实测 + +对共享 Goal authority 模型是非规范性的:不改任何代码,也不改任何 profile。它记录当前 +NoKV 候选布局在 fail-closed 之前能装下多少,让 §7.2 的有界 head 讨论和 +[#4727](https://github.com/loopx-project/loopx/issues/4727) 的有界布局设计建立在实测而非 +估算之上。 + +- **测的是什么。** `NoKVAuthorityStore` 为每个 goal 保存一个 JSON 信封,每次提交都把整段 + 保留 journal 重新发布;信封上限 16 MiB(`DEFAULT_MAX_ENVELOPE_BYTES`),超过后 + `commitAuthority` 在任何 CAS 之前返回 `failed/authority_envelope_too_large`。一个仓库外的 + 探针通过真实 store 逐笔提交(`commitAuthority`,每 50 笔采样一次首末操作的 `readReceipt` + 与 `loadAuthority`),直到收到该拒绝;一次走内存传输,一次走真实 JSON-lines helper 对单节点 + NoKV 0.11.1 owner。每笔事务带固定投影加约 0.6 KiB 的事件与收据。投影尺寸取生产规模 + history fixture 的自然大小(21,858 字节)和一个 64 KiB 的合成投影。测量基线为 LoopX + `da6d79778`(2026-09-19,incarnation 围栏合入之前;信封布局在 `main` 上未变)。 +- **信封在哪里停。** 内存下,21,858 字节投影在第 739 笔到顶(最终信封 16,758,084 字节,每笔约增 + 22.7 KB);64 KiB 投影在第 252 笔到顶(16,762,707 字节,每笔约 66.7 KB)。live 下 64 KiB 档 + 同样停在第 252 笔,16,762,708 字节。所以到顶的是保留的投影而不是收据:每一行已提交记录都留着 + 完整投影。 +- **折成天数。** 按 §7.2 每天 864 笔的最低连续性负载,21,858 字节档约撑 0.86 天,64 KiB 档约 + 0.29 天;按每天 10,000 笔,分别是 1.8 小时和 0.6 小时。 +- **延迟随历史增长。** live 下提交延迟从第 2 笔的 341 ms 涨到第 251 笔的 3,460 ms(251 笔的 + p50 1,340 ms、p95 3,139 ms);首个操作的 `readReceipt` 从 66 ms 到 1,307 ms;`loadAuthority` + 从 57 ms 到 1,334 ms。读是 O(历史),因为每次读都要解码并重新校验整段 journal。 +- **流量。** live 下到顶共写 2,128,646,475 字节、读 4,627,769,098 字节,252 笔耗时 409.6 秒; + 内存下 739 笔累计写 6,208,337,638 字节、读 12,526,179,676 字节。每笔提交读两次信封,每次读附带 + 一次 `find_workspaces` 身份校验。 +- **约束设计空间的 NoKV 事实。** 用同一 `operation_id`/`artifact_revision_id` 重发同一字节是 + `applied`(幂等回放);已存在路径上换新 id 的 create-only 发布是 `conflict`;复用 id 换字节或用 + 过期 generation 的拒绝,helper 只能报 `ambiguous`,所以发布 id 在首次尝试后即为终态。4、8、 + 16、24 MiB 的单对象都能经同一传输发布并读回(24 MiB 需把传输的响应上限从默认 32 MiB 调高), + 因此 16 MiB 是 LoopX 常量,不是 NoKV 的限制。 +- **本条目没有确立的事。** 有界布局尚不存在;#4727 是设计,不是交付。测量只覆盖一个 owner、 + 一个 workbench、一个 goal;对重启/恢复、可用性、HA、保留策略不作任何断言,也不移动任何资格 + hold。拒绝码仍是 `authority_envelope_too_large`;NoKV 面是否采用 Appendix C 的 + `store_capacity_exhausted` 是记录在 #4727 里的 owner 决定。 diff --git a/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-22-nokv-0-11-1-incarnation-fence-live-qualification.md b/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-22-nokv-0-11-1-incarnation-fence-live-qualification.md new file mode 100644 index 0000000000..f14aae96ff --- /dev/null +++ b/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-22-nokv-0-11-1-incarnation-fence-live-qualification.md @@ -0,0 +1,64 @@ +# NoKV 0.11.1 incarnation fence, live qualification on a reproducible stack + +Non-normative for the shared Goal authority model: it moves no qualification +hold and edits no RFC clause. It records the live re-measurement of the +publication fence that [#4774](https://github.com/loopx-project/loopx/pull/4774) +connected, on a stack anyone can bring up from one command, so that the hold +removal the RFC still lists has a citable record instead of a contributor's +scratch directory. + +- **What the change was.** #4774 (approved head `9cffc78be`, squash-merged as + `be7789fd95` on 2026-09-20) makes every `NoKVAuthorityStore` publication carry + `expected_workspace_incarnation_id`, the incarnation the envelope was read + under. NoKV 0.11.1 evaluates that fence atomically with `expected_generation` + before any operation row, artifact revision or object exists and refuses a + stale incarnation with the typed `WorkspaceIncarnationMismatch`, which the + helper maps to `failed/store_identity_mismatch`; the helper pins SDK 0.11.1 and + admits only a wheel that names the fence parameter and exports the typed + refusal. The approving review kept the profile hold + `atomic_workspace_incarnation_publication_fence` and Appendix A's wording + because the maintainer had no live owner to rerun the write-producing probe. +- **What made the re-measurement reproducible.** NoKV-Lab/NoKV#518 adds + `scripts/workbench/loopx_stage2a_stack.py`, which starts an isolated etcd + member, a digest-pinned RustFS container (or a `moto` S3 server without + Docker), provisions one owner, creates one workbench and writes the client + configuration and environment file that `env:nokv_legacy` and + `env:nokv_authority` read. This entry's stack: NoKV `590d3a4bdc` (the + `v0.11.1` tag; owner built from that commit by the script's `--build`, + SHA-256 `1c468a7b…`), the released `nokv==0.11.1` macOS arm64 wheel (SHA-256 + `e33f318e…`, checked against the release `SHA256SUMS`), etcd 3.7.1, LoopX + `main` at `4bed6ed3d` with a clean tree, Node 22.22.3 (the runtime CI uses for + the Stage 2C jobs). Measured 2026-09-22. +- **Positive rows.** `s0.nokv_live_matrix` and `s2a.nokv_live_qualification` + pass. The qualification report carries 15 checks, all passed, including + `stale_incarnation_fence_rejected` (a raw publication of the generation-1 + envelope fenced on a different incarnation is refused typed) and + `stale_incarnation_fence_left_generation_unchanged` (generation stays 1 and + the workbench identity is unchanged); final generation 3, SDK `0.11.1`, API + `1`. The complete 23-row ladder on the same stack: 22 pass, + `s2b.postgresql_conformance_live` unverified (no PostgreSQL configured), + `s2c2.sustained_parity_soak` pending as declared; privacy scan 0 violations. + The `moto` fallback stack passes `s2a` with the same 15 checks. +- **Negative pairing on the same stack.** With the released `nokv==0.11.0` + wheel, `s0` still passes (the matrix does not pin the SDK) and `s2a` fails + typed: the probe reports `nokv_transport_protocol_failed` because the helper + refuses the wheel at admission, before any client is constructed; no + publication reached the owner. +- **A macOS-only ladder condition, recorded because it cost a run.** Under + macOS's default `TMPDIR` (a `/var/folders/…` symlink) all eleven `s2c2` rows + fail with `shadow_management_state_invalid`: the TypeScript side digests the + real path of the runtime root (`realpathSync`) while the Python side digests + `os.path.abspath`, so the two `source_root_digest` values differ. With a + symlink-free `TMPDIR` the rows pass under Node 22.22.3 and Node 26 alike; + Linux CI has no such symlink and is unaffected. This is a LoopX condition, + not a NoKV one, and this entry only records it. +- **What this does not establish.** The incarnation rotation itself is not + exercised here: NoKV exposes no client-side retire or recreate verb, so the + probe proves only that a stale fence is refused against the current + incarnation; the rotation is covered by NoKV's executor tests in + NoKV-Lab/NoKV#514. One owner, one node, one workbench: nothing about + availability, failover, restart or restore recovery, capacity (see the + 2026-09-19 entry) or authenticated transport. The profile hold stays until + the maintainer decides; the RFC header and Appendix A still say 0.11.0 while + the helper, ladder and probe pin 0.11.1, an inconsistency this entry records + and does not resolve. diff --git a/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-22-nokv-0-11-1-incarnation-fence-live-qualification.zh-CN.md b/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-22-nokv-0-11-1-incarnation-fence-live-qualification.zh-CN.md new file mode 100644 index 0000000000..e4d178e1ae --- /dev/null +++ b/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-22-nokv-0-11-1-incarnation-fence-live-qualification.zh-CN.md @@ -0,0 +1,40 @@ +# NoKV 0.11.1 incarnation 围栏在可复现栈上的 live 资格 + +对共享 Goal authority 模型是非规范性的:不移动任何资格 hold,不改任何 RFC 条款。它记录 +[#4774](https://github.com/loopx-project/loopx/pull/4774) 接入的发布围栏在一条命令即可拉起的栈上 +的 live 复测,让 RFC 仍列着的那条 hold 的移除有可引用的记录,而不是某位贡献者的 scratch 目录。 + +- **改动是什么。** #4774(批准的 head `9cffc78be`,2026-09-20 squash 合并为 `be7789fd95`)让每次 + `NoKVAuthorityStore` 发布都携带 `expected_workspace_incarnation_id`,即读取信封时所在的 + incarnation。NoKV 0.11.1 在任何 operation 行、artifact revision 或对象存在之前,把这个围栏与 + `expected_generation` 一起原子校验,并用 typed 的 `WorkspaceIncarnationMismatch` 拒绝过期 + incarnation,helper 将其映射为 `failed/store_identity_mismatch`;helper 钉死 SDK 0.11.1,只接纳 + 显式命名围栏参数并导出该 typed 拒绝的 wheel。批准评审保留了 profile hold + `atomic_workspace_incarnation_publication_fence` 与附录 A 的措辞,理由是 maintainer 没有 live + owner 可以亲自重跑这条会写入的探针。 +- **复测靠什么变得可复现。** NoKV-Lab/NoKV#518 新增 `scripts/workbench/loopx_stage2a_stack.py`:启动一个隔离的 + etcd 成员、一个 digest 固定的 RustFS 容器(无 Docker 时改用 `moto` S3 服务),provision 一个 + owner,创建一个 workbench,并写出 `env:nokv_legacy` 与 `env:nokv_authority` 两个门读取的客户端配置 + 与环境文件。本条目所用的栈:NoKV `590d3a4bdc`(即 `v0.11.1` tag;owner 由脚本 `--build` 从该提交 + 构建,SHA-256 `1c468a7b…`),已发布的 `nokv==0.11.1` macOS arm64 wheel(SHA-256 `e33f318e…`, + 已对照 release 的 `SHA256SUMS` 校验),etcd 3.7.1,LoopX `main` `4bed6ed3d` 干净树,Node 22.22.3 + (CI 跑 Stage 2C 作业所用的运行时)。测量日期 2026-09-22。 +- **正向行。** `s0.nokv_live_matrix` 与 `s2a.nokv_live_qualification` 通过。资格报告含 15 项检查全部 + 通过,包括 `stale_incarnation_fence_rejected`(把 generation-1 的信封以另一个 incarnation 为围栏 + 原样重发,被 typed 拒绝)和 `stale_incarnation_fence_left_generation_unchanged`(generation 仍为 1, + workbench 身份不变);最终 generation 3,SDK `0.11.1`,API `1`。同一栈上完整的 23 行 ladder:22 + pass,`s2b.postgresql_conformance_live` unverified(未配置 PostgreSQL), + `s2c2.sustained_parity_soak` 按声明 pending;隐私扫描 0 命中。`moto` 备选栈同样以 15 项检查通过 `s2a`。 +- **同一栈上的负向配对。** 换成已发布的 `nokv==0.11.0` wheel:`s0` 仍通过(矩阵不钉 SDK),`s2a` + typed 失败:探针报 `nokv_transport_protocol_failed`,因为 helper 在 admission 阶段、构造任何 client + 之前就拒绝了该 wheel;没有任何发布抵达 owner。 +- **一个只在 macOS 出现的 ladder 条件,因为它耗掉了一轮运行所以记下。** 在 macOS 默认的 `TMPDIR` + (`/var/folders/…` 软链接)下,全部 11 行 `s2c2` 以 `shadow_management_state_invalid` 失败:TypeScript + 侧对 runtime root 的真实路径(`realpathSync`)做摘要,Python 侧对 `os.path.abspath` 做摘要,两边的 + `source_root_digest` 不一致。改用无软链接的 `TMPDIR` 后,Node 22.22.3 与 Node 26 下都通过;Linux CI + 没有这个软链接,不受影响。这是 LoopX 侧的条件而非 NoKV 的,本条目只做记录。 +- **本条目没有确立的事。** incarnation 轮转本身没有在这里被演练:NoKV 没有客户端侧的 retire 或 + recreate 动词,探针只能证明过期围栏在当前 incarnation 上被拒绝;轮转由 NoKV-Lab/NoKV#514 的 + executor 测试覆盖。一个 owner、一个节点、一个 workbench:对可用性、故障切换、重启或恢复、容量 + (见 2026-09-19 条目)、认证传输不作任何断言。profile hold 由 maintainer 决定去留;RFC 头部与附录 A + 仍写 0.11.0,而 helper、ladder、探针已钉 0.11.1,本条目记录这一不一致但不解决它。