Skip to content

Commit baa7c2d

Browse files
fix(boundary): unfreeze /ctx-recomp from a stale open tool arc too
The trigger-path fix (df5a76a4) staleness-gated open arcs in the normal boundary resolver, but the manual-full-recomp branch still selected the FIRST open arc at/after offset as protectedTailStart. So the same interrupted bash call at the tail head that froze the historian also froze /ctx-recomp (the user's manual escape hatch): protectedTailStart=offset -> zero eligible range -> recomp rebuilds nothing. Apply the same recent-window staleness gate to manual-full-recomp: derive the cutoff from findSuffixStartForTokens(deriveProtectedTailTokenTarget(usage:0).N) and require an open arc to be >= cutoff before it can hold back the recomp. A stale/dead open arc older than the window is ignored; only a genuine in-flight call in the live window is protected. Regression test added. Surfaced by the post-fix oracle re-review (it verified the trigger-path fix correct at both sites but flagged this unchanged path as a must-fix). Co-authored-by: Alfonso [Magic Context] <288211368+alfonso-magic-context@users.noreply.github.com>
1 parent 9d8c57c commit baa7c2d

2 files changed

Lines changed: 61 additions & 1 deletion

File tree

packages/plugin/src/hooks/magic-context/protected-tail-boundary.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,51 @@ describe("protected-tail boundary integration", () => {
347347
}
348348
});
349349

350+
it("manual-full-recomp is not frozen by a stale (dead) open tool arc at offset", () => {
351+
// The same interrupted bash call that froze the trigger path must not
352+
// freeze /ctx-recomp (the user's manual escape hatch): a dead open arc
353+
// older than the recent window is ignored, so recomp gets a full
354+
// eligible range to rebuild.
355+
useBoundaryTempDataHome("protected-tail-recomp-dead-arc-");
356+
const sessionId = "ses-recomp-dead-open-arc";
357+
const messages: Array<{ id: string; role: string; parts: unknown[] }> = [];
358+
messages.push({
359+
id: "m-dead-bash",
360+
role: "assistant",
361+
parts: [
362+
{
363+
type: "tool",
364+
callID: "toolu_dead",
365+
tool: "bash",
366+
state: { status: "running", input: { command: "sleep 999" } },
367+
},
368+
],
369+
});
370+
for (let i = 1; i <= 8; i++) {
371+
messages.push({
372+
id: `m-conv-${i}`,
373+
role: i % 2 === 1 ? "user" : "assistant",
374+
parts: [{ type: "text", text: `conversation turn ${i} `.repeat(800) }],
375+
});
376+
}
377+
const opencodeDb = createBoundaryOpenCodeDb(sessionId, messages);
378+
const db = createContextDb();
379+
try {
380+
const snapshot = resolveOpenCodeProtectedTailBoundary({
381+
db,
382+
sessionId,
383+
mode: "manual-full-recomp",
384+
contextLimit: 64_000,
385+
executeThresholdPercentage: 65,
386+
usageSource: "manual-none",
387+
});
388+
expect(snapshot.eligibleEndOrdinal).toBeGreaterThan(snapshot.offset);
389+
} finally {
390+
closeQuietly(db);
391+
closeQuietly(opencodeDb);
392+
}
393+
});
394+
350395
it("bails out when a boundary snapshot's eligible raw range changes", () => {
351396
useBoundaryTempDataHome("protected-tail-stale-");
352397
const sessionId = "ses-stale-boundary";

packages/plugin/src/hooks/magic-context/protected-tail-boundary.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,23 @@ export function resolveProtectedTailBoundary(
373373

374374
if (ctx.mode === "manual-full-recomp") {
375375
const arcs = buildToolArcs(messages);
376+
// Staleness gate (mirrors the trigger path): only the current in-flight
377+
// call — an open arc within the live recent window — may hold back a full
378+
// recomp. A stale/interrupted open arc (its result will never arrive)
379+
// must NOT block /ctx-recomp; otherwise the same dead invocation that
380+
// froze the historian also freezes the user's manual escape hatch.
381+
const recompTarget = deriveProtectedTailTokenTarget({
382+
contextLimit: ctx.contextLimit,
383+
executeThresholdPercentage: ctx.executeThresholdPercentage,
384+
usagePercentage: 0,
385+
triggerBudget: ctx.triggerBudget,
386+
});
387+
const recentOpenArcCutoff = index.findSuffixStartForTokens(recompTarget.N);
376388
const firstOpenArc = arcs.find(
377-
(arc) => arc.resOrdinal === null && arc.invOrdinal >= offset,
389+
(arc) =>
390+
arc.resOrdinal === null &&
391+
arc.invOrdinal >= offset &&
392+
arc.invOrdinal >= recentOpenArcCutoff,
378393
);
379394
const protectedTailStart = firstOpenArc?.invOrdinal ?? rawMessageCount + 1;
380395
const rawRangeFingerprint = computeRawRangeFingerprint(

0 commit comments

Comments
 (0)