Skip to content

Recover validated Todo creation after lost responses - #5012

Merged
huangruiteng merged 2 commits into
mainfrom
codex/recover-validated-todo-create-5007
Sep 25, 2026
Merged

huangruiteng merged 2 commits into
mainfrom
codex/recover-validated-todo-create-5007

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Goal And Delivered Outcome

A validated Todo could commit before its private validator was saved, leaving the Goal's Markdown projection unusable after a timeout. Prepare immutable private content before create/revision dispatch, then let the canonical digest select it. Projection and completion share the same strict reader.

todo add --operation-id now reuses the existing TS receipt across lost responses and later Todo edits; identity no longer depends on the current Todo count. Historical create retries cannot revert a newer validator. Closes #5007. Base: main.

Scope And Continuation

Complete for local File/SQLite publication and exact create recovery. TS still owns admission, CAS and receipts; Python owns private command transport. Existing sidecars remain compatible. Rejected requests can retain unreferenced private blobs; no automatic garbage collection or cross-host private-command distribution is introduced. Provider defaults and D1–D3 remain unchanged. The shared-authority RFC ledger and caller contract record this boundary.

A small companion typing correction narrows an already runtime-checked projection object, restoring the repository's configured mypy gate without changing behavior.

Validation

  • Tested revision: 965a3ea81 (220 focused tests before rebase; 115 recovery/CLI tests rerun on this head after resolving the upstream CLI option addition).
  • Run state: finished.
  • Input classes: synthetic.
Check kind Result Public-safe evidence / limitation
integration passed 220 tests across validated create recovery, local authority, projection recovery, completion validation, CLI diagnostics and operation receipt suites.
real_entrypoint passed A child process exits immediately after the real provider commit; another process rebuilds Markdown and retries through public CLI with no duplicate Todo. File and SQLite arms pass.
real_backend passed Disposable real File/SQLite stores; no active Goal was promoted or modified.
regression_parity failed Remote packaged browser smoke times out at typed-actions.mjs:587 waiting for the same empty-state text on PR run and main baseline run. This is a confirmed inherited failure, not a passing merge gate.
static passed Configured uv run --extra test mypy (23 files), changed-path Ruff, docs governance, public boundary scan and diff whitespace check.

Coverage includes corrupt selected content, foreign Goal identity, rejected requests, dry-run, preparation failure, validator revision response loss, and historical replay after newer edits. An exploratory strict mypy invocation outside the configured scope reported the same 4,096 diagnostics on base and the pre-refinement head; this is not reported as passing full-repository typing. The configured gate passes. Quality receipt: cqr_ef00a20001b4ce3c8edb. CI remains the merge gate.

Frontend / Visual Evidence

  • UI impact: none. Existing create/projection/completion facades are shared by callers; the added retry selector belongs to CLI automation. No frontend editor or display contract changes.
  • Before / After / viewports: N/A.
  • Source data: synthetic.
  • Attention review: actionable ambiguous-operation identity replaces an unaddressable timeout; no additional visual surface.

Shared-authority RFC fixture impact

No fixture schema, authority format, provider routing or promotion change. The added regression fixture exercises real File/SQLite publication and recovery. PostgreSQL private-command distribution and live migration are not claimed.

Boundary Checklist

  • Public-safe code, docs and synthetic fixtures only; no credentials, private state or raw logs.
  • DCO-signed, scoped commits; no duplicate benchmark work.
  • Bug fix, control-plane ownership unchanged; validation and remaining boundaries disclosed.

@huangruiteng

Copy link
Copy Markdown
Collaborator Author

CI readback for 965a3ea81: local focused validation is passing, but the merge gate is blocked. The packaged Personal Workspace smoke times out at examples/personal-workspace-browser/typed-actions.mjs:587, waiting for the empty-state text No delivered files or verified reports yet. Run and validation status remain in Tasks.

The exact same failure is present on the PR's 46280da6e main baseline: PR run, baseline run. This does not certify the remaining CI jobs or permit bypass; the PR remains unmerged. The body now discloses the inherited failure.

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Request changes conclusion (author-owned PR; GitHub blocks formal self-review). Reviewed exact head 965a3ea81d5cece5cc370cf0986522ca289a894b.

动机

#5007 的故障是带验证器的 Todo 已在 File/SQLite 权威存储提交,进程却在私有 sidecar 落盘前退出或丢失响应。Markdown 重建和后续完成验证因此找不到与权威摘要匹配的命令;简单重试 post-commit 写入无法覆盖进程死亡。

改动思路

先按摘要持久准备私有声明,再让既有 TS create/revision CAS 选择它;blob 本身不授予 Todo 权限。todo add --operation-id 提供稳定重试身份,由 TS 回执控制同意图重放。Python 在含糊响应时返回可操作的编号;历史重放不覆盖后续修订的 validator。权威、内容和重试职责没有混成第二套决策者。

具体改动

