mirror of
https://github.com/garrytan/gstack.git
synced 2026-06-18 07:40:09 +02:00
fix(sync): preserve staging dir on internal import timeout (#1802 C3)
The import-timeout branch printed 'checkpoint preserved' but the finally then deleted the staging dir: the SIGTERM forwarder's preserve branch only runs when the PARENT is signalled, and an internal runGbrainImport timeout kills just the child and returns normally. So #1611 resume-after-timeout never actually worked. Mirror the forwarder in the timeout branch: set preserveStaging only when gbrain checkpointed against this dir (finally then skips cleanup); otherwise clean up and tell the user it restages instead of falsely promising a resume. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -365,7 +365,9 @@ describe("#1802 D1 — remote-http finally gate (static invariant)", () => {
|
||||
);
|
||||
|
||||
test("finally gates cleanupStagingDir on !remoteHttpMode", () => {
|
||||
expect(ingest).toMatch(/if \(!remoteHttpMode\) cleanupStagingDir\(stagingDir\)/);
|
||||
// Tolerates additional guards (e.g. C3's !preserveStaging) in the same
|
||||
// condition — the load-bearing invariant is that remote-http never deletes.
|
||||
expect(ingest).toMatch(/if \(!remoteHttpMode[^)]*\) cleanupStagingDir\(stagingDir\)/);
|
||||
});
|
||||
|
||||
test("the only finally-scoped cleanup call is the gated one", () => {
|
||||
@@ -377,3 +379,31 @@ describe("#1802 D1 — remote-http finally gate (static invariant)", () => {
|
||||
expect(finallySlice).not.toMatch(/^\s*cleanupStagingDir\(stagingDir\);/m);
|
||||
});
|
||||
});
|
||||
|
||||
// ── #1802 C3: internal import-timeout must preserve a checkpointed staging dir ─
|
||||
// runGbrainImport kills only the child on an internal timeout; the parent
|
||||
// returns normally, so the SIGTERM forwarder's preserve branch never runs. The
|
||||
// timeout branch must mirror it (preserve when checkpointed) and the finally
|
||||
// must honor that — otherwise "checkpoint preserved" is a lie and resume breaks.
|
||||
describe("#1802 C3 — import-timeout preserve (static invariant)", () => {
|
||||
const ingest = fs.readFileSync(
|
||||
path.join(ROOT, "bin", "gstack-memory-ingest.ts"),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
test("timeout branch checks stagingDirIsCheckpointed and sets preserveStaging", () => {
|
||||
const timeoutAt = ingest.indexOf("if (importResult.timedOut)");
|
||||
expect(timeoutAt).toBeGreaterThan(-1);
|
||||
const slice = ingest.slice(timeoutAt, timeoutAt + 1200);
|
||||
expect(slice).toMatch(/stagingDirIsCheckpointed\(stagingDir\)/);
|
||||
expect(slice).toMatch(/preserveStaging = true/);
|
||||
// The not-checkpointed path must say so honestly rather than promising resume.
|
||||
expect(slice).toMatch(/before writing a checkpoint/);
|
||||
});
|
||||
|
||||
test("finally honors preserveStaging", () => {
|
||||
expect(ingest).toMatch(
|
||||
/if \(!remoteHttpMode && !preserveStaging\) cleanupStagingDir\(stagingDir\)/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user