From 8299c7ac2bf3c7138acb2cc1bf86712fd51f0464 Mon Sep 17 00:00:00 2001 From: Mikael Hugo Date: Sat, 2 May 2026 22:51:42 +0200 Subject: [PATCH] fix(sf): clear last 2 stale failures from gsd-2 compat sweep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit auto-session-encapsulation invariant: the parallel session refactored auto.ts to use the getAutoSession() factory; the test still expected `new AutoSession()` literally. Updated the regex + the allowedPatterns list to accept both shapes — the invariant is "exactly one module-level binding for the AutoSession instance", not which constructor expression yields it. silent-catch-diagnostics #3348: auto-supervisor.ts:53 swallowed signal- handler exceptions silently. Added logWarning("session", ...) — the intent stays the same (signal handler must not throw), but cleanup-path errors are now visible in the journal. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/resources/extensions/sf/auto-supervisor.ts | 10 ++++++++-- .../sf/tests/auto-session-encapsulation.test.ts | 12 +++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/resources/extensions/sf/auto-supervisor.ts b/src/resources/extensions/sf/auto-supervisor.ts index 1880285d3..e393c15ed 100644 --- a/src/resources/extensions/sf/auto-supervisor.ts +++ b/src/resources/extensions/sf/auto-supervisor.ts @@ -7,6 +7,7 @@ import { clearLock } from "./crash-recovery.js"; import { nativeHasChanges } from "./native-git-bridge.js"; import { releaseSessionLock } from "./session-lock.js"; +import { logWarning } from "./workflow-logger.js"; // ─── Signal Handling ───────────────────────────────────────────────────────── @@ -50,8 +51,13 @@ export function registerSigtermHandler( const handler = () => { try { onSignal?.(); - } catch { - // Best-effort: signal handler must not throw. + } catch (err) { + // Best-effort: signal handler must not throw — log and continue + // to lock cleanup so the user can still exit cleanly. + logWarning( + "session", + `auto-supervisor signal handler threw: ${(err as Error).message}`, + ); } clearLock(currentBasePath); releaseSessionLock(currentBasePath); diff --git a/src/resources/extensions/sf/tests/auto-session-encapsulation.test.ts b/src/resources/extensions/sf/tests/auto-session-encapsulation.test.ts index 510c5b41f..b69ee91b7 100644 --- a/src/resources/extensions/sf/tests/auto-session-encapsulation.test.ts +++ b/src/resources/extensions/sf/tests/auto-session-encapsulation.test.ts @@ -79,14 +79,19 @@ test("auto.ts has exactly one module-level const for AutoSession", () => { const source = getAutoTsSource(); const lines = source.split("\n"); + // Accept either historical shape: a direct `new AutoSession()` instantiation + // OR the current factory pattern `getAutoSession()` (auto/session.ts owns + // the singleton). The invariant is "exactly one module-level binding for + // the AutoSession instance" — not which constructor expression yielded it. const sessionConsts = lines.filter((line) => - /^const\s+\w+\s*=\s*new\s+AutoSession/.test(line), + /^const\s+\w+\s*=\s*(new\s+AutoSession|getAutoSession\s*\()/.test(line), ); assert.equal( sessionConsts.length, 1, - `auto.ts should have exactly one \`const s = new AutoSession()\`. ` + + `auto.ts should have exactly one module-level AutoSession binding ` + + `(\`const s = new AutoSession()\` or \`const s = getAutoSession()\`). ` + `Found ${sessionConsts.length}: ${sessionConsts.join(", ")}`, ); }); @@ -212,7 +217,8 @@ test("auto.ts module-level consts are only AutoSession instance, true constants, // Patterns that are acceptable at module level const allowedPatterns = [ - /^const s = new AutoSession/, // The session singleton + /^const s = new AutoSession/, // The session singleton (legacy shape) + /^const s = getAutoSession\s*\(/, // The session singleton (factory shape) /^const [A-Z_]+\s*=/, // UPPER_CASE constants /^const \w+StateAccessors/, // Static accessor objects /^const \w+:\s*\w+\s*=/, // Typed constants