Skip to content

feat(compaction): opt-in trigger split and tokens reclaimed - #445

Merged
sirmalloc merged 10 commits into
sirmalloc:mainfrom
CorticalCode:feat/compaction-rich-formats
Jun 15, 2026
Merged

sirmalloc merged 10 commits into
sirmalloc:mainfrom
CorticalCode:feat/compaction-rich-formats

Conversation

@CorticalCode

Copy link
Copy Markdown
Contributor

Summary

Two opt-in, composable, per-item add-ons for the Compaction Counter, parsed from data already present in the compact_boundary transcript markers — no new data source, hook, cache, or dependency:

  • s — trigger split: ↻ 3 (2 auto, 1 manual)
  • t — tokens reclaimed: ↻ 3 ↓887.0k

The default ↻ N and the existing f / n / h controls are unchanged; the two toggles are independent per-item and stack. Builds on #425 (marker-based counting), continuing the widget from #282.

How it works

  • compaction.ts returns { count, byTrigger, tokensReclaimed } from the same single transcript scan it already performs. A missing or unrecognized trigger is bucketed as unknown (never guessed); tokensReclaimed sums each compaction's preTokens − postTokens (floored at 0, only when both fields are present), so older transcripts predating postTokens simply show nothing.
  • The display add-ons reuse the shared isMetadataFlagEnabled / toggleMetadataFlag helpers, and formatTokens for the reclaimed figure.
  • formatTokens was extracted into a small leaf module to avoid a renderer → widget-registry → widget import cycle; renderer re-exports it, so existing importers are unaffected.

Test plan

  • bun test green — unit + widget coverage (trigger buckets incl. unknown, reclaimed math/floor, sidechain exclusion, both toggles, stacking, preview, and the reclaimed figure near 1M).
  • bun run lint clean; bun run build bundles.
  • Verified end-to-end on a real transcript: toggles render and compose, subagent (sidechain) compactions excluded from every stat, default output unchanged.

Note

formatTokens is also fixed by the separate small PR #444 (a rounding bug in renderer.ts). This PR's extracted format-tokens.ts carries the same one-line fix, so the reclaimed figure renders correctly near 1M and merging the two PRs in either order can't regress it — whichever lands second finds the fix already present.

CorticalCode and others added 10 commits June 14, 2026 13:50
…eclaimed) from markers

Parse compactMetadata.{trigger,preTokens,postTokens} during the existing
compact_boundary scan. No widget behavior change yet.

Co-Authored-By: Claude <noreply@anthropic.com>
…y naming

Address review feedback on the data layer: freeze the shared
ZERO_COMPACTION_STATS (incl. nested byTrigger); floor each marker's reclaimed
contribution with Math.max(0, ...) so postTokens>preTokens can't go negative;
rename metaObj -> metaRecord; add unknown-trigger and negative-reclaim tests.

Co-Authored-By: Claude <noreply@anthropic.com>
Adds a per-item showTriggers toggle that appends '(2 auto, 1 manual)';
unknown bucket shown only when > 0; omitted at count 0. Rendering now flows
through formatStats, shared by live render and preview.

Co-Authored-By: Claude <noreply@anthropic.com>
…cket

Co-Authored-By: Claude <noreply@anthropic.com>
Adds a per-item showReclaimed toggle that appends the reclaimed token total
(e.g. 887.0k) via the shared formatTokens humanizer; omitted when 0. Stacks
independently with the trigger split.

Co-Authored-By: Claude <noreply@anthropic.com>
…mport

CompactionCounter importing formatTokens from renderer.ts created a cycle
(renderer -> widget registry -> CompactionCounter) that broke isolated runs of
its test file with a TDZ error. Move formatTokens into src/utils/format-tokens.ts;
renderer re-exports it so existing importers are unaffected.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
- use shared isMetadataFlagEnabled/toggleMetadataFlag for the trigger/reclaimed
  flags instead of local copies
- freeze SAMPLE_STATS to match ZERO_COMPACTION_STATS
- guard tokensReclaimed against non-finite (overflow) marker differences
- docs: note the unknown trigger bucket and that reclaimed is floored/omitted at 0

Co-Authored-By: Claude <noreply@anthropic.com>
…ed leaf

The reclaimed display calls formatTokens; the extracted format-tokens.ts held the
pre-fix version, so a reclaimed total in [999950, 999999] rendered '1000.0k'
instead of '1.0M'. Apply the same threshold fix as PR sirmalloc#444 here, so the reclaimed
figure is correct and merging both PRs in either order cannot regress it.

Co-Authored-By: Claude <noreply@anthropic.com>
@sirmalloc
sirmalloc merged commit 3c1f472 into sirmalloc:main Jun 15, 2026
3 checks passed
@sirmalloc

Copy link
Copy Markdown
Owner

Looks good, it'll go out in the next release.

tahodev pushed a commit to tahodev/ccstatusline that referenced this pull request Oct 20, 2026
…c#445)

* refactor(compaction): compute stats struct (count, byTrigger, tokensReclaimed) from markers

Parse compactMetadata.{trigger,preTokens,postTokens} during the existing
compact_boundary scan. No widget behavior change yet.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(compaction): freeze zero stats, floor reclaimed at 0, clarify naming

Address review feedback on the data layer: freeze the shared
ZERO_COMPACTION_STATS (incl. nested byTrigger); floor each marker's reclaimed
contribution with Math.max(0, ...) so postTokens>preTokens can't go negative;
rename metaObj -> metaRecord; add unknown-trigger and negative-reclaim tests.

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(compaction): opt-in trigger split via (s) keybind

Adds a per-item showTriggers toggle that appends '(2 auto, 1 manual)';
unknown bucket shown only when > 0; omitted at count 0. Rendering now flows
through formatStats, shared by live render and preview.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(compaction): clarify zero-suffix test name; cover manual-only bucket

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(compaction): opt-in tokens reclaimed via (t) keybind

Adds a per-item showReclaimed toggle that appends the reclaimed token total
(e.g. 887.0k) via the shared formatTokens humanizer; omitted when 0. Stacks
independently with the trigger split.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: extract formatTokens to a leaf module to avoid a circular import

CompactionCounter importing formatTokens from renderer.ts created a cycle
(renderer -> widget registry -> CompactionCounter) that broke isolated runs of
its test file with a TDZ error. Move formatTokens into src/utils/format-tokens.ts;
renderer re-exports it so existing importers are unaffected.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(compaction): cover tokens reclaimed with a non-default format

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(compaction): document trigger-split and tokens-reclaimed toggles

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(compaction): apply code-review feedback

- use shared isMetadataFlagEnabled/toggleMetadataFlag for the trigger/reclaimed
  flags instead of local copies
- freeze SAMPLE_STATS to match ZERO_COMPACTION_STATS
- guard tokensReclaimed against non-finite (overflow) marker differences
- docs: note the unknown trigger bucket and that reclaimed is floored/omitted at 0

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(compaction): carry the formatTokens rounding fix into the extracted leaf

The reclaimed display calls formatTokens; the extracted format-tokens.ts held the
pre-fix version, so a reclaimed total in [999950, 999999] rendered '1000.0k'
instead of '1.0M'. Apply the same threshold fix as PR sirmalloc#444 here, so the reclaimed
figure is correct and merging both PRs in either order cannot regress it.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
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