Repository navigation
perf(usage): stream session ledger reconstruction - #7221
Conversation
Signed-off-by: aihop <4408344+hhyykk@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; effort=max
动机
通过明确绑定 Codex 会话记录用量、并长期保留运行历史的 Goal 使用者。旧路径重建一次会话累计基线时,会同时保留整个索引文本与拆行副本;历史增长会放大每次记账的 Python 内存峰值。新路径逐行遍历同一完整历史,并保留原有会话筛选、去重、累计和冲突规则。在相同的完整保留索引上,File/SQLite 都保存正确增量、零增量重放与后续增长;完整 CLI 的 Python 峰值内存约下降 26%,不是整机收益或普遍提速结论。这次不新增计费账本、自动会话发现、定价或生命周期总额,也不替代其他运行时覆盖与真实长期成本验收。
改动思路
流生命周期与读取异常属于现有 Python Codex 测量适配器;会话筛选、去重、累计和绑定规则仍在原 reducer,记账锁和 durable append 保持原 owner。当前 PR 只消除完整账本的文本及拆行缓存,保留完整扫描与既有持久记录格式;最大单行及所选会话的去重集合仍随输入增长。这比增加缓存或另一本账更小:原 run index 继续作为已记账事实,任何缺失尾部都可能缩小基线并重复计费,不能通过采样、显示上限或跳过坏行换内存。缺失文件仍表示首次观察;读取或 JSON 损坏仍应使整次记账失败,而不是提交部分累计。Python 保留的是专用测量 IO,不是新的控制面语义 owner。
具体改动
评审 head:15600cdee19d4f8b93427cf590c348a5a17fe16c,独立基线 905d0ae4b7e48ffab230f1f8578f867d9a9350cd。先读原 docs/status-data-contract.md 的 Usage Summary 和原 accepted usage RFC,再读 diff。规范映射:Cumulative host snapshots are converted to non-negative deltas 保留单一提交点;Replaying the same snapshot identity 保留零增量与冲突拒绝;Missing optional measurements stay omitted 保留 unknown;a failed usage observation blocks the whole refresh append 保留完整扫描和失败不 append。新文档检查点不重写这些原验收要求。
关键代码讲解
_usage_index_records通过 context manager 逐条读完整 UTF-8 索引,保留原行号与 JSON 错误文案,并把打开或迭代期间的 IO 错误交回原异常边界。Unicode separator 仍是内容,不当作 JSONL 额外行。session_usage_baseline只改输入迭代方式,原会话前缀筛选、index_identity去重、累计指标、首次 booking 时间与旧 model 绑定规则留在原处;最终尾行参与同一累计。book_codex_session_usage经原 refresh-state 记账锁调用上面 reducer,仍由既有 strict collector 写入 Run 与 index。未指定 usage flag 的 refresh 不选择会话,也不把缺失费用填为零。
另外三条路径是原测试 fixture 转用真实 canonical owner、完整账本/延迟 IO/内存回归,以及 RFC 与 usage 文档。原功能断言保留;fixture 修正也用于基线生产代码,避免把 legacy-only 初始化拒绝误算为本优化失败。没有新 ledger、依赖、CLI 选项、持久字段或共享状态词汇。
对主干的风险
独立运行所选 owner/collector/summary 三组测试:93 通过;相同修正 fixture 与当前 oracle 对基线为 92 通过、1 失败,唯一失败是新 allocation 回归:8,462,705 bytes 超过保留的1MiB上限。公共 File/SQLite CLI 在相同完整历史中返回400/150 tokens,重放0/0,后续增长100/50;每次均核对保存 Run 与 index。删掉末尾有效 booking 的私有突变通过真实 CLI 得500/200,独立 oracle 拒绝;当前完整扫描通过。两 provider、两源码臂的坏行拒绝没有部分 append,省略 usage flag 的返回和持久记录都保留 unknown。24组完整 payload/保存 Run 对照只去除输出文件名、时间及事件 ID,其余字段相同。
合并门仍有既有失败。 当前 quick premerge 的6项 direct 通过,4项 selected 中3项通过;review-packet-cli-smoke.py 在 planned-main-control fixture 失败。独立基线与当前 head 的相同命令都返回 exit1,以及逐字相同的完整错误 Canonical authority is required; back up and migrate this Goal before retrying。该 fixture/source 路径逐字节未变,失败命令没有 usage flag,不执行本次新 iterator;changed invariant 另有上述独立通过证据。因此归为 pre_existing_unrelated,评审不把它归咎本 PR,合并门的失败仍保留,须由该 fixture 的 owner 修复后重跑,未绕过或放宽检查。CI 按契约不查询、不等待。
完整命令测量在真实 File/SQLite、冻结的9,660,736字节/10,002行索引上顺序执行,每 provider 六组 ABBA、首组 warmup 后每臂10样本;每次 public CLI append 后单独读回实际文件。Python 进程自行报告 RUSAGE_SELF,不包括 Node/系统内存。
| Provider/源码 | Python峰值MiB,中位数/p95 | 完整命令ms,中位数/p95 |
|---|---|---|
| file/base | 108.6 / 109.4 | 563 / 673 |
| file/head | 80.5 / 81.1 | 558 / 635 |
| sqlite/base | 108.9 / 109.4 | 549 / 602 |
| sqlite/head | 80.7 / 81.3 | 545 / 576 |
这一合成负载的内存中位数约降26%;延时差异不外推为普遍提速。最大单行与所选会话去重集合仍可能增长,未证明任意历史规模、安装包、真实模型会话、整机总内存或长期费用收益。保留两次私有 fixture/oracle 失误和最初零测试路径错误,再用正确的原 row identity 与冻结 snapshot 完成对照;未改产品或原断言。
我的整体评价
APPROVE,合并仍受上述既有 premerge 失败约束。 所选有用结果是保留完整记账语义并减少每次 booking 的内存,而不是创造更复杂的账本。long_horizon 为 preserved:重放、并发与历史完整性沿原 owner;user_experience 在内存占用与持续记账路径上改善,但不认证 lifetime 成本或模型收益。已检查 refresh-state 用量写入和原 Usage Summary 消费路径;本次没有改页面布局、控件或渲染数据契约,因此视觉评审不适用。未重新验收安装包、浏览器整页或实际用户采用;本次无渲染改动。当前 PR 只消除完整账本的文本及拆行缓存,保留完整扫描与既有持久记录格式;最大单行及所选会话的去重集合仍随输入增长。新迭代器与问题相称,复用现有 owner 的取舍成立;无需为这条内部 IO 路径增加用户界面、配置或迁移协议。本结论不授权合并,也不取消仍失败的仓库门。
English verdict: APPROVE — 15600cdee19d4f8b93427cf590c348a5a17fe16c preserves complete per-session accounting while reducing measured Python peak RSS by about26% in a matched real File/SQLite CLI workload.93 focused tests pass; replay/growth, corrupt-input refusal, full-output parity and a public-path tail-loss mutation are covered. The identical pre-existing review-packet fixture failure remains a required premerge hold; no gate or merge authority is waived.
Goal And Delivered Outcome
Codex usage booking reconstructed a session baseline by retaining the complete run-index text plus split-line copies. This PR streams every retained index record through the existing booking module, preserving the accounting reducer and its caller interface.
Basis: the accepted per-Goal usage RFC and Usage Summary contract at main
905d0ae4b7e48ffab230f1f8578f867d9a9350cd. Intended base:main. No new dependency, RPC, cache, ledger, provider default or decision owner.Author Declaration
Written by: model_agent — OpenAI Codex, GPT-6 family.
Scope And Continuation
The private filesystem iterator owns stream lifetime and typed read failures. The existing reducer still owns duplicate suppression, cumulative counters and legacy model binding. The booking/index locks and durable append are unchanged. Python placement stays with the Codex measurement adapter; this is not a TypeScript ownership migration.
The producer tests now reuse the repository's canonical-authority fixture. Their prior legacy-only fixture caused the same 12 failures on main and candidate, before booking could run. All assertions remain; the real producer smoke covers File and SQLite.
Validation
Backend qualification: isolated native File v0 and SQLite 3.54.0 on Node 26.12.1, Python 3.11.6.
Tested head:
15600cdee19d4f8b93427cf590c348a5a17fe16c. Input: synthetic local fixtures; no provider messages, paid/model work or live Goal writes.[500, 200]tokens instead of[400, 150].review-packet-cli-smoke.pystill fails for itsplanned-main-controlfixture withCanonical authority is required. The unchanged main and this head reproduce the exact same refusal. This remains a merge hold; the gate was not bypassed or relabeled.Complete CLI measurement
Frozen workload: 10,000 retained rows, 10267834 bytes. Fresh Python processes execute the public
refresh-state --usage-codex-sessiondurable write with a warm native runtime. Both arms use the same fixture and launcher. Six alternating ABBA blocks per provider; the first block is warmup, leaving 10 measured samples per arm/provider.Memory is the Python CLI process's peak RSS, not combined Python/Node/system memory. Timing includes the complete command and common small launcher. Every measured command produces the independently expected delta and matching saved run/index usage. Additional public CLI calls verify zero-delta replay and subsequent cumulative growth on both providers and both arms. File median/p95 cost is +86/+120 ms in this run; SQLite is −16/−139 ms. The demonstrated gain is about 21% lower Python peak RSS. There is no speedup claim.
An initial RSS experiment was discarded because its large parent image polluted pre-exec child RSS. A small fresh launcher removes that contamination. Earlier interrupted and pre-rebase runs remain local evidence; the table uses the complete run at base
c113af70d/ candidateae7fd74ba. The final rebase onto905d0ae4bchanged only unrelated research files. Python CLI and usage-source bytes are unchanged. The final head repeats all 106 owner regressions plus eight full CLI writes and eight replay/growth calls across File/SQLite and both source arms.Limits And Rollback
The largest record and selected-session duplicate identities still consume memory. This does not qualify arbitrary history sizes, an installed package, real long-running model sessions or fleet memory savings. Lifetime cost and per-runtime coverage remain open RFC questions.
Rollback restores the original reader. Persisted rows and public output keep their existing schema. No migration or activation is introduced. No UI changes. All four changed paths were checked against the complete paginated open-PR file lists; 40 other open PRs, no overlap. No merge is requested or performed.