Skip to content

Commit 2124bfa

Browse files
ufukaltinokalfonso-magic-context
authored andcommitted
test(e2e): make overflow-recovery version-agnostic (opencode 1.16 compaction change)
opencode 1.16 commit 7e09660c3 (#30749, 'respect disabled auto compaction on overflow') changed the post-overflow path: when compaction.auto=false (the Magic Context default), an overflow now errors the turn and goes idle instead of setting needsCompaction. Pre-1.16, needsCompaction triggered an in-turn compaction → a second transform pass → our emergency recovery (95% bump → historian → clear flag) completed SAME turn. On 1.16 there is no second in-turn pass, so recovery fires on the user's NEXT prompt. The plugin is correct on both versions — overflow detection persists needs_emergency_recovery + detected_context_limit on the overflow turn, and the transform.ts:519 consumer bumps to 95% and runs the recovery historian on the next transform pass. Verified live on 1.16.0: after the overflow turn needs_emergency_recovery=1/historian=0, and after a follow-up turn needs_emergency_recovery=0/historian=1/compartment written (recovered=YES). The TEST, however, asserted same-turn recovery (an opencode <=1.15 assumption), so it failed on 1.16 — which is why CI/release host-e2e was pinned to 1.15.4 and I had to downgrade locally to release. That pin was masking a stale test, not a plugin defect. Fixed: assert detection on the overflow turn, then drive a follow-up turn and assert recovery via persisted state. Verified 2/2 on BOTH 1.15.4 and 1.16.0; full OpenCode host suite 44/44 on 1.16.0. Co-authored-by: Alfonso [Magic Context] <288211368+alfonso-magic-context@users.noreply.github.com>
1 parent 56ca95e commit 2124bfa

1 file changed

Lines changed: 57 additions & 9 deletions

File tree

packages/e2e-tests/tests/overflow-recovery.test.ts

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@
2525
* 3. **Recovery** — The emergency recovery flag forces the percentage to 95%
2626
* even if the model's self-reported usage still looks low, which fires
2727
* the existing 95% emergency path (abort + historian + aggressive drops).
28+
* NOTE: recovery runs on a transform pass AFTER detection. On opencode
29+
* <=1.15 an overflow triggered in-turn compaction (a second pass same
30+
* turn), so recovery completed same-turn. On opencode >=1.16 (commit
31+
* 7e09660c3, "respect disabled auto compaction on overflow") a session
32+
* with `compaction.auto:false` — the Magic Context default — errors the
33+
* turn and goes idle with NO in-turn second pass, so recovery fires on
34+
* the user's NEXT prompt. The plugin is correct in both cases; this test
35+
* drives a follow-up turn and asserts on persisted state so it is
36+
* version-agnostic.
2837
*
2938
* 4. **Completion** — When historian successfully publishes a compartment,
3039
* the recovery flag is cleared so future turns aren't stuck at 95%.
@@ -174,13 +183,20 @@ describe("context overflow recovery", () => {
174183
// error from the provider.
175184
mainShouldOverflow = true;
176185

177-
// Fire the turn that will overflow. The full recovery cycle —
178-
// detection → bump percentage to 95% → historian → clear flag —
179-
// completes inside this single prompt's lifecycle because the
180-
// emergency path is intentionally synchronous (historian runs
181-
// inline at 95%). The SDK will still throw because the provider
182-
// returned 400, but the plugin has already recorded and recovered
183-
// from the overflow by the time the error propagates back.
186+
// Fire the turn that will overflow. The provider returns 400, so the
187+
// SDK throws. What opencode does next depends on its version:
188+
// - opencode <=1.15: an overflow set `needsCompaction`, which ran
189+
// opencode's compaction flow IN-TURN — producing a second
190+
// transform pass on which our recovery fired same-turn.
191+
// - opencode >=1.16 (commit 7e09660c3, "respect disabled auto
192+
// compaction on overflow"): with `compaction.auto:false` (what
193+
// every Magic Context user sets), opencode now errors the turn
194+
// and goes idle — NO in-turn compaction, no second transform
195+
// pass. Recovery therefore fires on the user's NEXT prompt.
196+
// Either way, DETECTION happens on this turn via the session.error
197+
// event; RECOVERY may be deferred to the next turn. The test asserts
198+
// detection here, then drives a follow-up turn and asserts recovery —
199+
// version-agnostic across both behaviors.
184200
try {
185201
await h.sendPrompt(sessionId, "user turn that will overflow", {
186202
timeoutMs: 30_000,
@@ -189,6 +205,38 @@ describe("context overflow recovery", () => {
189205
// expected — provider returned 400
190206
}
191207

208+
// Detection must persist on the overflow turn itself (the session.error
209+
// handler records the real limit + arms recovery), independent of when
210+
// the recovery historian actually runs.
211+
const afterOverflow = await h.waitFor(
212+
() => {
213+
const s = readState();
214+
if (s.detected_context_limit !== 120000) return false;
215+
return s;
216+
},
217+
{
218+
timeoutMs: 15_000,
219+
intervalMs: 100,
220+
label: "overflow detected (real limit persisted)",
221+
},
222+
);
223+
expect(afterOverflow.detected_context_limit).toBe(120000);
224+
225+
// Drive the recovery turn. On opencode >=1.16 this is the pass that
226+
// bumps to 95% and fires the emergency historian; on <=1.15 recovery
227+
// already completed in-turn and this is just a normal follow-up (the
228+
// waitFor below still passes because the flag is already cleared and
229+
// the historian already ran). The follow-up prompt itself may succeed
230+
// or throw depending on timing — either is fine; we assert on state.
231+
try {
232+
await h.sendPrompt(sessionId, "follow-up turn that drives recovery", {
233+
timeoutMs: 30_000,
234+
});
235+
} catch {
236+
// tolerated — recovery is asserted via persisted state, not the
237+
// prompt's own resolution.
238+
}
239+
192240
// Wait for the recovery cycle to complete. End state evidence:
193241
// - detected_context_limit persisted (proves detection worked)
194242
// - needs_emergency_recovery cleared to 0 (proves historian ran
@@ -210,7 +258,7 @@ describe("context overflow recovery", () => {
210258
return s;
211259
},
212260
{
213-
timeoutMs: 15_000,
261+
timeoutMs: 20_000,
214262
intervalMs: 100,
215263
label: "overflow detected, recovery completed, flag cleared",
216264
},
@@ -234,7 +282,7 @@ describe("context overflow recovery", () => {
234282
// At least one historian call during recovery.
235283
expect(historianCalls).toBeGreaterThan(historianBeforeOverflow);
236284
},
237-
120_000,
285+
180_000,
238286
);
239287

240288
it(

0 commit comments

Comments
 (0)