fix(authority): prevent cold File proofs from starving the shared runtime - #5156
Conversation
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
评审 head:5c83f9b8bae98a0670a4ce49a27aadf31f726731;base:96a3b90f41094bd2ddea7263b9c7ee37371a9c3b。未发现本次有界修复的阻塞问题。
动机
需要修复的是冷 File 历史证明占用共享 Effect 事件循环,使不相关的回执、Todo 规则和 delegation grant 查询也被拖住。热缓存会掩盖问题,交替读取 Goal 又会触发冷证明。这个切片对应既有 shared-authority 验收与恢复审计的延迟核对。它有独立价值,但不代表 D2 容量/soak、默认 provider 切换或整个迁移计划完成。
我用同一份固定字节的 96 笔混合 Todo/lease/decision 历史,在独立真实 server 上对照 base/head:base 的轻请求约等待 1.4 秒,返回时重证明已结束,非独占 oracle 失败;head 约 63 毫秒返回,此时重证明仍在进行,oracle 通过。保持原 10 秒响应预算。这里只证明本机合成负载下的调度改进,不继承作者真实来源快照的耗时,也不宣称正式 p95。
改动思路
既有公共 codec 继续单独拥有 Unicode 排序和 canonical bytes;File journal 拥有完整物理历史证明,File store 拥有锁、缓存和持久化。比较器减少分配,File 在完整交易的校验之间让出事件循环,相同 path/store identity/精确字节摘要的并发读共享正在进行的证明。
只优化比较器仍无法保证 socket 在完整证明之前推进;提高 timeout 会保留阻塞,提前返回局部证明则破坏完整性。当前方案在既有 owner 内解决已复现的问题,没有新增 worker 框架、协议、配置、Python 决策源或第二份权威状态,范围合适。
具体改动
完整检查了 11 个文件:四个运行时代码文件、三个原生回归文件、双语恢复 ledger,以及 self-repair 的 pattern/targeted diagnostics。后两项引导操作员区分冷/热读、调用方成本和共享运行时饥饿,保留不重发不确定写入的边界;它们不是新的机器义务或 provider 激活条件。双语 ledger 保留 #4931/#4224 的资格缺口及 #5144 等已有交付归属,没有用本次测试关闭这些验收。
关键代码讲解
authorityUnicodeCompare直接遍历码点,补充字符仍按两个 UTF-16 code unit 前进。严格前缀的返回数值幅度可能改变,但所有已检索调用方只依赖排序/符号;固定旧实现的排序对照、literal canonical bytes,以及实际 provider 读写对照保留序列化和 revision 语义。FileAuthorityJournal.decode返回 Promise,并在约 8ms 的交易间隔调用setImmediate。它仍检查逐笔状态、revision、cursor、重复 operation,最后核对完整 head 才构造 journal。微任务让步不能让 socket 公平推进,这里使用 macrotask 是正确边界。FileAuthorityStore.readVerified用 path、identity 和 raw digest 绑定 pending proof,完成后才记入既有 verified cache,finally清除自己的进行中项。损坏尾部仍拒绝早期 receipt;失败 Promise 不会成为永久失败缓存。commit/archive 的真实 mutation lock 和 CAS 仍包住异步读、判定和持久化。migrateFileAuthorityStore的 current decode 与fromTransactions均传播await;完整逻辑历史摘要、内容寻址备份、持久化发布和中断重试继续由原 owner 处理,业务读取没有增加 legacy fallback。
测试也有实际价值:Unicode 旧实现对照与固定字节 oracle、并发冷读合并/失败恢复、真实独立 server 的轻请求推进及尾部损坏拒绝。最后的 delegation case 只证明既有 binding 选择能推进,没有把它写成 Host 启动或完整 before-delegate 验收。
对主干的风险
独立验证结果:
- Exact head 完整 TypeScript 套件 3168 passed、30 个可选 PostgreSQL 环境项 skipped,类型检查通过。所需的真实 store/service/归档路径另行运行,未把 skip 当通过。
- 隔离 PostgreSQL 16.15:store 套件 head/base 各 293 passed;service 1 passed,跨 provider archive 4 passed,这些独立套件无跳过。
- 两份固定历史分别运行 39 个 real RPC/File base/head 对照场景,完整响应一致,包含 omitted/empty/schema 错误优先级、缺失对象、不同分页、并发 CAS、独立持久化回读、尾部损坏、identity fence、修复后重试和 archive replay。共同有效 Unicode fixture 另有 8 个 PostgreSQL 对照场景,72 笔完整逻辑历史与 File 三臂一致。跨 provider 只区分其本地 revision hash,不消除状态、回执、事件、顺序或诊断差异。
- 真实 Python authority journal/SQLite CLI:8 passed。选中的 premerge 19 项及 3 项 diff hygiene 通过,公共/私有边界扫描通过,三个 commit 均有 DCO sign-off。
初次验证有环境设置错误,记录未删除:多个 PostgreSQL 套件共用数据库造成 schema/identity 冲突,随后按既有 workflow 使用独立数据库;包含孤立 surrogate 的跨 provider fixture 被 PostgreSQL JSONB 拒绝,base/head 相同,正例改用双方支持的 Unicode scalar fixture,原拒绝保留。初次 premerge 有嵌套 60 秒超时;对照又暴露我把临时目录放在 checkout 内,使“非 Git 目录”样例继承父仓库并错误运行缺失脚本。改用仓库外私有临时目录后完整重跑通过,没有改源代码、预算或断言。
剩余风险明确:JSON parse、单笔巨大交易和其他同步 handler 仍不能被这次让步抢占,多种不同冷证明也没有获得通用 worker 隔离。正式容量、长时间 soak、其他平台和 Host 执行生命周期未在本次验证。现有 CLI/provider 入口、schema、selector、timeout、权限和默认值保持原合同;没有新增设置或操作流程需要 frontend/Lark 配置伴随改动。
我的整体评价
APPROVE。完整历史安全边界和后续重试/CAS/readback 得到独立验证,真实共享运行时的推进效果也能让旧版本 oracle 失败、修复版本通过。未来维护方向的有界检查已落实为减少比较器分配和重复证明;继续加入通用调度/worker 结构会扩大当前切片,留在既有性能验收内处理更合适。
这是一个可以独立审查、回退的运行时增量;#4931、正式 D2 资格及后续 activation/default 切换仍归原 owner。合并交由维护者,批准不授予自合并或默认 provider 切换权限。本次按 Goal 的 wait_for_ci=false 契约执行本地验证,没有查询或等待远端 CI。
English verdict: APPROVE - 5c83f9b. Complete File history proof and canonical bytes remain intact while unrelated real RPCs progress during cold verification; fixed-byte baseline fails and head passes the fairness oracle. Independently validated full TS/typecheck, real PostgreSQL, paired RPC/provider readback, CLI journeys and premerge. Capacity/soak, huge single-transaction preemption and Host execution remain outside this bounded repair; maintainer merge required.
|
Merge-readiness readback for 合并资格与代码评审结论分别记录:当前 head 的 APPROVE 有效,但分支落后于 main,readiness 仍为 false。请更新后对新 head 重新资格验证;本次未合并,也不把旧 head 的批准或质量回执迁移给新提交。 |
Cold File history verification can monopolize the shared Effect runtime: a small ownership decision or ping waits behind another Goal's proof and hits its unchanged 10-second response budget. This repair preserves every historical revision and receipt while allowing independent requests to progress. Related to #4574 and the shared-authority D2/D3 / TS migration work.
Validation: full TypeScript suite 3,168 passed / 30 environment-gated skips; TypeScript typecheck; 601 File/SQLite/state-log tests; 293 real isolated PostgreSQL 16.15 store tests; 28 archive/crash/cross-provider tests; focused codec and runtime regressions. The no-yield mutation fails the same socket regression. Public/private scan, 19 selected premerge checks and 3 diff checks passed; no manual holds. Exact-head quality receipt is valid/pass (one documented efficiency advisory, no blockers).
Fixed, detached real File snapshots took about 9.5–10.5 seconds on the baseline and 2.9 seconds on the candidate for cold verification. Concurrent lightweight requests fell from near/over the original 10-second budget to 18–52 ms. These are local observations, not formal p95/capacity qualification; no active Goal, selector or production service was changed.
The improvement does not implement worker isolation or make one huge transaction/JSON parse preemptible. SQLite retained replay and its formal qualification remain separate (#4931/#4224). No new format, timeout, command, setting, Python decision owner or UI flow is introduced. CLI and other callers continue using the same runtime/provider contracts; no frontend/Lark configuration companion is needed. Future-facing pass: consolidate identical in-flight proofs at the existing File owner, without adding a generic cache/framework. Maintainer merge required.
The final test-only follow-up also qualifies delegation grant selection during cold reads: 10 targeted tests passed and the updated no-yield mutation failed. It does not launch a Host or certify the full before-delegate journey. The full TS/provider results above validated the identical production subtree at
345b05868; final production code is unchanged.Additional unchanged-head qualification of
todo.succession.project: the actual RPC used the caller's internedcontext_field_setsshape with 4,002 synthetic Todo facts and a ~1 MB response during cold reads of the same detached File snapshots. The diagnostic harness was corrected: expiry now raises before send/every receive, and a completion timestamp after JSON parsing and semantic assertions must remain inside 10 seconds. The earlier minimum-timeout clamp was not a strict deadline; those old metrics are retained as historical observations, not strict-budget qualification. Three synthetic counterexamples show the old guard accepted late results and the corrected guard rejects them.Both sides were rerun from private Git exports pinned to exact commits with recorded archive/entry hashes. Baseline
96a3b90f4cold/alternating/return succession reads took 9.513/9.993/9.560 seconds; this corrected rerun did not time out. Head5c83f9b8btook 79/52/76 ms (warm 27 ms), with full cardinality, successor and gap assertions. This qualifies the reproduced interference case, not attribution of a particular production timeout, arbitrary graph capacity, scheduler ACK recovery or notification-error diagnosis. No extra runtime implementation or uncertain request replay.