fix(gsd): surface scoped doctor health warnings
This commit is contained in:
parent
4b671fba0f
commit
07da34dadb
4 changed files with 59 additions and 0 deletions
|
|
@ -13,6 +13,20 @@ export async function checkEngineHealth(
|
|||
issues: DoctorIssue[],
|
||||
fixesApplied: string[],
|
||||
): Promise<void> {
|
||||
const dbPath = join(basePath, ".gsd", "gsd.db");
|
||||
|
||||
if (!isDbAvailable() && existsSync(dbPath)) {
|
||||
issues.push({
|
||||
severity: "warning",
|
||||
code: "db_unavailable",
|
||||
scope: "project",
|
||||
unitId: "project",
|
||||
message: "Database unavailable — using filesystem state derivation (degraded mode). State queries may be slower and less reliable.",
|
||||
file: ".gsd/gsd.db",
|
||||
fixable: false,
|
||||
});
|
||||
}
|
||||
|
||||
// ── DB constraint violation detection (full doctor only, not pre-dispatch per D-10) ──
|
||||
try {
|
||||
if (isDbAvailable()) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import type { DoctorIssue, DoctorIssueCode, DoctorReport, DoctorSummary } from "
|
|||
|
||||
function matchesScope(unitId: string, scope?: string): boolean {
|
||||
if (!scope) return true;
|
||||
if (unitId === "project" || unitId === "environment") return true;
|
||||
return unitId === scope || unitId.startsWith(`${scope}/`) || unitId.startsWith(`${scope}`);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ export type DoctorIssueCode =
|
|||
| "db_orphaned_slice"
|
||||
| "db_done_task_no_summary"
|
||||
| "db_duplicate_id"
|
||||
| "db_unavailable"
|
||||
| "projection_drift";
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
import { afterEach, test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { closeDatabase } from "../gsd-db.ts";
|
||||
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
import { filterDoctorIssues } from "../doctor-format.ts";
|
||||
import { checkEngineHealth } from "../doctor-engine-checks.ts";
|
||||
|
||||
afterEach(() => {
|
||||
closeDatabase();
|
||||
});
|
||||
|
||||
test("filterDoctorIssues keeps project and environment issues in scoped reports", () => {
|
||||
const issues = [
|
||||
{ severity: "error", code: "env_dependencies", scope: "project", unitId: "environment", message: "node_modules missing", fixable: false },
|
||||
{ severity: "warning", code: "db_unavailable", scope: "project", unitId: "project", message: "DB unavailable", fixable: false },
|
||||
{ severity: "warning", code: "state_file_missing", scope: "slice", unitId: "M016/S01", message: "slice warning", fixable: false },
|
||||
] as const;
|
||||
|
||||
const filtered = filterDoctorIssues([...issues], { scope: "M016", includeWarnings: true });
|
||||
assert.deepEqual(
|
||||
filtered.map((issue) => issue.unitId),
|
||||
["environment", "project", "M016/S01"],
|
||||
);
|
||||
});
|
||||
|
||||
test("checkEngineHealth reports db_unavailable when gsd.db exists but the DB is closed", async (t) => {
|
||||
const base = mkdtempSync(join(tmpdir(), "gsd-doctor-db-unavailable-"));
|
||||
t.after(() => rmSync(base, { recursive: true, force: true }));
|
||||
|
||||
const gsdDir = join(base, ".gsd");
|
||||
mkdirSync(gsdDir, { recursive: true });
|
||||
writeFileSync(join(gsdDir, "gsd.db"), "");
|
||||
|
||||
const issues: any[] = [];
|
||||
await checkEngineHealth(base, issues, []);
|
||||
|
||||
const dbIssue = issues.find((issue) => issue.code === "db_unavailable");
|
||||
assert.ok(dbIssue, "doctor should surface degraded DB mode when a DB file exists");
|
||||
assert.equal(dbIssue.unitId, "project");
|
||||
assert.equal(dbIssue.file, ".gsd/gsd.db");
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue