Skip to content

fix(capacity): follow quota context navigation and retry temp cleanup - #8256

Open
LIHUA919 wants to merge 5 commits into
loopx-project:mainfrom
LIHUA919:codex/sqlite-d2-matched-1m-remeasure
Open

LIHUA919 wants to merge 5 commits into
loopx-project:mainfrom
LIHUA919:codex/sqlite-d2-matched-1m-remeasure

Conversation

@LIHUA919

@LIHUA919 LIHUA919 commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

Refs #4224.

Problem

Since a2aa667 (2026-11-01), the quota should-run CLI returns a context_capture_navigation_v1 envelope and delivers the full capture through paged quota context-read. The sqlite-capacity runner's cold CLI stage still asserted the old inline payload shape, so every --cli measurement arm silently failed with cold_cli_quota: AssertionError — the formal measurement entrypoint was unusable for five days without anyone noticing.

Separately, the teardown rmSync raced with just-stopped managed-runtime grandchildren briefly holding the temp root: a fully measured, fully passing axis was flipped to failed by the cleanup error and the later axis was cancelled by the runner's short-circuit (observed on a formal matched-1m run: 10k arm complete with 20 CLI samples, then cancelled before the 100k arm).

Change (examples/coordination/sqlite-capacity.ts only)

  • Follow the navigation envelope's full-capture read command (command, not first_read_command, which is the initial selection digest) page by page until eof, reassemble and parse the original payload; the cold sample keeps the whole navigation cost, because a cold reader cannot act before the payload arrives.
  • Retry the recursive temp-root delete briefly (4 × 250 ms) before declaring cleanup failed, and stop overwriting an existing failure reason with the cleanup error.

No persisted format, ledger, threshold, provider or default changes; the report contract is unchanged.

Validation

  • sqlite-capacity.ts --profile rehearsal --cli: both axes pass end to end with real status/quota/mutation CLI samples on Node 22.22.3 / SQLite 3.51.3 (previously: first axis failed at the quota assertion).
  • node --test tests/control_plane_ts/sqlite_capacity.test.ts: 10/10.
  • tsc --project tsconfig.control-plane.json --noEmit: clean.
  • Formal matched-1m profile then completed both 10000- and 100000-commit axes at a9485073f with cleanup verified; results will be posted on [Task]: Qualify SQLite D2 capacity and crash/replay recovery on the merged provider #4224.

Refs loopx-project#4224. The sqlite-capacity runner's cold CLI stage asserted the
inline quota should-run payload, but since a2aa667 the command returns
a context_capture_navigation_v1 envelope and delivers the full capture
through paged quota context-read, so every --cli arm silently failed
after that change. Follow the envelope's full-capture read command page
by page until eof and parse the reassembled payload; the sample keeps
the whole navigation cost. Separately, the teardown rmSync raced with
just-stopped managed-runtime grandchildren holding the temp root,
flipping fully measured axes to failed and cancelling later axes through
the short-circuit; retry the recursive delete briefly and stop
overwriting an existing failure reason with the cleanup error.

Validation: rehearsal --profile rehearsal --cli passes both axes with
real status/quota/mutation CLI samples end to end on Node 22.22.3;
tests/control_plane_ts/sqlite_capacity.test.ts 10/10;
tsc --project tsconfig.control-plane.json --noEmit clean; the formal
matched-1m profile then completed both 10000- and 100000-commit axes at
a948507 with cleanup verified.

Signed-off-by: Lihua <1017343802@qq.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 | reasoning_effort=max

[P2] 含空格的临时目录会让 --cli 中止。 配额读取命令用 shlex.join 给路径加单引号,splitReaderCommand 只识别双引号。设置含空格的 TMPDIR 后,子进程把文件路径拆成多个参数,context-read 退出 2。首组轴因此失败,第二组不会运行。保留原捕获和原解释器,用结构化 reference_file 与 next_offset 传参,或用与生成器一致的解码。从含空格的 TMPDIR 跑一次现有 rehearsal --cli,核对跨页读完、实际 Todo 更新和临时目录清理。 调用处 命令生成处

