Skip to content

fix: harden post-compaction continuation guard (supersedes #61) - #62

Merged
willytop8 merged 3 commits into
mainfrom
wr/61-compaction-guard-fixes
Aug 22, 2026
Merged

fix: harden post-compaction continuation guard (supersedes #61)#62
willytop8 merged 3 commits into
mainfrom
wr/61-compaction-guard-fixes

Conversation

@willytop8

@willytop8 willytop8 commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Summary

Follow-up to #61 (and #58 before it) hardening the post-compaction goal
continuation guard. This branch keeps @harryzhou2000's epoch-guard work from #61
as its base — his commit is preserved — and corrects three issues that only
surface against the event shapes OpenCode actually emits.

The event shapes were confirmed against the vendored @opencode-ai/sdk
type definitions rather than inferred from test fixtures:

  • EventMessageUpdated is { type, properties: { sessionID, info } } — it never
    carries parts. Parts arrive on message.part.updated, which this plugin does
    not observe.
  • EventSessionCompacted is { type, properties: { sessionID } } — no id, no
    compactionID/summaryID/messageID, and no sync variant in the plugin-facing
    Event union.

What changes

  1. Identity-less compaction re-delivery no longer trips the breaker. Because a
    real session.compacted has no identity field, the identity-based dedup from
    fix: guard goal continuation across compaction epochs #61 can never fire against a live host, so a single duplicate delivery would
    reach MAX_STALLED_COMPACTIONS and abort the session. Re-deliveries are now
    recognized by the absence of any message activity since the previous
    compaction (a genuine new compaction is always preceded by messages, since the
    context has to grow again to trigger one). New messageSeenSinceCompaction
    flag, persisted and restored fail-open.

  2. A completion/blocked claim on the retained compaction source is honored.
    The terminal checks ([goal:complete] / [goal:blocked]) are split off from
    the progress/checkpoint boundary. The compaction source still gates
    checkpointing and stall heuristics, but no longer suppresses a terminal claim
    on the retained turn — which had survived the compaction unprocessed, so
    swallowing it discarded a real result and spent another continuation.

  3. Remove the inert tool-part detection branch. messageHasToolCall against
    the message.updated envelope is always false (no parts on that event), so it
    was dead. The breaker resets on assistant output-token progress, which a
    tool-using turn also produces. messageHasToolCall is unchanged and still
    correct at its other call site, which reads API-fetched messages that do carry
    parts.

Tests

  • Rewrote the productive-turn test onto the canonical properties.info shape with
    realistic output tokens (the original used an envelope OpenCode does not emit and
    output: 0, which rested the assertion entirely on the now-removed branch).
  • Added: identity-less re-delivery does not trip the breaker; a completion claim
    on the retained compaction source is honored; identity-less compactions
    separated by message activity still trip the breaker; tool parts on a
    message.updated event are not a productive-turn signal. The first two fail
    against this branch's base with the source fix reverted.

Verification

npm test (394/394), npm run type:check, npm run test:mutation (67/67),
npm run smoke, all green; also green on Node 18.

Not included (deliberately)

  • Whether to raise MAX_STALLED_COMPACTIONS or drop the session.abort on trip
    is left as a separate discussion; the false-positive paths that made the abort
    dangerous are closed here.
  • The idle-event dedup reads event?.id, but EventSessionStatus /
    EventSessionIdle carry no id either, so seenIdleEventIDs never dedups in
    production. Same class of issue as (1), predates fix: guard goal continuation across compaction epochs #61 — worth its own issue.

Closes #61.

🤖 Generated with Claude Code

@willytop8
willytop8 merged commit a1f3717 into main Aug 22, 2026
25 of 26 checks passed
@willytop8 willytop8 mentioned this pull request Aug 22, 2026
@harryzhou2000

Copy link
Copy Markdown
Contributor

@willytop8 Thanks for your help!

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