feat: trustworthy tool summaries, semantic audit, and repetition collapsing#7
Merged
Merged
Conversation
Bash/Read results carry no toolUseResult.success field, so every failed command was rendered as "-> ok: Exit code 1" — misleading LLMs consuming injected context. Status now follows ADR-003's ladder: explicit success field, then is_error:true on the tool_result block (previously unparsed), then a conservative sniff list (non-zero "Exit code N", hook error), else ok. Failure excerpts skip noise lines (line-number prefixes, bare exit code lines, hook boilerplate) and widen to 200 runes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UQYeDtvg1CQYvirZ4jWC5
Successful Edit results now render "-> ok (+A, -D @ L<n>)" computed from toolUseResult.structuredPatch hunks; Write renders "-> ok (new file, N lines)"; missing patch data falls back to the bare status (ADR-003 decisions 3-4). Unknown tools show their first input key/values instead of a bare tag, so new Claude Code tools degrade gracefully. Also fixes the pre-existing root cause that defeated ADR-002's per-tool suppression on real transcripts: tool names live on the assistant tool_use block, not on toolUseResult (commandName/agentType are absent for Bash/Read/Write/Edit), so RawName was always empty. ReadFile now correlates tool_use id -> name and resolves result names through it, covered by pipeline-level regression tests that parse realistic two-entry fixtures instead of hand-filled RawName values. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UQYeDtvg1CQYvirZ4jWC5
writeContextHeader silently skipped the header whenever the session-meta JSON was absent — and upstream stopped producing those files, so every recent session's context output started mid-dialogue with no hint of which project or conversation it was. The fallback header now derives session id, project (from event cwd, else transcript directory), and date (first non-empty event timestamp) from the transcript itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UQYeDtvg1CQYvirZ4jWC5
Session-meta JSON files stopped being produced upstream, so every recent session fell back to the header scan, which showed 0m durations and blank previews for inherit-style sessions. Duration now derives from the transcript's first/last timestamps (last one found via a bounded 16KB tail read, never a whole-file load). The preview scan no longer lets noise lines (command tags, skill injections, tool results, interrupt sentinels) consume the candidate budget, and falls back to a [/command args] preview when no genuine prompt exists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UQYeDtvg1CQYvirZ4jWC5
Usage entries now carry result (ok/error) and a one-line error message, written after the command finishes via a begin/finalize split around the existing exitOnError choke point — failures before target resolution are captured too. Legacy entries without the field read back as unknown, never as errors. The usage query normalizes the pre-rename "inject" command to "inherit" in both filter and display, and local builds resolve their version from runtime/debug.ReadBuildInfo instead of "dev". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UQYeDtvg1CQYvirZ4jWC5
ComputeStats kept its own copy of the compaction logic, so the KEPT category sum drifted from the Filtered total (some categories counted pre-compression text, join newlines went unaccounted, and formatter-side cc-session collapsing was invisible). Filtered is now measured from the actual read-render output via a content sink threaded through the formatter, categories derive from that same pass, and the residual template bytes (timestamps, role labels, indentation) surface as an explicit "render overhead" row — the breakdown now reconciles to the character. System-reminder/context-usage blocks that the renderer drops are no longer miscounted as kept user text. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UQYeDtvg1CQYvirZ4jWC5
- analyzer references formatter.Category* constants instead of re-typed string literals, so the category-name invariant is compiler-enforced - render pipeline params (agentIDs/opts/out/sink) bundled into a renderContext struct; output verified byte-identical before/after - mutation-guard tests: countContentLines' documented no-trailing-newline and empty-content contract, and the (?m)^Exit code N$ anchor that keeps mid-sentence mentions from sniffing as FAILED - stats test expectation hardcodes "??-?? ??:??" instead of borrowing parser.FormatTimestamp into the expected value Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UQYeDtvg1CQYvirZ4jWC5
Bucket CUT content by semantic risk (failure_output first, harness_noise last), report failed-result length stats (count/median/p90/max) to inform the upcoming head+tail error retention threshold, and annotate audit samples with their bucket. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SaBPDHw1cZDxhehYrqFgGe
Records the fleet length distribution (379 sessions), the adversarially reviewed two-tier design (threshold ~1,500, global-ranking head+tail+signal truncation, self-describing omission markers, re-derivability budgets), and the measured rejection of project-path rescue (<1% net coverage, half noise). Implementation deferred until the expand-telemetry feedback loop exists; revisit triggers listed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SaBPDHw1cZDxhehYrqFgGe
Truncated/garbage/null-byte lines error explicitly without panic or silent loss; a 1MB single line guards against a future bufio.Scanner 64KB-token regression; Truncate stays valid UTF-8 at emoji-ZWJ and combining-char boundaries (grapheme-cluster integrity documented as a known limitation). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SaBPDHw1cZDxhehYrqFgGe
Prerequisite for ADR-004's feedback loop: expand entries now carry tool_ids (all requested short IDs, including unresolved ones — the goal is what the caller wanted to inspect). Legacy entries without the field read back empty; display appends tools: only for expand rows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SaBPDHw1cZDxhehYrqFgGe
Consecutive failed calls of the same tool whose command shares a prefix collapse to one line with a xN count and the last error (last tool id kept so expand reaches the final state); consecutive successful Reads of the same file collapse to a single xN line. Collapsing never crosses an interleaved event, never hides a distinct failure, and -verbose-bash exempts retry collapsing per the ADR-001 precedent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SaBPDHw1cZDxhehYrqFgGe
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SaBPDHw1cZDxhehYrqFgGe
…token prefix Adversarial verification (Codex) found two violations of ADR-005's invariants: distinct errors under a prefix-matched command merged into one line hiding the earlier error, and bare HasPrefix let 'git add' absorb 'git add-on-something' (and a bare 'git' absorb everything). Collapsing now additionally requires identical failure excerpts, and a prefix match needs a whitespace token boundary plus a multi-token shorter command. ADR-005 revised to match, including the rendered-event boundary semantics and expanded negative knowledge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SaBPDHw1cZDxhehYrqFgGe
…g in tests ProjectDirName (single source of truth, was duplicated across production caller detection and two test helpers) now also normalizes backslashes and drive colons — a no-op on unix paths; the SKILL.md frontmatter test helper trims CR before quote stripping. Both regressions are pinned by OS-independent tests that inject windows-style inputs directly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SaBPDHw1cZDxhehYrqFgGe
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SaBPDHw1cZDxhehYrqFgGe
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two-day overhaul of what an inheriting Claude session actually sees, driven by real-transcript evidence: the compressed output previously lied (failures rendered as
-> ok, edits invisible), and the tool's own metrics couldn't be trusted to tune it.Injected-context correctness
toolUseResult.success→is_error→ conservative failure sniffing. Real Bash/Read results carry nosuccessfield and were blindly defaulted to ok —-> ok: Exit code 1contradictions are gone.Exit code N), 200-rune budget for failures.-> ok (+15, -3 @ L42)/(new file, N lines)fromstructuredPatch— plus a fix for a pre-existing bug whereRawNamenever resolved on real transcripts, so ADR-002's per-tool suppression had never actually fired.[ToolName].FAILED ×3: <error>, only when commands share a token-boundary prefix and errors are identical) and consecutive same-file Reads ([Read#id ×N] path). Invariants adversarially verified; two violations found and fixed pre-release.Discoverability & metrics
list: durations no longer all0m(tail-read timestamp fallback); previews survive command-first sessions.context: minimal header when session metadata is missing.stats: KEPT breakdown now measured from the real render pipeline — reconciles with Filtered to the character.audit: semantic histogram of CUT content (risk-descending) + failed-result length distribution.result/error),inject→inheritalias normalization, version fallback via BuildInfo, and expand now logs requested tool ids.Decision records
Tests
Benchmark
Compression holds at ~80% saved (baseline 81.9%), break-even still turn 1 — the added diff/error detail is paid for by collapsing and boilerplate suppression.
🤖 Generated with Claude Code
https://claude.ai/code/session_01SaBPDHw1cZDxhehYrqFgGe