From ae9afc0b9bdd39ab0605f1037f9bf6eaf2c4fa9f Mon Sep 17 00:00:00 2001 From: Jeremy Date: Thu, 9 Apr 2026 17:32:55 -0500 Subject: [PATCH] fix(gsd): surface warnings when DB or STATE.md init fails ensureDbOpen() returns false on failure instead of throwing, so the try/catch alone was not catching the real failure path. Now check the return value and notify the user with a visible warning when DB or STATE.md generation fails, instead of silently claiming full success. --- src/resources/extensions/gsd/init-wizard.ts | 15 +++++++++--- .../tests/init-bootstrap-completeness.test.ts | 24 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/resources/extensions/gsd/init-wizard.ts b/src/resources/extensions/gsd/init-wizard.ts index 7c26f388d..6d1deb660 100644 --- a/src/resources/extensions/gsd/init-wizard.ts +++ b/src/resources/extensions/gsd/init-wizard.ts @@ -238,11 +238,15 @@ export async function showProjectInit( // Initialize SQLite database so GSD starts in full-capability mode (#3880). // Without this, isDbAvailable() returns false and GSD enters degraded // markdown-only mode until a tool handler happens to call ensureDbOpen(). + let dbReady = false; try { const { ensureDbOpen } = await import("./bootstrap/dynamic-tools.js"); - await ensureDbOpen(basePath); + dbReady = await ensureDbOpen(basePath); } catch { - // Non-fatal — DB creation failure should not block project init + // Swallowed — warning surfaced below + } + if (!dbReady) { + ctx.ui.notify("Warning: database initialization failed — GSD will run in degraded mode until the next /gsd invocation.", "warning"); } // Ensure .gitignore @@ -263,6 +267,7 @@ export async function showProjectInit( // Write initial STATE.md so it exists before the first /gsd invocation. // The explicit /gsd init path (ops.ts) returns without entering showSmartEntry(), // which would otherwise generate STATE.md at guided-flow.ts:1358. + let stateReady = false; try { const { deriveState } = await import("./state.js"); const { buildStateMarkdown } = await import("./doctor.js"); @@ -270,8 +275,12 @@ export async function showProjectInit( const { resolveGsdRootFile } = await import("./paths.js"); const state = await deriveState(basePath); await saveFile(resolveGsdRootFile(basePath, "STATE"), buildStateMarkdown(state)); + stateReady = true; } catch { - // Non-fatal — STATE.md will be regenerated on next /gsd invocation + // Swallowed — warning surfaced below + } + if (!stateReady) { + ctx.ui.notify("Warning: initial STATE.md generation failed — it will be created on the next /gsd invocation.", "warning"); } ctx.ui.notify("GSD initialized. Starting your first milestone...", "info"); diff --git a/src/resources/extensions/gsd/tests/init-bootstrap-completeness.test.ts b/src/resources/extensions/gsd/tests/init-bootstrap-completeness.test.ts index 51c928b1b..bde28376c 100644 --- a/src/resources/extensions/gsd/tests/init-bootstrap-completeness.test.ts +++ b/src/resources/extensions/gsd/tests/init-bootstrap-completeness.test.ts @@ -94,4 +94,28 @@ describe("init-wizard bootstrap completeness (#3880)", () => { "ensureDbOpen must appear before deriveState so DB is ready for state derivation", ); }); + + // ── Failure visibility: user must be warned on partial bootstrap ─────── + + test("ensureDbOpen failure surfaces a warning to the user", () => { + assert.match( + wizardSrc, + /if\s*\(\s*!dbReady\s*\)/, + "init-wizard should check dbReady and warn the user on failure", + ); + // The warning must reference degraded mode so the user knows what happened + assert.match( + wizardSrc, + /degraded mode/, + "DB failure warning should mention degraded mode", + ); + }); + + test("STATE.md failure surfaces a warning to the user", () => { + assert.match( + wizardSrc, + /if\s*\(\s*!stateReady\s*\)/, + "init-wizard should check stateReady and warn the user on failure", + ); + }); });