动机 / Motivation

维护者用容量工具核验真实 CLI 调用。配额检查现在先返回读取指令,旧工具直接找 Todo,所以拿不到配额阶段的样本。 修订后,无空格目录里的 rehearsal 能读完原捕获并更新 Todo。相同入口遇到含空格的临时目录仍中止。 两种路径的差别会反映到报告中。成功时两组轴都有 CLI 样本,失败时第一组轴报错,第二组轴无法开始。 这里验证现有容量工具和临时数据清理。正式 D2 性能资格仍按原测量计划验收。 读取器仍须正确传递带引号的文件路径。

改动思路 / Approach

沿用已有的配额捕获和 SQLite 测试数据。工具在启动子进程后按页读取同一份捕获,把翻页的开销计入该样本。清理仍在测量之后执行,先停隔离运行时,再重试删除临时目录。主干合并预检只触及现有容量脚本。 读取和计时

具体改动 / Changes

读取分支优先跟随 command 读取完整捕获,避免把 first_read_command 的首批字段当成整份结果。每页成功后累加正文,直到 EOF,继续用原来的 Todo 校验和更新。临时目录删除最多尝试五次。注入两次删除失败时第三次清理成功,持续失败时保留已有测量错误。 翻页 清理

按修订 a948507 的文档核对 rehearsal --cli、cleanup 和 matched-1m。前两项属于隔离运行器复现,正式匹配负载属于单独测量。 docs/reference/sqlite-authority-store.md

对主干的风险 / Risks

在提交 c705ea0 用 Node 24、Python 3.11 和真实 SQLite 验证。普通路径的 100 和 1000 提交两组均完成,各有三次 CLI 更新并成功清理。含空格的路径停在首组配额读取,CLI 更新为零,临时目录已清理。用原有参数解码读取同一类文件,四页可完整重组。TypeScript 类型检查、十项容量测试和快速 premerge 通过。已有测试的 rehearsal 未打开 --cli。按策略未查 CI。

我的整体评价 / Verdict

本次交付只涉及容量 CLI 和文本报告。 恢复现有入口和保留首个测量错误都有价值。先修复路径传参并补上真实 CLI 反例,再复审。正式 D2 资格和实际系统删除竞争仍需各自的证据。

English verdict: REQUEST_CHANGES. At c705ea0, a valid quoted reader path still fails the real CLI rehearsal. Preserve the emitted reference as a single argument and cover it at the caller.

@LIHUA919

LIHUA919 commented Nov 7, 2026

Copy link
Copy Markdown
Contributor Author

Review finding addressed on new head 7442e5b5b (includes a merge of current main; typecheck, the 11 capacity tests including the new splitter cases, exact-path boundary scan and canary premerge --from-git-diff --git-diff-base origin/main all pass).

P2 空格 TMPDIR 中止 —— 已修复,按"与生成器一致的解码"路线。 splitReaderCommand 只认双引号,而生成方用 POSIX shlex.join(单引号 + '"'"' 转义)。新的共享 splitShellCommand(sqlite-capacity-report.ts,带单元测试)精确解码生成方发出的引号形式:单引号、双引号、双引号内反斜杠转义;引号不闭合时抛错,而不是把 reference 路径拆成多个参数。发出的带引号 reference 现在严格保持为单个参数。选择调用方解码而非结构化传参,是因为分页链每一页都只返回 next_command 字符串——这是现有接口,改它超出本修复边界。

要求的验证(真实 CLI,含空格 TMPDIR):TMPDIR="/tmp/loopx spaced tmpdir/" 运行 --profile rehearsal --cli(本机参考运行时,分支 head)。两轴均 passed:100 与 1000 提交、各 3 次 CLI 更新(quota 导航跨页读完、Todo 实际变更、最终 cursor 回读)、cleanup_verified: true、退出码 0;quota 冷样本 p50 793/728 ms。

如实披露一个观察:清理验证通过后,刚停止的 runtime 孙进程偶发重建空的 axis 根目录壳(0 字节、无内容)。内容清理与验证语义不受影响,空壳属可清理残留;未在本修复中掩盖或重试该竞态。

之前 CI 的 pytest/kernel-static-checks/stage2c/merge-gate 失败来自合并自旧 main 的预存状态;本 head 已并入最新 main(e2371c476 一线),等待 CI 重跑。若仍有失败将逐一归因。

@mergify

mergify Bot commented Nov 7, 2026

Copy link
Copy Markdown

Hi @LIHUA919, the DCO Sign-off check did not pass. Please inspect
its details first: checkout, fetch, timeout or infrastructure errors
need their own recovery, not a rewrite of otherwise signed commits.

If the log confirms a missing Signed-off-by trailer, amend the
affected commit with git commit --amend -s; for multiple commits,
use an interactive rebase against the current base from the correct
base-repository remote and sign off each affected commit. Push the
rewritten PR branch with git push --force-with-lease origin HEAD.

…ed-1m-remeasure

Signed-off-by: Lihua <1017343802@qq.com>
The quota context-capture navigation builds reader commands with POSIX
shlex.join, which single-quotes a path containing spaces and escapes an
embedded apostrophe with the '"'"' sequence. The capacity runner's own
splitter only recognized double quotes, so a temporary directory with a
space broke the reference path into several arguments and aborted the
whole --cli arm before its first sample.

The splitter now decodes exactly what the generator emits — single
quotes, double quotes, backslash escapes inside double quotes — and
fails loudly on unbalanced quoting instead of mis-splitting a reference.
It lives in the shared report module with unit tests covering the spaced
and apostrophe paths the review reproduced. A real rehearsal --cli run
from a space-containing TMPDIR completes both axes with three CLI
mutations each and verified cleanup; the empty directory shells a
just-stopped runtime grandchild recreates afterwards are disclosed, not
hidden.

Refs loopx-project#4224

Signed-off-by: Lihua <1017343802@qq.com>
@LIHUA919
LIHUA919 force-pushed the codex/sqlite-d2-matched-1m-remeasure branch from 7442e5b to 09db913 Compare November 7, 2026 20:00
@LIHUA919

LIHUA919 commented Nov 7, 2026

Copy link
Copy Markdown
Contributor Author

Head corrected to 09db913c5 — identical tree to 7442e5b5b (verified empty diff), re-created only so the merge commit carries the required Signed-off-by trailer (the previous merge used --no-edit without it, failing the DCO check). The fix commit is unchanged.

@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 | reasoning_effort=max

[P2] 清理成功后,原运行时仍能重建两个临时目录。 最后一次 CLI 更新后,stopRuntime 等到停止请求的回执就返回。将同一进程的真实退役 mkdir 延后 500 毫秒,两个轴都报 cleanup_verified=true,随后原进程各重建了一个临时目录,里面只有空的运行时子目录。在试验目录内复用 restart_effect_runtime(wait_for_exit=True),核对停止结果,进程退出后再删除目录;超时保留失败并避免覆盖首个测量错误。 从含空格及单引号的 TMPDIR 执行 rehearsal --cli,延后最后一次真实运行时的退役 mkdir,并在进程结束后核对两个轴目录均未重建。 停止调用 清理判定 退役锁 mkdir 已有退出接口

本轮提交 09db913c55ba308d6cf74054e50ce3d91c9272af 与 7442e5b5b58a099ec27640633be17c9a0e6cc747 的完整源码树一致。此次更新补齐人工合并提交的签署。当前主干 e58ba30bc949c29ec90c570a8362fb1e7ec9f3be 的净改动核对无重叠,原测量及退役证据适用。

动机 / Motivation

维护者在本机运行 SQLite 容量演练,用两组临时数据库核验配额读取、Todo 写入和退出后的清理。 临时路径带空格和单引号时,上轮提交在第一组读配额时退出,第二组无结果。当前提交跑完 100 和 1,000 两组,每组写入 3 次 Todo。 配额翻页已恢复。将真实运行时的退役目录操作延迟 500 毫秒后,两组虽都报清理成功,退出后仍留下运行时重建的目录。 这次评审核对本地容量入口、结果回读和临时数据清理。正式 D2 容量与恢复资格另按原工作负载验收。 上一轮评审

改动思路 / Approach

容量脚本按原 quota 命令返回的读取引用读取完整捕获。解码后以独立 argv 参数启动子进程,汇总翻页时间,然后校验同一个 Todo 和最终 SQLite cursor。纯参数单测和真实带引号路径覆盖不同边界。退出确认已有可复用的运行时接口,目录重试应处理进程退出后的暂时删除失败。 读取与计时 Todo 写入与回读

具体改动 / Changes

splitShellCommand 保留 POSIX shlex.join 产生的带空格和引号的单个参数。两个例程文件和一个测试文件共增加 101 行、删除 9 行。公开合同为 docs/reference/sqlite-authority-store.md,本次依据主干 e2371c476805f67903dd3c338a7e2712f577c9cc。

  • rehearsal-cli 已验证。普通路径和带空格及单引号路径的真实演练均完成两轴,配额、状态和更新各有三个样本。
  • disposable-cleanup 尚未满足。真实关闭回执后仍可重建目录;等待原进程退出的同提交对照解决了本次复现。
  • qualification-boundary 保持。演练报告的总状态为 incomplete,正式 D2 容量资格仍由匹配负载验收。 执行合同 清理与结果合同 参数回归测试

对主干的风险 / Risks

在 Node 24.21.0 和 SQLite 3.53.4 上,普通与带引号路径均通过。本次延迟只加在原进程退役时第一次真实建目录之前,停止响应、SQLite 写入、删除和重建均实际执行。两组各重建一次。保持同样延迟,只把停止步骤替换为等待退出,两组目录均未重建。日常自然发生频率待测。

同一源码树的 TypeScript 检查、11 项容量测试、三文件公开边界扫描和标准 premerge 的 4 项直接检查与 6 项选中检查通过。新的签署提交已重跑真实带引号路径、延迟和等待退出对照。按仓库 DCO 规则独立核对当前提交范围,三次提交均有有效签署。托管 CI 未读取。 DCO 工作流

我的整体评价 / Verdict

带引号的配额读取已修复,维护者可以用原命令拿到两组样本。反复运行的清理结果仍会误导操作者。请让清理以真实退出为前提,并用相同延迟验证目录在退出后保持清除。受影响入口为 CLI 文本与 JSON 报告,本次没有渲染界面可检查。

English verdict: REQUEST_CHANGES. Quoted capture paths now work. The real retiring runtime can still recreate both axis directories after cleanup was reported successful. Wait for observed process exit before deleting.

// times before declaring the disposable database uncleaned.
for (let attempt = 0; ; attempt++) {
try { rmSync(root, {recursive: true, force: true}); } catch { /* retried below */ }
axis.cleanup_verified = !existsSync(root);

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.

[P2] 先等待原进程退出再确认目录清理。将真实退役 mkdir 延后 500 毫秒后,两个轴均报 cleanup_verified=true,已收到关闭回执的原进程随后分别重建目录。同一延迟下使用 restart_effect_runtime(wait_for_exit=True) 后,两组目录均无残留。请复用该接口,并保留超时及首个测量错误。

@LIHUA919

LIHUA919 commented Nov 7, 2026

Copy link
Copy Markdown
Contributor Author

CI attribution note for the windows-powershell failure on head 09db913c5: the failing step is the agent-facing CLI base/head output differential (cli_output_probe_fixture.py, _assert_collection_growth_and_bootstrap_duplication), a Python CLI-semantics harness. This PR touches only examples/coordination/sqlite-capacity.ts, sqlite-capacity-report.ts, their test file and docs — no Python, CLI, or output surface. Another open PR (#8290) shows the same check failing in the same window, so this looks main-side/parallel, not introduced here. If it still blocks merge-gate, that attribution stands for the unchanged head. All other checks so far: 16 SUCCESS, remainder queued/running.

@LIHUA919

LIHUA919 commented Nov 7, 2026

Copy link
Copy Markdown
Contributor Author

Extending the CI attribution to the second failure, kernel-contracts, on the unchanged head 09db913c5: the failing lint is loopx/control_plane/turn_driver/decision_capture.py:659: Function is missing a return type annotation [no-untyped-def] — the inner def render(plan, present): introduced by main's #8293 (b586e92f9, 2026-11-08). This PR does not touch decision_capture.py or any Python file; the violation arrived through the required merge of current main (base e2371c476 line already contained it at merge time). Same class as the windows-powershell CLI-differential failure noted earlier: main-side, inherited by every PR that merges current main. Both attributions stand for the unchanged head; a one-line annotation fix on main clears kernel-contracts. Remaining checks are still running.

…ed-1m-remeasure

Signed-off-by: Lihua <1017343802@qq.com>
@LIHUA919

LIHUA919 commented Nov 8, 2026

Copy link
Copy Markdown
Contributor Author

Head advanced to 3ecf768e2 — a signoff-carrying merge of current main (b0474082c), which already contains the decision_capture.py return-annotation fix that caused the kernel-contracts failure attributed earlier (no PR-side change was needed; the fix landed on main separately). Fix commits are unchanged; the 11 capacity tests and typecheck pass on the merged tree. CI re-runs on this head — kernel-contracts should clear; the windows-powershell attribution stands unless main's CLI-differential state also changed.

The receipt-only runtime.shutdown stop let a retiring runtime's delayed
exit-time lock mkdir recreate the axis directory after cleanup_verified
was recorded. Reuse restart_effect_runtime(wait_for_exit=True), require
its stopped result before deleting, and keep the first measurement
failure when the stop cannot prove exit.

Signed-off-by: Lihua <1017343802@qq.com>
@LIHUA919

LIHUA919 commented Nov 8, 2026

Copy link
Copy Markdown
Contributor Author

Head advanced to 4a530289b — addresses the P2 from the 2026-11-07T20:06Z review.

Change

stopRuntime no longer returns on the shutdown receipt. It reuses restart_effect_runtime(wait_for_exit=True) (the existing disposable-owner interface) and requires stopped=true before the axis temp root is deleted; a stop that cannot prove observed exit fails the axis without overwriting the first recorded measurement error. Source-level regression added (cleanup is anchored to observed runtime exit and keeps the first failure); no production surface outside the runner changed.

Verification (all on 3ecf768 + this commit, Node 22.22.3 / SQLite 3.51.3, macOS)

  • npm run typecheck:control-plane — pass.
  • sqlite_capacity.test.ts — 12/12 pass (11 prior + the new regression).
  • uv run --extra test loopx canary premerge --from-git-diff --git-diff-base origin/main — all direct and selected checks pass, 0 failures.

Same-delay contrast, quoted TMPDIR (/tmp/loopx cap 'quoted-…, space + single quote), rehearsal --cli, 500 ms delay injected before the retirement mkdir in acquireFileMutationLock (uncommitted local patch, heavier than the review's last-runtime-only delay since every lock acquire is delayed):

  • Old receipt-only stop (same delay): axis 100 reports cleanup_verified=true yet after process end the axis root is recreated containing only the empty runtime subdir (loopx-effect-runtime-1158e7e12c5e) — the review's misleading-cleanup repro.
  • This fix (same delay, 56 s run): both axes passed, cleanup_verified=true, 3 CLI commits each, and 3 s after process end zero loopx-sqlite-capacity-* directories remain.
  • Clean tree (no delay), quoted TMPDIR: both axes passed, cleanup verified, no recreation.

Delayed-run reports kept locally under ignored .local/; no measurement surface changed (stop happens outside the timed window, as before).

This branch has not been deployed

No deployments
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.

2 participants