Repository navigation
fix: prune/recommend scan history once per turn (#498) - #499
Conversation
prune rebuilt the tool-result position map inside pairSafeAnchorIndex for every active summary anchor (O(anchors x N)); recommend rescaned all blocks' effectiveMessageIds for every candidate message (O(visible x coverage)). Both now share one O(N) structure per pass: prune builds run-start + prefix tool-result-end arrays once per rebuild, recommend precomputes the covered-id set once per helper call (exact-ID semantics unchanged). Behavior-preserving: verified byte-identical outputs vs the previous implementation on 3000 randomized prune inputs, 2000 recommend input/config combinations, hand-crafted pairing edge cases (multi-step fixed point, duplicate/unmatched tool ids), and the issue's 21k-message session through full processTurn including second-pass re-feed.
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)In your adapter project: npm install acp-kernel@pr-499Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf acp-kernel-pr499.tgz
npm install ./packageThis comment is automatically updated on each push. |
[bot] 🏷 收到。这是带 |
[bot] 🏷 Review 完成(PR #499,base = 当前 master tip 633b8c8,单 commit,CI 全绿:test(22)/test(24)/pr-validation/build-artifact)。独立验证手段:逐行等价性分析 + 自跑 2000 例随机差分测试(base vs head,含重复/未匹配 call id、dangling block id、active/inactive 块)+ 本地定向测试(新 8 例 + 既有 prune/recommend 相关 69 例全过)+ tsc --noEmit 干净 + base/head 二遍过程对比。 结构化七问:
测试有效性:断言有牙——4 个精确放置用例钉死旧实现输出、规模级结构不变量(499 条输出、132 个 summary 各恰出现一次且保序、无未答工具调用、二遍稳定)、covered-set 门控语义(inactive 不排除 / 合成头排除)。wall-time 用宽松 <10s 守卫保 CI 确定性是正确取舍,性能证据在正文测量(中位数 16 次:prune 87.9→7.7ms,recommend 31.1→3.6ms)。离线 3000 例差分未入库可接受(旧实现合并后即消失,入库测试改钉语义)。 diff 整洁度:3 文件 +437/-43,全部切题,无空行/锁文件噪音,commit 规范(fix: + Fixes 引用)。 合并注意事项:open PR #490/#491 也改 结论:可合(人工合并)。行为保持经独立差分验证成立,回归审查无发现,无需补修或立项。 |
Closes #498
What
Two per-turn hotspots in large sessions, both caused by rescanning the full history:
src/prune.ts):rebuildMessagescalledpairSafeAnchorIndexfor every active summary anchor; each call rebuilt the tool-result position map over ALL messages and ran a prefix scan — O(anchors × N).src/recommend.ts):isSyntheticOrPrunedlooped over every block'seffectiveMessageIds.includes(message.id)for every candidate message, in bothcomputeProtectedRefsandbuildCompressibleRanges— O(visible × coverage).Fix
buildAnchorPairingIndex: first tool-result position per call id, assistant-run starts, prefix-max of tool-call end positions); each anchor resolves by array lookups + fixed-point jumps instead of a rescan. The index is built only when there are anchors.coveredMessageIds) and usesSet.has. Exact-ID semantics unchanged (base-ID normalization stays exact-id membership vs block.effectiveMessageIds: remaining same-class sites (latent until sub-id projections ship) #234).SUMMARY_HEADERfrom prune (same string, single source).Behavior preservation (verified)
Outputs identical to the previous implementation, verified differentially against a pre-edit snapshot of
src/:processTurnon the issue's session shape (21,751 messages, 132 active blocks): entire output object deep-equal, including a second-pass re-feed comparisonThis PR does not change the #286 tool-call/result pairing guarantee or any rendered output — it only changes how fast the same answers are computed. No new config, no new defaults, no prompt-cache byte changes.
Measurements (issue repro session, this machine, median of 16 runs)
(The issue reported ~132ms/~45ms on the reporter's machine; the ratios should transfer.) Output remains 499 messages.
Tests
New
tests/prune-recommend-scale.test.ts(8 tests): exact-placement pairing cases pinned against the old implementation's outputs; scaleprocessTurncorrectness (499 messages, all 132 summaries placed exactly once in order, no unanswered tool calls, second-pass stability); scale recommend correctness (covered ids never appear compressible); covered-set semantics (inactive blocks don't exclude; synthetic header does). A deliberately loose wall-time guard (<10s) keeps the suite deterministic across CI machines; the actual perf proof is the differential verification above.Note for review
pruneencodes the #286 tool-pair atomicity invariant (§7.3 item 5). This change is behavior-preserving, not a contract change — proven by the differential verification above — but it touches that module plusrecommend, so it is not auto-merge eligible under §7.4 (two modules + contract-adjacent node); human review requested.