Skip to content

Compaction preserves the loop and drops the substance - #544

Open
TheGreatAxios wants to merge 4 commits into
mainfrom
cl-6906-compaction-preserves-the-loop-and-drops-the-substance
Open

Compaction preserves the loop and drops the substance#544
TheGreatAxios wants to merge 4 commits into
mainfrom
cl-6906-compaction-preserves-the-loop-and-drops-the-substance

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Collaborator

DO NOT AUTO-MERGE

This touches context-management (compaction/summarization), which is human-gated in this repo. It carries needs-sawyer-review and must wait for Sawyer's manual review and approval before merging. Do not squash-merge, auto-merge, or merge on green CI alone.

Summary

src/session/compactor.ts anchored every errored tool_result (score +5, threshold 5) regardless of whether it repeated, so a failing-edit retry loop got preserved verbatim past the summary boundary while healthy context was summarized away. Pairing anchors were then pulled in with no cap, so maxAnchorTurns was not a real bound. src/session/summarizer.ts seeded its summary prompt from the last 8 assistant snippets, which during degeneration is the looped text itself, and silently swallowed summary failures in a bare catch.

Changes

  1. Errored results no longer auto-anchor. A lone error now scores 3 (below the threshold of 5); two distinct errors on one turn still clear it. Runs of the same repeating error (same tool name + matching error-text prefix) collapse to their last occurrence before scoring, so a retry loop contributes one representative instead of scoring every iteration.
  2. Degenerate tails are filtered from the summary prompt. condenseTurns now drops assistant snippets flagged by the existing detectRepetition (from src/subagent/repetition.ts) before they reach the summarizer — no new detector written.
  3. Pairing anchors respect maxAnchorTurns. Scored-anchor selection now takes each candidate's tool_call/tool_result pair closure whole-or-nothing against a shared budget, so the cap is a real bound. Partners of turns that straddle the recent-window boundary are still pulled in unconditionally (required for a well-formed tool sequence) and count against the same budget; the initiating task remains an explicit, documented exception outside the cap, as before.
  4. Superseded-result stubbing extended to grep/search_files/list_dir. These are deduped by tool name + canonicalized (key-order-independent) arguments, the same mechanism read_file already used for path identity. run_shell is deliberately excluded: the same command is not idempotent (builds, tests, mutations), so an older run_shell result can be the only record of a genuinely distinct outcome.
  5. CompactorConfig.summarize now accepts the optional workflow context and actually receives it. summarizer.ts already supported a SummaryContext parameter, but the compactor called summarize with one argument, so it was always undefined. Added summaryContext to CompactorConfig and threaded it through. The bare catch in createModelSummarizer is replaced with a logged warning and both failure paths (empty output, thrown error) now prefix the deterministic fallback with [Model summary unavailable (...)] so a lossy fallback is distinguishable from a real model summary.

Each item has a regression test in src/context-compactor.test.ts, tests/unit/compactor-pairing.test.ts, and tests/unit/summarizer.test.ts.

Test plan

  • bunx prettier --check and bunx eslint on all touched files — eslint reports the same count/kind of pre-existing errors as the untouched baseline (a known repo-wide issue); no new violations introduced.
  • bun run typecheck — clean.
  • bun run build — clean.
  • bun test ./src ./tests ./evals — 5127 pass, 1 fail (src/agent/lsp-availability.test.ts, pre-existing and unrelated — fails identically on main in this worktree because it's a git worktree checkout, not a .git directory).

Fixes CL-6906

Errored tool_results scored above the anchor threshold on their own, so a
failing-edit retry loop anchored every iteration verbatim while healthy
context got summarized away. Score errors below threshold and collapse
runs of the same repeating error to one representative before scoring.

Pairing anchors were pulled in with no cap, making maxAnchorTurns not a
real bound; the scored-anchor selection now takes each candidate's pair
closure whole-or-nothing against a shared budget.

The summary prompt seeded from the last 8 assistant snippets, which during
degeneration is the looped text itself; filter snippets flagged by the
existing detectRepetition detector before they reach the summarizer.

Superseded-result stubbing only covered read_file; extend it to grep,
search_files, and list_dir (byte-identical arguments), excluding run_shell
since the same command is not idempotent.

CompactorConfig.summarize was typed with one argument even though the
summarizer already accepted a workflow context, so the context never made
it through; widen the type and thread cfg.summaryContext() into the call.
Replace the bare catch in the model summarizer with a logged warning and a
fallback marker so a failed LLM summary is distinguishable from a real one.
@TheGreatAxios TheGreatAxios added the needs-sawyer-review Touches human-gated context-management code; requires Sawyer's review before merge label Aug 23, 2026
@linear-code

linear-code Bot commented Aug 23, 2026

Copy link
Copy Markdown

CL-6906

The TUI wrapped summarize to inject the active workflow, but the pruning
compactor always called summarize with one argument, so mid-workflow
compaction still lost the step contract. Also make the max-anchor fixture
score above the new threshold so the cap test actually exercises it.
Main's repetition detector now needs sixteen consecutive repeats, so ten copies of the loop phrase no longer trip it. Twenty copies still flag, and the Unreleased changelog records the compaction-quality pass.
@TheGreatAxios TheGreatAxios mentioned this pull request Aug 23, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-sawyer-review Touches human-gated context-management code; requires Sawyer's review before merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant