Skip to content

Commit 1d32a5d

Browse files
committed
docs(rfc): record quota void migration receipt
Signed-off-by: hyk <4408344+hhyykk@users.noreply.github.com>
1 parent c85e702 commit 1d32a5d

2 files changed

Lines changed: 65 additions & 11 deletions

File tree

‎docs/architecture/rfcs/typescript-control-plane-migration-v0.md‎

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ choice is now implemented rather than hypothetical.
159159
| Scheduler durable state ([#3440](https://github.com/huangruiteng/loopx/pull/3440)) | State normalization, persistence, replay, and one coarse transition are TS-owned | The Python compatibility path still pays a cross-runtime transport tax |
160160
| Scheduler heartbeat/state transaction | TypeScript owns receipt freshness, ACK and host-failure validation, state construction, failure-cache transitions, replay/CAS fencing, atomic writes, and the public JSON/Markdown projection | Generated, receipt-bound host follow-up runs through the native TS CLI; Python remains only for unbound/manual compatibility calls and external host mutation |
161161
| Quota spend commit transaction | TypeScript owns final spend-transition validation, typed event construction, effect replay/CAS fencing, crash repair, and the JSON/Markdown/index write set | Python still projects `should-run` and settlement readback facts, and holds the legacy cross-writer index lock until the CLI/index writers move in-process |
162+
| Quota void commit transaction | TypeScript owns spend-target resolution, before/after reduction, canonical correction construction, effect replay/index CAS, prepared-receipt repair, and the JSON/Markdown/index write set | Python retains `should-run` facts, clock/effect identity, the legacy cross-writer index lock, one transport call, and compatibility entry points |
162163
| Quota monitor-poll commit transaction | TypeScript owns monitor admission revalidation, target/event/result construction, effect replay/index CAS, provider intent, and repairable JSON/Markdown/index persistence | Python projects compact `should-run` facts, invokes the real Todo provider between at most two reductions, reloads legacy status, and holds the cross-writer index lock |
163164
| Runtime decoders ([#3443](https://github.com/huangruiteng/loopx/pull/3443)) | Stable primitive decoding has one small shared module; domain decoders remain local | No larger schema framework is justified |
164165
| Transaction payoff ([#3464](https://github.com/huangruiteng/loopx/pull/3464), [#3481](https://github.com/huangruiteng/loopx/pull/3481), and Todo completion) | Turn settlement, quota delivery routing, and Todo completion each cross one coarse TS boundary; the Todo transaction owns identity, replay fencing, validation planning/result reduction, continuation/recovery, and completion metadata | Python still executes explicitly external providers and materializes legacy Markdown/event results; other domains still need their own bounded cutovers |
@@ -242,7 +243,7 @@ domains would now increase total complexity.
242243

243244
Select by deletion leverage and runtime traffic, not by ease of translation.
244245
The shipped Turn settlement, quota delivery-routing, Todo-completion,
245-
scheduler-heartbeat, quota-spend commit, and task-lease acquire cutovers
246+
scheduler-heartbeat, quota-spend commit, quota-void commit, and task-lease acquire cutovers
246247
establish the pattern.
247248
Subsequent candidates must name a remaining transaction and its deletion
248249
leverage; remaining quota settlement readback is eligible only when it can
@@ -294,6 +295,18 @@ shipped Stage 2B cutovers are in place:
294295
Python retains `should-run`/settlement fact projection plus one coarse
295296
transport call and the legacy kernel index lock; it no longer constructs or
296297
writes the spend event.
298+
- Quota void commit: TypeScript finds the referenced spend under the mutation
299+
lock, reduces the before/after accounting decision, constructs the canonical
300+
correction, and commits its JSON, Markdown, index row, and prepared receipt
301+
through the closed spend/void accounting-artifact kernel. Same-effect retry
302+
replays or repairs one transaction; a fresh CLI invocation remains a fresh
303+
effect and therefore preserves the existing ability to append another
304+
correction for the same spend target. Malformed index rows now fail closed
305+
instead of being skipped. Void artifact names include an effect digest and
306+
JSONL rows use compact JSON; public payload semantics remain stable. The
307+
shared kernel also validates persisted receipt/path identity for spend
308+
recovery. Python retains `should-run` facts, UUID/clock ownership, one coarse
309+
transport call, and the legacy cross-writer index lock.
297310
- Local task-lease lifecycle: native TypeScript transactions now own acquire,
298311
renew, transfer, release, terminal verification, holder verification, and
299312
fence close. They own boundary decode, handoff and owner/Todo eligibility,
@@ -328,11 +341,13 @@ shipped Stage 2B cutovers are in place:
328341
durability checks. Invalid identities stop before the provider, while a
329342
crash/retry after the provider re-enters its same-key idempotent path.
330343

331-
The quota-spend cutover removes the Python spend-event builder and three-file
332-
writer. Its bounded facade exits when the quota CLI and remaining run-index
333-
writers execute the transaction in-process; until then it supplies compact
334-
projection facts and shares the legacy Python index lock with unmigrated
335-
writers. The Todo cutover removes the Python state-evaluation dataclass, local identity
344+
The quota-accounting cutovers remove the Python spend and void event builders
345+
and their three-file writers. Their bounded facades exit when quota decision
346+
and the top-level CLI execute in-process TypeScript, all run-index writers use
347+
the native lock, and the legacy Python void API compatibility window closes.
348+
Until then Python supplies compact projection facts, clock/effect identity,
349+
result validation, and the shared legacy index lock. The Todo cutover removes
350+
the Python state-evaluation dataclass, local identity
336351
projection, replay helper, and public runtime handlers for those implementation
337352
leaves. The remaining Python Todo facade owns transport, external command
338353
execution, source compare-and-swap, legacy response projection, and the actual
@@ -359,6 +374,19 @@ retiring a lock. This is not an exactly-once guarantee for a timed-out handler
359374
that is still executing concurrently inside the same Node process; callers must
360375
not start a second independent operation while that handler may still be live.
361376

377+
#### Quota void commit migration economics
378+
379+
| Field | Receipt |
380+
| --- | --- |
381+
| Canonical owner | Before: Python `slot_accounting.py` owned spend-target lookup, correction reduction, event/result construction, artifact allocation, and JSON/Markdown/index persistence. After: versioned TypeScript `quota.void.commit` owns those semantics plus effect fencing, index CAS, receipts, replay, and repair through the closed spend/void accounting kernel. |
382+
| Legacy semantic code deleted | 212 Python product LOC covering the prior void lookup, transition, event/projection, path-allocation, and JSON/Markdown/index writer path. |
383+
| Bridge code added | 263 Python diff LOC: the 243-line bounded `void_commit.py` transport/compatibility facade plus 20 import, re-export, normalization, and route-wiring lines in `loopx/quota.py` and the legacy `slot_accounting.py` surface. |
384+
| Cross-runtime calls | The public execute and dry-run paths move from zero crossings to one coarse request/response. Exact-effect replay or repair also uses one request/response. Distinct CLI invocations remain distinct effects; the legacy two-step preview-plus-record compatibility surface uses one call per entry point. |
385+
| Product-code net change | Product code is +2,210/−898 LOC, net +1,312. Tests/examples are +1,416/−3, net +1,413; build configuration is +3 and docs are excluded. The production shared kernel is already used by spend and void, replacing 671 lines in `spend_commit.ts` rather than creating a speculative framework. |
386+
| Migration scaffolding | No migration-only worker, parity corpus, or temporary schema framework is added. Native boundary/invariant/replay/CAS/repair tests remain as shipped and persisted contracts; Python bridge tests exit with the compatibility facade. |
387+
| Facade exit | Delete the Python void facade when quota decision and the top-level CLI run in-process TypeScript, all run-index writers use the native lock, and the legacy `build_*void*`/`record_*void*` Python API compatibility window closes. |
388+
| Correctness and performance | Typed-decoder negatives, legacy target compatibility, effect isolation, index CAS, malformed receipts and paths, exact index-row identity, supported duplicate-index repair, concurrent mutation, truncated-tail repair, public CLI behavior, and clean wheel/sdist semantic probes pass. Across 16 cold starts, p50/p95 is 230.88/260.92 ms; 128 warm typed pings are 1.07/1.29 ms and warm void previews are 1.93/2.34 ms. Across 64 durable facade transactions, commit is 30.64/37.49 ms and exact-effect replay is 8.05/9.86 ms. Daemon RSS is 108.38 MiB idle and 109.80 MiB after 256 requests. In 64 interleaved full-CLI pairs, baseline/candidate p50/p95 is 736.51/828.68 versus 779.52/856.49 ms: p95 +27.81 ms (+3.36%). The absolute delta is the measured cost of one new managed-runtime fingerprint/request plus prepared-receipt durability; the percentage stays below the 5% material-regression gate, and Stage 3 removes that crossing. |
389+
362390
#### Task-lease acquire migration economics
363391

364392
| Field | Receipt |

‎docs/architecture/rfcs/typescript-control-plane-migration-v0.zh-CN.md‎

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ replay、receipt 与 settlement。这个架构选择已经落地,不再是假
138138
| Scheduler durable state([#3440](https://github.com/huangruiteng/loopx/pull/3440)) | State normalization、persistence、replay 与一笔粗粒度 transition 由 TS 拥有 | Python compatibility path 仍承担跨 runtime transport 税 |
139139
| Scheduler heartbeat/state transaction | TypeScript 拥有 receipt freshness、ACK 与 host-failure validation、state construction、failure-cache transition、replay/CAS fencing、atomic write,以及 public JSON/Markdown projection | 生成的 receipt-bound host follow-up 直接进入 native TS CLI;Python 只处理 unbound/manual compatibility call 与 external host mutation |
140140
| Quota spend commit transaction | TypeScript 拥有最终 spend transition 校验、typed event 构造、effect replay/CAS fencing、crash repair,以及 JSON/Markdown/index write set | Python 仍投影 `should-run` 与 settlement readback facts,并在 CLI/index writer 进程内迁移前持有 legacy cross-writer index lock |
141+
| Quota void commit transaction | TypeScript 拥有 spend-target resolution、before/after reduction、canonical correction 构造、effect replay/index CAS、prepared-receipt repair,以及 JSON/Markdown/index write set | Python 保留 `should-run` facts、clock/effect identity、legacy cross-writer index lock、一次 transport 与 compatibility entrypoint |
141142
| Quota monitor-poll commit transaction | TypeScript 拥有 monitor admission 复核、target/event/result 构造、effect replay/index CAS、provider intent,以及可修复的 JSON/Markdown/index persistence | Python 投影 compact `should-run` facts,在最多两次 reduction 之间调用真实 Todo provider,刷新 legacy status,并持有 cross-writer index lock |
142143
| Runtime decoder([#3443](https://github.com/huangruiteng/loopx/pull/3443)) | 稳定 primitive decoding 进入一个很小的共享模块;domain decoder 仍留在本地 | 没有理由建设更大的 schema framework |
143144
| Transaction 兑现([#3464](https://github.com/huangruiteng/loopx/pull/3464)、[#3481](https://github.com/huangruiteng/loopx/pull/3481) 与 Todo completion) | Turn settlement、quota delivery routing 与 Todo completion 均只跨一个粗粒度 TS boundary;Todo transaction 拥有 identity、replay fence、validation planning/result reduction、continuation/recovery 与 completion metadata | Python 仍执行显式 external provider,并物化 legacy Markdown/event result;其他 domain 仍需各自的 bounded cutover |
@@ -211,7 +212,7 @@ leaf pattern 会增加总复杂度。
211212

212213
按删除杠杆与 runtime traffic 选切口,而不是按翻译难度选。已经交付的 Turn
213214
settlement、quota delivery routing、Todo completion、scheduler heartbeat、quota
214-
spend commit 与 task-lease acquire cutover 建立了这一模式。后续候选必须明确剩余
215+
spend commit、quota void commit 与 task-lease acquire cutover 建立了这一模式。后续候选必须明确剩余
215216
transaction 及其删除杠杆;剩余 quota settlement readback 只有在能退出或显著收窄
216217
facade,而不是再增加 leaf handler 时才适合迁移。
217218

@@ -253,6 +254,16 @@ window 仍需 differential proof 时才保留 characterization corpus;引入
253254
截断 JSONL 尾行,其他损坏仍然 fail closed。
254255
Python 只保留 `should-run`/settlement fact projection、一次 coarse transport call 与
255256
legacy kernel index lock;它不再构造或写入 spend event。
257+
- Quota void commit:TypeScript 在 mutation lock 内定位被引用的 spend,归约
258+
before/after accounting decision,构造 canonical correction,并通过闭合的
259+
spend/void accounting-artifact kernel 提交 JSON、Markdown、index row 与 prepared
260+
receipt。同一 effect 的 retry 会 replay 或修复同一 transaction;新的 CLI invocation
261+
仍是新的 effect,因此保留对同一 spend target 再追加 correction 的既有行为。
262+
Malformed index row 现在由静默跳过改为 fail closed。Void artifact 文件名加入
263+
effect digest,JSONL row 改用 compact JSON;public payload 语义保持稳定。共享 kernel
264+
同时加固既有 spend recovery 的持久化 receipt/path identity。Python 只保留
265+
`should-run` facts、UUID/clock、一次 coarse transport call 与 legacy cross-writer
266+
index lock。
256267
- 本地 task-lease lifecycle:native TypeScript transaction 现在拥有 acquire、renew、
257268
transfer、release、terminal verification、holder verification 与 fence close。它们拥有
258269
boundary decode、handoff 与 owner/Todo eligibility、同 Todo 与重叠 write scope
@@ -280,10 +291,12 @@ window 仍需 differential proof 时才保留 characterization corpus;引入
280291
compare-and-swap、idempotency 与 lease-file durability check。无效 identity 会在
281292
provider 前停止;provider 后发生 crash/retry 时则重入同 key 的幂等路径。
282293

283-
Quota-spend cutover 删除了 Python spend-event builder 与三文件 writer。它的 bounded
284-
facade 会在 quota CLI 和剩余 run-index writer 进程内执行 transaction 后退出;在此
285-
之前,它只提供 compact projection facts,并与未迁 writer 共享 legacy Python index
286-
lock。Todo cutover 删除了 Python state-evaluation dataclass、local identity projection、
294+
Quota-accounting cutover 删除了 Python spend/void event builder 与三文件 writer。
295+
当 quota decision 与顶层 CLI 在进程内执行 TypeScript、全部 run-index writer 改用
296+
native lock,并且 legacy Python void API compatibility window 结束时,它们的 bounded
297+
facade 即可退出。在此之前,Python 只提供 compact projection facts、clock/effect
298+
identity、result validation 与共享 legacy index lock。Todo cutover 删除了 Python
299+
state-evaluation dataclass、local identity projection、
287300
replay helper,以及这些 implementation leaf 的 public runtime handler。剩余 Python
288301
Todo facade 只拥有 transport、external command execution、source compare-and-swap、
289302
legacy response projection 与实际 Markdown/event write;当 writer 与 CLI 进入 native
@@ -304,6 +317,19 @@ managed Node server PID;stale reclaim 会先取得 token claim,并用抗路
304317
核验后再退役 lock。这不构成“同一 Node 进程内 handler 超时后仍并行执行时”的
305318
exactly-once 保证;原 handler 可能仍存活时,caller 不得启动第二笔独立 operation。
306319

320+
#### Quota void commit 迁移经济账
321+
322+
| 字段 | 回执 |
323+
| --- | --- |
324+
| Canonical owner | 迁移前由 Python `slot_accounting.py` 拥有 spend-target lookup、correction reduction、event/result 构造、artifact 分配及 JSON/Markdown/index persistence。迁移后由版本化 TypeScript `quota.void.commit` 拥有这些语义,并通过闭合的 spend/void accounting kernel 拥有 effect fence、index CAS、receipt、replay 与 repair。 |
325+
| 删除的旧语义代码 | 删除 212 行 Python 产品代码,包括原 void lookup、transition、event/projection、path allocation 与 JSON/Markdown/index writer 路径。 |
326+
| 新增的 bridge 代码 | 新增 263 行 Python diff LOC,其中 243 行是有界的 `void_commit.py` transport/compatibility facade,另有 `loopx/quota.py` 与 legacy `slot_accounting.py` surface 中 20 行 import、re-export、normalization 与 route wiring。 |
327+
| 跨 runtime 调用 | 公开 execute 与 dry-run 路径从零次 crossing 变为一次 coarse request/response。Exact-effect replay 或 repair 也使用一次。不同 CLI invocation 仍是不同 effect;legacy preview 加 record 两步 compatibility surface 的每个 entrypoint 各调用一次。 |
328+
| 产品代码净增减 | 产品代码新增 2,210 行、删除 898 行,净增 1,312 行。Test/example 另计新增 1,416 行、删除 3 行,净增 1,413 行;build configuration 为 +3,docs 不计入。生产共享 kernel 已同时服务 spend 与 void,并替换 `spend_commit.ts` 中 671 行逻辑,不是预留的 speculative framework。 |
329+
| 迁移 scaffolding | 没有新增 migration-only worker、parity corpus 或临时 schema framework。保留 native boundary/invariant/replay/CAS/repair 测试作为已交付和持久化 contract;Python bridge 测试随 compatibility facade 一起退出。 |
330+
| Facade 退出 | 当 quota decision 与顶层 CLI 在进程内执行 TypeScript、全部 run-index writer 使用 native lock,并且 legacy `build_*void*`/`record_*void*` Python API compatibility window 结束时,删除 Python void facade。 |
331+
| 正确性与性能 | Typed-decoder 负例、legacy target compatibility、effect isolation、index CAS、malformed receipt/path、exact index-row identity、受支持的 duplicate-index repair、concurrent mutation、truncated-tail repair、公开 CLI 行为,以及干净 wheel/sdist semantic probe 均通过。16 次 cold start 的 p50/p95 为 230.88/260.92 ms;128 次 warm typed ping 为 1.07/1.29 ms,warm void preview 为 1.93/2.34 ms。64 次 durable facade transaction 中,commit 为 30.64/37.49 ms,exact-effect replay 为 8.05/9.86 ms。Daemon RSS 在 idle 时为 108.38 MiB,256 次请求后为 109.80 MiB。64 对交错 full-CLI 样本中,baseline/candidate p50/p95 为 736.51/828.68 与 779.52/856.49 ms,p95 增量为 27.81 ms(3.36%)。这个绝对增量来自新增的一次 managed-runtime fingerprint/request 与 prepared-receipt durability;百分比低于 5% 物质回退门槛,Stage 3 会删除这次 crossing。 |
332+
307333
#### Task-lease acquire 迁移经济账
308334

309335
| 字段 | 回执 |

0 commit comments

Comments
 (0)