completion_validation_store.py 新增加锁、原子写入/fsync 的 digest blob 与严格读取;completion_validation.py 让投影/完成路径按 canonical digest 选择声明。provider_create.py 用 operation id 生成 Todo ID、预准备声明并处理含糊响应,provider_update.py 同样预准备修订。CLI 参数校验、add_goal_todo、双语 RFC/参考文档及 File/SQLite、损坏、进程退出测试组成完整入口;另有一处投影 typing 调整。

对主干的风险

独立 head 上实跑 16 个恢复用例(包括真实子进程提交后退出、损坏 blob、变更意图及修订后重放)、配置 mypy 23 文件、变更路径 Ruff 和 diff 空白检查,均通过。未把作者描述或远端 CI 当作我的验证。

[P1 集成阻断] git merge-tree --write-tree origin/main 965a3ea81d5cece5cc370cf0986522ca289a894b 报内容冲突,唯一冲突文件是 loopx/control_plane/coordination/local_authority_shadow_projection.py。主干已在同一 project_coordination_source 路径实现投影类型检查。本 PR 的伴随 hunk 需在新 head 上与主干协调,然后复跑 File/SQLite 进程退出→重建→原编号重试及静态检查。当前没有可验证的集成后代码;这不等于已复现独立 head 的恢复缺陷。

我的整体评价

核心修复复用已有 digest、TS 回执和 Python 私有传输边界,范围与故障相称。未引用 blob 留在私有存储是已披露的有限代价。相关的未来维护改进是删除重复 typing hunk,而非扩成通用历史回滚或跨主机分发。独立 head 未见额外阻断,但集成尚未证明,故请求修改并在新 exact head 复审。

English verdict: REQUEST_CHANGES - Exact head 965a3ea passes 16 focused File/SQLite recovery tests and configured static checks, but conflicts with current main in the shared projection typing file. Rebase and revalidate the integrated head before approval.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng
huangruiteng force-pushed the codex/recover-validated-todo-create-5007 branch from 965a3ea to 403c741 Compare September 25, 2026 04:42

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Approval conclusion (author-owned PR; GitHub blocks formal self-approval). Reviewed exact head 403c741b1c0f33d148b8744440660e7e564b8787, rebased onto origin/main 1e21976d61e3a8f6c04b95a845b8e21f92935541.

动机

已复核基线行为:validated Todo 的创建会先做 canonical 提交,再把私有 validator 落盘;一旦响应丢失或进程在提交后退出,Goal 的 Markdown 投影就缺了对应的声明内容而不可用。基线还让 todo_id 依赖「当前 Todo 计数」,因此丢失响应后重新执行会得到不同身份,历史重试甚至可能把较新的 validator 覆盖回去。

对长期推进而言,创建是所有后续工作的入口:修复前一次超时就会留下一个「提交成功但不可读」的 Todo,后续 Turn 要么重复创建要么修数据;修复后私有内容在提交前先以内容摘要落盘,canonical 记录只在选中该摘要时才消费它,丢失响应重放同一个 --operation-id 会复用既有回执并保持身份不变。对用户旅程而言,受影响入口是 loopx todo add 与投影/完成读取路径:操作者重新执行同一命令会得到幂等结果而不是重复 Todo,投影与完成校验共用同一严格 reader,历史重试不会让较新的 validator 回退。

改动思路

身份与发布顺序是两个关键点。身份改为由稳定 operation_id 派生(todo_<sha256(operation_id) 前 24 位>),因此与当前 Todo 数量和其他 Todo 的增删编辑解耦;updated_at 从 provider metadata 中移除,因为提交时间由 TS 拥有,传输重试不得改变意图。发布顺序改为「先准备、后提交」:prepare_completion_validation_declaration 在跨运行时文件锁内把不可变声明写入 blobs/<digest>.json 并同步目录,canonical 提交再把该摘要写进记录;读取时只接受由 canonical 记录选中的精确摘要,摘要、goal 身份或内容不符即拒绝,绝不回退到别名 blob。

语义与集成

EffectRuntimeResponseAmbiguous 现在被显式处理:创建/修订在响应不确定时不再当成失败,而是按既有 TS 回执恢复同一身份,这也让「进程在真实 provider 提交后立刻退出」这一类可以用另一个进程通过公开 CLI 恢复。被拒绝的创建可能留下无人引用的 blob——它不授予任何权限,也不会被读取,这一点已在 PR 中披露而不是靠自动回收掩盖。

具体改动

  • loopx/control_plane/todos/completion_validation_store.py:新增 prepare_completion_validation_declaration(加锁、幂等、同步目录)与 _read_prepared_declaration(严格校验摘要与身份),persist_... 复用它。
  • loopx/control_plane/todos/provider_create.py:operation_id 参数与格式校验、基于摘要的稳定 todo_id、移除 updated_at、捕获 EffectRuntimeResponseAmbiguous 并复用既有回执。
  • loopx/control_plane/todos/provider_update.py、completion_validation.py、loopx/todos.py、loopx/cli_commands/todo*.py:修订路径同样先准备后提交,CLI 传递 --operation-id。
  • 测试与 fixture:新增 tests/control_plane/test_validated_create_recovery.py(7 例,含丢失响应后他人编辑、修订回执、准备失败与 dry-run 不发布、选中 blob 损坏不得回退、未选中内容不改变权威、进程退出后经公开 CLI 恢复),canonical_authority_fixture.py 提供 provider 夹具;test_local_coordination_authority.py 相应精简。
  • 文档:双语 ledger 2026-09-24-validation-publication-recovery.md 与 docs/reference/canonical-todo-completion-update.md 记录该边界与仍开放的私有命令分发/回收。

