Skip to content

fix(recovery): bind archive scans to their compressed byte witness - #7220

Merged
huangruiteng merged 1 commit into
mainfrom
codex/recovery-archive-byte-witness
Oct 24, 2026
Merged

huangruiteng merged 1 commit into
mainfrom
codex/recovery-archive-byte-witness

Conversation

@hhyykk

@hhyykk hhyykk commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

Goal And Delivered Outcome

Backup verification could hash archive A, parse different compressed bytes B, then accept A again after an ABA restore before its final hash. Both preview and execute reproduce this with an ordinary producer archive. The regression changes gzip identity while retaining valid tar members; this is an input-consistency defect, not evidence of execution authority or remote compromise.

Bind each parse to the compressed bytes it actually reads. A private bounded IO adapter records their SHA-256 and count under the existing gzip/tar stream. The first witness must match preflight; the copied scan's witness participates in the existing observation comparison. Keep the final source hash, early wrong-digest refusal, capacity/metadata guards and inert publication rules.

Source: docs/architecture/rfcs/complete-state-recovery-v0.md, M1 and the immutable recovery-set decision, at main 659c1fd441abf5bd9171f22d9a84981497856a63. Intended base: main.

Author Declaration

Written by: model_agent — OpenAI Codex, GPT-6 family.

Accepted criterion Disposition Evidence
One digest-bound immutable verification unit implemented Preview/execute reject the actual changed stream even if the original file is later restored
Archive/Host adapter supplies observed bytes; typed owners keep decisions implemented Streaming witness stays inside the existing archive IO module; native operations and manifests are unchanged
Bounded, inert verification and inspection retained and exercised Compressed-byte bound, existing path/PAX/sparse/expansion cases, real File/SQLite inspection, no output publication on rejection

The existing module's read seam now hides compressed identity as well as expansion checks. Buffering keeps witness updates bounded; the caller-owned archive handle remains available for subsequent passes. No new operation, persisted field, store, capability, dependency or authority is added. The public CLI/HTTP entrypoints keep their interfaces.

Scope And Continuation

Complete for the scanned-input witness. The paired RFC checkpoint states this bounded M1 behavior. Reverting code requires no state conversion. Capture consistency M2, controlled reactivation M3 and broader platform/provider qualification retain their existing gates. No live recovery is performed.

Checked 43 open PRs and their changed paths. Only the shared repair-pattern table overlaps #7199, #7196 and #3412; their actual patches address admission timers, context delivery or settlement effects. None changes archive byte witnessing or adds this diagnostic pattern.

Validation

  • Tested revision: 78b008a. Linux, CPython 3.11.6, Node 26.12.1.
  • Run state: finished. Inputs: synthetic/public fixtures only. Full 64-Python/8-native qualification and the immutable cost comparison used the pinned initial base. The final rebase onto main 19ccb6328 leaves all five patch files byte-identical; six targeted recovery cases and all eight native cases were rerun there.
Check Result
Regression sensitivity Both baseline preview/execute cases fail the independently stated refusal invariant; the fixed verifier rejects before publishing a destination
Python recovery suite 64 passed; real producer/CLI/HTTP paths, File/SQLite, hardlinks, unavailable original sources, saved audit integrity, unsafe tar inputs, source-byte races and the compressed budget
Native recovery owner 8 passed
Static Ruff; configured mypy (17 files) and strict changed-module mypy (1 file); semantic diff advisory; RFC lifecycle/bilingual checks; whitespace
Repository gate Initial and final quick premerge passed; final gate: 6 direct + 4 selected checks, including semantic vocabulary and changed-surface public-boundary checks.
Guards clean-code-guard, test-guard and docs-guard completed

Complete-command Cost And Parity

This adds streaming hash work. The following results are retained costs, not a throughput improvement:

Frozen 8 MiB payload, complete CLI Base median / p95 Candidate median / p95
Preview 1029 / 1361 ms 1085 / 1487 ms
Execute, owner inspection and saved-audit readback 1665 / 1795 ms 1740 / 2005 ms

Ten measured samples per arm/workload, alternating base/head/head/base; one warmup block excluded, fresh Python processes and warm native runtime. The baseline restores only the original IO module from the pinned main; other source and the immutable archive pair are identical. No tests/builds overlap this run.

Full public results match after normalizing only destination, observation time, measured durations and the resulting audit seal. Each original seal is independently verified before normalization. Recovery/archive/manifest identities, component state, diagnostics and execution denial remain compared. Representative cost rose about 56/75 ms at the median and 126/210 ms at p95; the 8 MiB case does not qualify worst-case capacity or supported-platform performance.

Full repository CI, installed packages, browser journeys, live recovery and compound worst-case qualification have not been run here. No model call, provider activation, Goal mutation or external delivery is started by this proposal.

Frontend / Visual Evidence

Existing backup inspection entry and error path are reused. Public schemas, layout and controls are unchanged. Actual CLI/loopback HTTP recovery coverage is in the recovery suite; packaged-browser capture is not rerun for this archive IO repair.

Boundary Checklist

  • Explicit scoped product/test paths and paired public RFC text only; no private archives, raw logs, credentials or local artifact paths.
  • DCO sign-off and main base.
  • Author proposal for review; no merge, release or activation claim.

Signed-off-by: aihop <4408344+hhyykk@users.noreply.github.com>

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; effort=max

动机

