fix(authority): restore SQLite replay after streaming verification refactor - #5215
Conversation
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Exact-head self-review: APPROVE for maintainer review. The replay callback verifies the retained row before comparing the full incoming projection/events/receipts. Exact retries preserve the original revision/cursor; changed intent conflicts. Missing or corrupt retained history remains rejected and no new write is performed on replay.
Validation: 322 real-SQLite tests passed across sqlite_authority_store.test.ts and sqlite_authority_bounded_profile.test.ts, no skips; complete control-plane typecheck passed; git diff check passed. The existing historical replay test fails on main 71525ab with provider_transaction_failed and passes here. Disposable databases only. PostgreSQL is untouched; the equivalent risk-based set is the real SQLite suites plus full TS check.
Future-facing pass: retired the obsolete return-value call; reused the streaming verifier without a compatibility adapter or second verifier. No persisted protocol change. Maintainer merge required.
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
详细中文评审
Review head: d32e35d2b2bcaf597ae498c4291fbf74f0045cb4。独立比较基线:71525ab908e24dc9f3e4ace922d1d2ef3437ce4d。完整检查单文件 +15/-9 变更,未以作者的短评或测试声明代替验证。
动机
SQLite verifier 已迁为 streaming callback,但旧 operation replay 调用点仍将 void 返回值当作 window 读取,导致历史 operation 的精确重试失败。本修复恢复既有 direct-provider replay 合同:原请求返回原 receipt,不因当前 CAS 已前进而重跑或覆盖后续工作。这关闭的是一个可复现恢复缺陷,提升持续推进及调用者恢复体验,不表示 SQLite 整体性能或资格里程碑已完成。
改动思路
调用者复用原 SqliteAuthorityStore 的 verifiedRange,而不是另建重放判定或信任存储中的 digest。BEGIN IMMEDIATE 写快照内加载包含目标 cursor 的 checkpoint/delta 窗口,逐条验证链、状态、events 和 receipts;只有回调提供经过验证的目标 transaction 与 store identity 后,才计算完整请求摘要。完全相同返回原 cursor/revision;不同 intent 保留 operation_id_exists;新 operation 仍走原 CAS。成功重放 ROLLBACK 本次无写事务,不恢复旧 head,不再次发出事件或 receipt。
具体改动
唯一生产变更位于 commitAuthority 的 existing operation 分支:新增局部 verified 和 replayResult,改为同步 callback 消费原 verifier,保留未找到目标 row 时的 protocol refusal,移除对不存在的 transactions/identity 返回值的访问。没有修改 schema、checkpoint 间隔、delta 编码、容量上限、数据库选择、provider activation、CLI/API 输入或持久化 receipt 格式;也没有增加 Python 决策源、兼容 wrapper、测试专用业务分支或网络依赖。readReceipt、scanCommitted 与 normal commit 路径周边代码一起检查了,不只查看修改行。
关键代码讲解
- commitAuthority:428:在实际写事务中查原 operation。完整 intent 匹配时回原 receipt;不同 intent 返回 conflict;新 operation 的 stale CAS 不获豁免。
- verifiedRange:306:继续使用有界 retained window 与同步 consumer,避免重新物化整段 history。回调接口是此次应复用的既有 owner。
- verifyCommitRow:250:从状态链和真实 retained transaction 重算验证,旧 digest 本身不是完整性证明。这个未改的前置验证保证 forged events/receipts 不能被幂等性旁路。
对主干的风险
没有发现阻塞性问题。最大风险是把历史精确 replay 错当成新的 write authority,或只匹配 operation id 便吞掉改变的 intent;实际代码仍验证 projection、events、receipts,并保留 store identity、完整性和新操作 CAS 边界。真实临时 SQLite 数据库上的 322 项 store/bounded-profile 测试通过,含并发、进程崩溃、历史重放、损坏拒绝及后续 head 保留;control-plane typecheck 也通过。
独立生产入口 probe 使用 Node 24.21.0 / SQLite 3.53.4,先写 A、再写 B、关闭并重新打开 Store:相同 A 在 null/current CAS 及 key-order 变化下返回 cursor 1,B 的 head 和所有 receipts/events 完整保持;仅改变 projection/events/receipts 的请求被拒绝。错误 selected identity、伪造 retained event、新 operation stale CAS 都没有被放行。总计 26 条完整观察,基线有 10 条 SQLite replay oracle 违例,head 为零;默认 File provider 的 12 条完整观察一致。没有向 active Goal、真实 registry 或生产数据库做测试写入。
语义与 CI 对齐
本次是复用既有 replay 词汇和 typed provider contract,结果是 machine-enforced applied/conflict/failed,不是建议。SQLite 的显式 opt-in、File 默认路径、跨宿主限制和 caller 权限不变;安装或发现该 provider 不等于启用它。改动不涉及 PostgreSQL 实现或 migration,因此这里验证真实 SQLite,而不把 mock、其他 provider 或跳过的 PostgreSQL 测试冒充相关资格。
基线的历史 replay 原生筛选测试复现 66 passed / 2 failed,head 对应完整 322 项通过;基线三个 typecheck 诊断正是本调用点的 void/参数错误,head 已消除。risk-based premerge 的 3 项直接检查与 13 项选中检查通过,但 maintainability ratchet 标记一个已继承 advisory:status facade 119 个 re-export 超过 117。该故障单独按同一基线命令验证,涉及未改的 status owner,不能归责于本修复,也不能以 advisory/绿色 gate 替代维护它。公开边界检查和 diff check 通过。没有获取或等待 GitHub CI。
我的整体评价
持续推进与用户体验均得到明确改善:同一承诺能够读回,不出现原 operation 反复报 transport-style failure;改变 intent 的拒绝仍可通过新 operation 与正确 CAS 恢复正常提交。代码量与严重性相称,已应用的有界未来向整理就是让 replay 使用现有 streaming owner,避免保留第二套 window 判定;无需再加抽象。结论 APPROVE,保留作者 PR 的 COMMENTED fallback。仅认可该 exact head 的缺陷修复,不声明全库无遗留故障、不自动合并、不提升 provider activation 或更广 qualification。
English verdict: APPROVE - head d32e35d. Reuses the existing streaming verifier to restore exact historical replay without changing current head, CAS, integrity or opt-in authority. Real SQLite 322 tests, typecheck and independent base/head replay/corruption/default-File observations pass. An independently reproduced inherited status-facade advisory is unrelated; no merge or broader qualification claimed.
|
Fresh self-review at |
Problem and result
The streaming retained-window refactor and operation-replay change merged with incompatible call sites: commitAuthority still expected verifiedRange to return transactions and identity. Retrying a previously committed operation returned provider_transaction_failed, and the control-plane typecheck failed.
Consume the verified transaction through the current callback API and compare the complete incoming intent inside that callback. An exact replay returns the original cursor/revision after rollback; changed intent remains operation_id_exists, and corrupt or missing history remains rejected. No compatibility wrapper, history materialization or alternate verifier is added.
Validation
The existing real-SQLite historical-replay conformance test fails on main 71525ab and passes with this change. Control-plane typecheck passes. Real SQLite store and bounded-profile suites cover replay, intent changes, corrupt retained history, receipt recovery and window bounds; full results are recorded in the review comment. Tests use disposable databases; no active Goal store was mutated. PostgreSQL is unchanged.
This repairs the existing typed authority boundary consumed by the App/coordination roadmap; no new protocol or roadmap track. The future-facing pass keeps replay on the streaming verifier instead of restoring its old return API. Maintainer merge required.