Raised as finding N1 in the re-review of #32 with "fix the wording in a follow-up, unify the pass order"; #32 merged and the drift is unchanged on main (5dbbc47).
The defect
src/strategies/autobiographical.ts
| path |
order |
selectAdaptive (~:8135-8143) |
pruneToolEntries → trimOrphanedToolUse → enforceToolPairing |
selectHierarchical (~:9480-9484) |
trimOrphanedToolUse → enforceToolPairing → pruneToolEntries |
pruneToolEntries' per-tool last-N tally counts every tool_result occurrence whose id maps to a known tool. On the hierarchical path the stub and relocated results that enforceToolPairing inserts are therefore counted toward toolResultMaxLastN, and can push one more real older result into the [Result truncated — …] marker. On the adaptive path they can't, because pruning already ran.
So the same store, same config, same budget renders different history depending on which selector ran.
Why it matters beyond the truncation
This is precisely the class of cross-path drift that produced the original #32 blocker — enforceToolPairing was wired into one tail and not the other, and nobody noticed because the two tails were never required to be identical. Leaving the orders divergent leaves the next such omission equally invisible.
Fix
Pick one order and use it in both places. The review's preference was hierarchical's trim → enforce → prune, either:
- minus the stub-counting side effect, or
- excluding
STUB_TOOL_RESULT_TEXT blocks from the pruneToolEntries tally.
A test that renders the same fixture through both selectors and asserts identical output would pin the contract.
Refs: re-review of #32 (finding N1).
Part of the 2026-09-08 merged-PR review-debt harvest; lower-severity items from the same pass are in #92.
Raised as finding N1 in the re-review of #32 with "fix the wording in a follow-up, unify the pass order"; #32 merged and the drift is unchanged on
main(5dbbc47).The defect
src/strategies/autobiographical.tsselectAdaptive(~:8135-8143)pruneToolEntries→trimOrphanedToolUse→enforceToolPairingselectHierarchical(~:9480-9484)trimOrphanedToolUse→enforceToolPairing→pruneToolEntriespruneToolEntries' per-tool last-N tally counts everytool_resultoccurrence whose id maps to a known tool. On the hierarchical path the stub and relocated results thatenforceToolPairinginserts are therefore counted towardtoolResultMaxLastN, and can push one more real older result into the[Result truncated — …]marker. On the adaptive path they can't, because pruning already ran.So the same store, same config, same budget renders different history depending on which selector ran.
Why it matters beyond the truncation
This is precisely the class of cross-path drift that produced the original #32 blocker —
enforceToolPairingwas wired into one tail and not the other, and nobody noticed because the two tails were never required to be identical. Leaving the orders divergent leaves the next such omission equally invisible.Fix
Pick one order and use it in both places. The review's preference was hierarchical's
trim → enforce → prune, either:STUB_TOOL_RESULT_TEXTblocks from thepruneToolEntriestally.A test that renders the same fixture through both selectors and asserts identical output would pin the contract.
Refs: re-review of #32 (finding N1).
Part of the 2026-09-08 merged-PR review-debt harvest; lower-severity items from the same pass are in #92.