需要核验备份、但不能让恢复副本取得执行权限的本地操作者。旧路径先校验归档 A,却可能解析中途被换成的 B;若随后恢复 A,最终 hash 仍可能接受。新路径为解析器实际读取的压缩字节生成摘要与字节数,遇到这种替换就在发布前拒绝。同一真实生产器归档在 File/SQLite 的预览与执行中均拒绝 A→B→A 替换,普通备份仍能生成内容一致、无执行权限的可读审计。这次不恢复当前身份、不激活 Goal,也不证明 M2 捕获一致性或 M3 完整恢复及长期收益。

改动思路

压缩字节见证属于现有归档 IO 边界;清单、恢复审计和权限判断仍由原 TypeScript owner 执行。无需新 store、操作协议或用户确认轮次。当前 PR 的完整边界是实际扫描输入与预检身份一致,并在复制发布前再次比较;不扩展到受控重新激活。这里的见证是摘要与字节数,由实际输入流推导,既不是用户新声明,也不是执行凭据。旧的最后一次 hash 只能证明最后看到 A,不能证明解析阶段也看到 A;因此只增加一次末次重读无法修复问题。现有压缩、展开、metadata 与路径限制继续在读取和复制时生效,失败仍由原调用者处理。

输入 原路径 当前 head
普通有效归档 可预览、可生成 inert 审计 完整结果保持
校验 A、解析 B、随后恢复 A 可能接受 在发布前拒绝实际输入不一致
一开始 digest 错误 在 tar 解析前拒绝 保留同一拒绝顺序

具体改动

评审 head:78b008a8aefc26d70ead4e56ca274d37f3f84147,独立基线 19ccb632845ceae49ca6463ef26e868e2dcc1a45。先读取原规范 docs/architecture/rfcs/complete-state-recovery-v0.md,再读实现;规范检查点的新增文字不充当自身验收。逐项映射:Archive and manifest bind exactly 已实现;Extraction is confined 保留并执行;M1 stays inert 保留并读回;v0 uncertainty is honest 保留为 held、不授予激活。M2/M3 与本次有界修复分开验收。

关键代码讲解

  • _ArchiveInput 在每次向 gzip 交付压缩字节时累计 SHA-256 与计数;超过既有压缩上限直接拒绝。BufferedReader 只负责有界批量读取,没有复制成另一份完整归档,也不接管 caller 的文件句柄。
  • _scan 继续走原安全 tar 遍历、gzip EOF 与链接处理,返回实际读入身份;复制扫描把身份和原 member 观察一起比较。关闭包装流不会使后续原句柄重读失效。
  • verify_state_backup 在首轮扫描后、manifest/owner 审计前比较预检身份;执行分支继续要求复制观察一致及末次 hash 一致,保持 staging 清理和不覆盖发布。

全部五条改动路径都在范围内:运行时 IO、保留原断言的回归、英中 RFC 同步,以及按需加载的修复模式行。该行只解释已证实的诊断,不增加后台自动恢复、配额义务或权限。未引入公共 schema 或新的共享状态词汇;复用现有错误及恢复 owner。

对主干的风险

独立源码验证:原恢复套件 64 通过,原 native recovery 8 通过。同一当前测试 oracle 对不可变基线生产源码为 61 通过、3 失败,恰是两条 A→B→A 预览/执行拒绝和压缩读取预算;没有修改原断言使其通过。另从真实 producer 创建相同 File/SQLite 归档,执行完整公共 CLI 预览、执行和替换负例:基线错误接受,当前 head 返回 recovery_input_changed,不发布 destination 或残留 staging。只改 gzip mtime 的 B 仍含有效 tar 内容,因此这是输入一致性缺陷,不是远程入侵或执行权限证明。

普通 CLI 结果、组件、诊断和权限字段保持一致;仅归一化实际耗时、观察时刻及由它们产生的审计 seal,并先独立验证每份原 seal。实际 JSON 保存结果与返回值逐项读回;已有套件覆盖 loopback HTTP、原源不可用和 File/SQLite 历史审计。当前快速 premerge 6 direct +4 selected 全过。仓库 CI 按契约不查询、不等待。额外 hash/缓冲会有代价,不声明吞吐提升;复合最大容量、其他平台、安装包和 live recovery 没有被本次资格覆盖。

我的整体评价

APPROVE。这是一项完整、可回退的现有输入边界修复:真实消费者不再把另一轮读到的字节冒认为已校验输入,现有合法备份、历史状态和无执行权限约束保持。long_horizon 判断为 preserved,并非已证明模型采用或长期净收益;user_experience 在准确失败与读回上改善,原调用流程没有增加确认轮次。CLI 与既有 HTTP/Settings 调用共用原核验入口;本次没有改变页面布局、控件或渲染数据契约,因此视觉评审不适用。未重新验收安装包、浏览器整页或实际用户采用;本次无渲染改动。代码体量与这个可复现缺陷相称;更大的恢复服务或新存储不必要。当前 PR 的完整边界是实际扫描输入与预检身份一致,并在复制发布前再次比较;不扩展到受控重新激活。本结论不执行合并或启用恢复。

English verdict: APPROVE — 78b008a8aefc26d70ead4e56ca274d37f3f84147 binds both scans to their actually consumed compressed bytes. Independent real File/SQLite CLI ABA cases now refuse before publication; ordinary output/audit parity,64 Python tests,8 native tests and6+4 quick checks pass. Compound limits, broader platforms and installed/live recovery remain unqualified.

@huangruiteng
huangruiteng merged commit ad6d2f6 into main Oct 24, 2026
29 of 40 checks passed
@huangruiteng
huangruiteng deleted the codex/recovery-archive-byte-witness branch October 24, 2026 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants