Skip to content

fix(quota): keep long-history closeout responsive and unify receipt reads - #5050

Merged
huangruiteng merged 4 commits into
mainfrom
codex/closeout-preflight-0925
Sep 25, 2026
Merged

huangruiteng merged 4 commits into
mainfrom
codex/closeout-preflight-0925

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

Problem and outcome

Long-running Goals can repeatedly decode their entire receipt history before a heartbeat may proceed. A live closeout preflight exceeded its five-second response budget; a later read-only query and same-Turn retry recovered. Per-request indexing was already present. This change removes redundant parsing across requests and the second Python monitor-log scan, while preserving complete-history validation and the five-second budget.

Changes

  • Share a TS receipt-log reader that reads fresh bytes and SHA-256 verifies the retained newline-terminated prefix before reuse. Append parses only new rows; rewriting, truncation, rotation, malformed history and partial UTF-8/JSON tails remain observable. Nested records are immutable, and cold parsing yields between batches. Retention is bounded to four histories / 128 MiB of source bytes; larger inputs use uncached parsing.
  • Reuse the existing TS settlement rule for exact committed monitor polls. Python adapts only the current Todo. A newer uncommitted observation cannot hide an earlier exact commit; foreign identities still cannot close a Turn.
  • Report a lost read-only preflight response as unknown query state, through the final CLI/envelope projection, without suggesting a nonexistent write receipt. Preserve an existing heartbeat receipt or report not_committed; ambiguous writes retain conservative failure semantics. No automatic mutation retry, server restart, admission bypass or timeout increase.
  • Update both RFCs and the reconciled cutover checkpoint. This addresses an R1/R5/S7 liveness gap and retires one Python read path; it does not complete whole-Goal migration or reduce the three remaining implementation packages by one. Related: [Roadmap]: LoopX overall delivery program / LoopX 整体路线与交付总跟踪 #4574.

Validation and limits

  • 51 focused TS tests and 124 settlement/monitor/heartbeat/RPC tests passed. Added real-file regressions for append, old identity conflicts, same-size rewrite with restored mtime, truncation/replacement, malformed lines, unfinished UTF-8 tails, eviction and immutable reuse.
  • 159 Python quota/settlement/heartbeat/RPC and CLI regression tests passed; the preflight suite covers 6 cases, including real files → TS RPC → Python adapter → typed monitor closeout.
  • Final clean-head premerge canary: 19 checks executed, zero failures. An intermediate vocabulary check caught a missing producer registration; it is now declared without broadening the enum or scanner.
  • The public CLI failure matrix covers missing/existing heartbeat receipts, compact/envelope output and query/write response loss, asserting no history mutation or new heartbeat event.
  • TypeScript typecheck, Ruff, configured Mypy (23 files), focused adapter Mypy, diff hygiene and public-boundary scan passed. An initial ad-hoc Mypy invocation followed the wider untyped import graph and failed; it is not the repository's configured typecheck. Registry scan also reported two unrelated existing projection warnings.
  • Same frozen local history on base 41ba6f4d9 and this implementation: 7,162 scoped Turns; 12 sequential reads with an append between reads. Warm median was approximately 348 → 101 ms; eight concurrent readers completed in approximately 2.93 → 0.60 seconds. Cold read was 427 → 334 ms. These are one-machine measurements, not a new SLO or D2 qualification.
  • The real active Goal's read-only preflight, canonical Todo lookup and final typed recovery completed in 2.09 seconds without requiring recovery. Private logs and identities are excluded from public fixtures. No active Goal was migrated or fault-injected.

The original transient host/process scheduling cause was not reproduced reliably. This establishes reduced repeated work and concurrency headroom, not immunity to environmental timeouts. Full byte reads still scale with history; retained-source bytes are not an exact JS heap bound. This is an in-memory acceleration, not a durable index or new authority. PostgreSQL storage and provider contracts are unchanged. Existing quota/heartbeat callers adopt the repair; no new UI/Lark setting is needed.

Review focus

Challenge stale-cache safety, older conflicting receipts, exact poll identity, cold-history scheduling, memory retention and query-versus-mutation failure semantics. The future-facing pass consolidated the actual receipt owners and removed duplicate Python IO without introducing a new capability or provider.

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>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>

@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)

动机

长期运行的 Goal 在 prior-host-Turn closeout 中反复读取历史 JSONL;已有单次请求索引仍会跨请求重复解码。约 7,010 个历史 Turn 的现场 preflight 曾接近外层超时。需要缩短重复读取,同时保持旧回执冲突、精确 monitor 提交和失败重试的权威语义。本文结论仅针对 #5050 的精确 head 723fc33cadd977b7bfbd7c8f9ec9a4dec6cc2fe3。

改动思路

我先检验了更小的选择:单纯增加超时不能去掉随历史增长的重复解码;持久索引又引入新的写入/迁移权威。当前方案每次读取新鲜字节,只在已换行的旧前缀 SHA-256 完全相符时复用解析结果;缓存可丢弃,磁盘回执仍是唯一事实。另把 monitor 已提交判断复用 TS settlement 规则,删除 Python 第二次 run-log 扫描。第一次审查发现“只读查询丢响应”仍被外层 CLI 误报为回执写失败;最终 head 已补齐公开投影和真正的 CLI 回归,而未放宽真实写丢响应的保守处理。

具体改动

  • readReceiptLogSnapshot:新鲜全量字节校验、增量解析完整前缀,未结束尾行每次重读;改写、截断、删除/重建、损坏行不能借缓存逃过检查。
  • committedMonitorPollFromSnapshot / preflightPriorHostTurnCloseout:只接受同 Goal、Agent、Turn、Todo 和精确 effect 的已提交 poll;后来的未提交观察不遮住早先的精确提交。
  • _prior_closeout_preflight、quota_failure_payload、handle_quota_command:只读查询丢响应返回 quota_closeout_query_unavailable / control_plane_health_repair,保留已有心跳回执或标记 not_committed,建议检查 runtime 后同 Turn 重查;真正写丢响应仍是 write_failed。

关键代码讲解

receipt_log_snapshot.ts:81 的哈希核对而非 mtime/大小决定复用;settlement_readback.ts:322 是 monitor 提交的共用规则;unsettled_host_turn.py:101 只做 TS 响应与 Todo 事实的桥接;quota_failure_report.py:68 和 quota.py:325 才拥有操作员看见的失败分类与回执视图。最后两层已补上先前遗漏的诊断传递。

对主干的风险

独立复跑最终 head:相关 TS 测试 100/100、Python closeout/CLI 测试 14/14、action-selection/heartbeat-receipt 测试 4/4、TS 类型检查、semantic-vocabulary drift smoke 与 git diff --check 均通过。同一合成输入对比 base/head:只读查询由误报 write_failed 改为查询不可用;真实写丢响应的 write_failed 路径保持不变。新增 8 组合 CLI 测试覆盖有/无已有回执与 compact/envelope。作者报告 canary 19/19;我没有把该报告当作独立复跑。

残余边界:每次仍需读取并哈希完整历史,128 MiB 是保留原始输入量的上限,不是 JS heap 硬上限;原始短暂主机调度原因未稳定重现。RFC 如实保留 D2 容量/retention 和后续默认切换门槛,不应把本 PR 视为其完成。

我的整体评价

未发现最终 head 的阻塞项。这是已有 closeout 路径内可逆、可验证的性能与失败语义修复;没有新增持久权威,也没有把只读故障伪装成成功。代码审查结论为可接受;control-plane/runtime 合并仍由维护者按独立 gate 决定,本 review 不执行合并。未来相邻重构已核对:共用解析和 monitor 规则、移回回执 owner 的 not_committed 视图足以消除本次重复权威;更大持久索引留在独立容量工作包。

English verdict: APPROVE — exact-head review passed; no blocking finding. Maintainer merge gate remains separate.

@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Exact-head delivery decision for 723fc33cadd977b7bfbd7c8f9ec9a4dec6cc2fe3: independently reviewed APPROVE in review 5316873123; no unresolved blockers. Owner-authorized admin bypass is conditional on the current-head capability merge-readiness result.

Changed surfaces: shared TS receipt-history reads, prior-Turn monitor closeout, Python CLI failure projection, semantic producer registry and RFC checkpoint. Local validation: 51 focused and 124 integration TS tests; 159 combined Python tests; TS typecheck, Ruff, configured/focused Mypy, public-boundary scan, real-history base/head profiling and active-provider read-only recovery. Final clean-head premerge canary executed 19 checks with zero failures and no manual holds. Exact-scope change-quality receipt cqr_ba4afd016543e00e89ce verifies.

An intermediate vocabulary check exposed a missing producer declaration, now fixed. A concurrent author edit triggered an intermediate canary side-effect guard; the final complete canary was run on an unchanged clean head. A broad ad-hoc Mypy invocation followed unrelated untyped imports; repository-configured and focused checks passed. CI is intentionally not consulted under this Goal's wait_for_ci=false policy. PostgreSQL storage is unchanged; no provider qualification is claimed.

The independent review also passed 100 TS tests, 14 closeout/CLI tests, 4 action-selection/heartbeat tests, typecheck and vocabulary checks. Coverage includes exact identities, stale/rewritten history, malformed and partial tails, retained receipt reuse and public query/write failure distinctions. The future-facing refactor consolidates actual receipt ownership and removes duplicate Python IO. Fresh reads still scale with history, the retained-source budget is not a heap ceiling, and the transient host scheduling cause remains unproven. The RFC's three migration implementation packages and separate D2 evidence remain open.

@huangruiteng
huangruiteng merged commit cb4b5e3 into main Sep 25, 2026
16 of 24 checks passed
@huangruiteng
huangruiteng deleted the codex/closeout-preflight-0925 branch September 25, 2026 11:03
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Post-merge local acceptance: installed an immutable release from merge commit cb4b5e384b02c9ccee87df58811e3057a3d661d5; its manifest reports that exact commit and a clean source checkout. The packaged Chat bundle verified with the previous delivered assets retained.

Against the real long-lived Goal, read-only preflight completed in 0.577 / 0.117 / 0.099 seconds. The full preflight → canonical Todo lookup → typed recovery returned no pending recovery obligation. Recovery plus packaged-bundle verification took 2.60 seconds. These are local observations, not new latency guarantees or SQLite D2 qualification. No Goal promotion, registry/fence update, Todo mutation or fabricated settlement was used for this acceptance. The previous immutable release remains available for code rollback.

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.

1 participant