- Replaced legacy `compaction.strategy` and `remoteEnabled` settings with `compaction.methodOrder` across session maintenance, schema, and tests.
- Added automatic fallback mechanism to try subsequent compaction methods upon failure or unsupported model capabilities.
- Added mouse drag-and-drop reordering support and click handlers to multi-select settings submenus.
- Updated documentation and test suites to reflect ordered compaction strategy preferences and fallback chains.
- Replaced time-based sleeps and polling loops with event-driven promise resolvers and fake timers across agent and tool tests.
- Migrated test suites to share in-memory auth storage and fixtures using lifecycle hooks.
- Updated catalog model definitions, metadata, and configurations.
A recovered artifact:// read is an ordinary read result, so the next shake
pass elides it into a new artifact, indefinitely. Extends the 5f9558d17a
spill exemption to shake; the dead-end rescue gets a dedicated config
instead of falling through to AGGRESSIVE. Manual /shake unchanged.
Kept superseded summaries and preserveData durable while deriving forward transcript elision from the active compaction.
Added branch and rewind coverage for snapcompact archives and OpenAI remote replacement history.
Fixes#4090
Review follow-ups (Codex on #6362, round 5):
- #computeSnapcompactRescueMaxFrames now subtracts the kept tail AFTER the
archive (plus the existing fixed-context reserves) so the budget mirrors
what #compactionCreatedHeadroom will measure, and returns 0 when not even
one frame fits — the rescue bails instead of appending a rebuild that can
never create headroom (and would wedge prepareCompaction behind its
last-entry guard once elide fixes the real tail).
- Dead-end warnings now stamp the branch's LATEST compaction entry: the
post-pass path no longer badges the entry the rescue just superseded, and
the no-preparation path badges the rebuilt entry when the rescue appended
without creating headroom.
Claude-Session: https://claude.ai/code/session_014rh4JyWFkxgMhgFaEf8VBY
Review follow-up (Codex on #6362, round 4): rebuilding a non-tail archive
appends the replacement compaction at the leaf, so the branch tail becomes a
compaction entry that prepareCompaction's last-entry guard can never
summarize past — even after elide shrinks the oversized kept tool result
that was the real culprit. The rescue now estimates the kept tail AFTER the
latest archive and bails when it alone exceeds the recovery band, leaving
that shape to the elide/image tiers.
Claude-Session: https://claude.ai/code/session_014rh4JyWFkxgMhgFaEf8VBY
Review follow-ups (Codex on #6362):
- #rescueSnapcompactFrameOverflow now returns the CompactionResult and emits
session_compact for the rebuilt entry, so extensions see the entry that is
actually active instead of (only) the one the rescue superseded.
- The no-preparation auto_compaction_end now carries that result instead of
{result: undefined, skipped: true} when the rescue rewrote history — the
TUI rebuilds the transcript on result, so a successful rescue is no longer
presented as a benign no-op.
Claude-Session: https://claude.ai/code/session_014rh4JyWFkxgMhgFaEf8VBY
Review follow-ups (Codex on #6362):
- The !preparation frame rescue now counts as complete only when the rebuild
actually created headroom; otherwise the elide/image tiers still run and the
no-progress warning stays — a frame-count shrink alone must not suppress it
when the oversized tail is a kept message/tool result the archive rescue
cannot touch.
- #computeSnapcompactRescueMaxFrames now applies the same MAX_FRAMES_DEFAULT /
maxFramesForDataBudget caps as #computeSnapcompactMaxFrames, so a
threshold-derived count can never exceed what the rebuilt prompt can attach.
Claude-Session: https://claude.ai/code/session_014rh4JyWFkxgMhgFaEf8VBY
A branch whose last entry is a snapcompact CompactionEntry billed past the
compaction threshold (FRAME_TOKEN_ESTIMATE x frames) dead-ended on every
resume: prepareCompaction returns undefined (nothing after the entry to
summarize), and the #4786 elide/image rescue tiers only inspect
"message"/"custom_message" entries, so a type:"compaction" tail escaped both
and the "Compaction freed too little context" warning re-fired forever.
Add a dedicated first rescue tier that rebuilds the SAME archive locally (no
LLM, no network) by re-running snapcompact.compact() over the entry's
carried-forward source text at a maxFrames derived from the trigger
threshold's recovery band instead of the window-fit budget: planArchive
truncates the oldest chars to fit, so the rebuilt entry genuinely shrinks.
Persisting through appendCompaction lets the write-time
superseded-compaction elision drop the stale frame payload from the JSONL,
and the pass skips the misleading no-progress warning.
Fixes the loop reported in
https://github.com/can1357/oh-my-pi/issues/4786#issuecomment-5056055342
Claude-Session: https://claude.ai/code/session_014rh4JyWFkxgMhgFaEf8VBY