对主干的风险

第一是磁盘状态:被拒绝的创建会留下无人引用的 blob,目前没有回收;它不可被读取也不能授权,但会累积。第二是身份语义:todo_id 从「按计数派生」变成「按操作派生」,对已存在的 Todo 没有影响(它们保留原 id),但新增 Todo 的 id 形状与历史不同,依赖旧形状的临时脚本需要按公开 id 字段读取而不是重算。第三是门禁现状:canary premerge --goal-id loopx-meta 选中 19 项检查、18 项通过,唯一失败的 semantic-vocabulary-drift-smoke 是模块对预算 44 > 43,我在干净的 origin/main 上复现同一失败,属于继承的基线红灯;本目标不等待远端 CI。PostgreSQL 私有命令分发与活跃 Goal 迁移不在本切片内,也未在本地复跑(PR 正文记录了一个已知的打包浏览器 smoke 继承失败及其基线对照)。

我的整体评价

没有发现阻断项。这个增量把「提交成功但 validator 缺失」这类不可用状态从结构上消除,并让丢失响应后的重放保持身份与内容恒定;它复用既有摘要契约与锁,而不是引入第二套私有存储。验证覆盖正例、负例与真实路径:54 个恢复/授权用例(含子进程提交后立刻退出、经公开 CLI 恢复)、90 个完成校验/投影用例、3080 个 control-plane TS 用例(0 失败)、严格 mypy 与 ruff 全部通过;变更质量回执 cqr_74236bf8fa12fa94c568 对精确指纹有效。建议按维护者流程合并。

English verdict: APPROVE - exact head 403c741b1c0f33d148b8744440660e7e564b8787; private validator content is prepared before the canonical digest can reference it, create identity comes from a stable operation id instead of the current Todo count, and lost responses recover through the existing receipt with no duplicate Todo. Focused recovery/authority, completion-validation and full control-plane TypeScript suites plus strict typing and lint are green; the only failing check is the inherited module-pair vocabulary budget, reproduced on a clean origin/main.

@huangruiteng
huangruiteng merged commit c36b416 into main Sep 25, 2026
6 checks passed
@huangruiteng
huangruiteng deleted the codex/recover-validated-todo-create-5007 branch September 25, 2026 04:44
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Merge note — #5012 merged on the reviewed exact head

Merged via admin bypass as c36b41678928df2bd64d13cf6eeb81c5372b06c5; the merge tree equals the reviewed head tree, so every changed path is byte-identical to head 403c741b1c0f33d148b8744440660e7e564b8787 (rebased onto origin/main 1e21976d6).

Changed surfaces: the completion-validation store (new durable prepared-blob helper plus a strict digest reader), the canonical create and revision providers (operation-derived identity, prepare-before-commit, ambiguous-response recovery), Todo CLI argument plumbing, one new recovery suite with a provider fixture, and the bilingual ledger plus caller contract.

Rebase repair: one conflict in local_authority_shadow_projection.py; the branch's already-upstream readback-type hunk was dropped in favour of the upstream form.

Checks on the reviewed head

  • pytest: 54 recovery/authority tests including the child-process-exit-after-real-commit case on File and SQLite, plus 90 completion-validation/projection tests — all passed;
  • npm run test:control-plane — 3080 tests, 3051 passed, 0 failed, 29 skipped;
  • npx tsc --project tsconfig.control-plane.json --noEmit clean; strict mypy clean; ruff check clean; git diff --check clean;
  • change-quality receipt cqr_74236bf8fa12fa94c568 for scope fingerprint 74236bf8fa12fa94c56865bf55de36aa692f965de8cf48948e0cadfe604a5272;
  • loopx pr-review --check-merge-readiness 5012@403c741b1 --goal-id loopx-meta returned ready=true immediately before merge.

Failures, skips and holds: the goal-scoped premerge gate selected 19 checks and 18 passed; examples/semantic-vocabulary-drift-smoke.py fails on the module-pair budget (44 > 43) for a pair merged earlier and reproduces on a clean origin/main, so it is inherited. The packaged browser smoke has the separately disclosed inherited failure recorded in the PR body. Remote CI was not awaited (wait_for_ci=false). Manual holds: none.

Residual risk: rejected creates can leave unreferenced prepared blobs (inert and unreadable without an exact canonical digest selection) and no collection owner exists yet; cross-host private-command distribution is not introduced.

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.

Todo create timeout can strand canonical validation projection

1 participant