mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
fix: doctor's FAIL verdict was zeroed by the owned exit — sweep stragglers + class pin
The merged-state suite caught it: doctor --fast --json reported FAIL but exited 0. Master's v0.42.41.0 brought raw `process.exitCode =` writes (doctor.ts hasFail ternary, extract.ts) that the #2084 verdict-owning exit silently zeroes — getCliExitCode() deliberately never reads ambient process.exitCode (the PGLite-Emscripten pollution defense), so any setter that bypasses setCliExitCode reports success on failure. Swept both sites and added the structural class pin: a test greps src/ for raw `process.exitCode =` outside cli-force-exit.ts, so the next merge that introduces one fails loudly instead of lying about exit codes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
62d54056c0
commit
de4c29d037
@@ -1,5 +1,6 @@
|
||||
import type { BrainEngine } from '../core/engine.ts';
|
||||
import * as db from '../core/db.ts';
|
||||
import { setCliExitCode } from '../core/cli-force-exit.ts';
|
||||
import { LATEST_VERSION, getIdleBlockers } from '../core/migrate.ts';
|
||||
import { checkResolvable } from '../core/check-resolvable.ts';
|
||||
import { autoFixDryViolations, type AutoFixReport, type FixOutcome } from '../core/dry-fix.ts';
|
||||
@@ -7225,10 +7226,12 @@ export async function runDoctor(
|
||||
} catch { /* best-effort */ }
|
||||
}
|
||||
|
||||
// Use process.exitCode instead of process.exit() so cleanup handlers
|
||||
// (e.g. Bun unload events, open database connections) still run before
|
||||
// the process terminates. process.exit() is a hard kill that bypasses them.
|
||||
process.exitCode = hasFail ? 1 : 0;
|
||||
// Use the owned exit verdict instead of process.exit() so cleanup handlers
|
||||
// (e.g. Bun unload events, open database connections) still run before the
|
||||
// process terminates — and so the deliberate flush-exit (#2084) reports
|
||||
// doctor's verdict: a RAW process.exitCode write is silently zeroed by
|
||||
// getCliExitCode() at the entrypoint (the PGLite-pollution defense).
|
||||
setCliExitCode(hasFail ? 1 : 0);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
* pagination). FS-source preserves the original v0.10.1 walker behavior.
|
||||
*/
|
||||
|
||||
import { setCliExitCode } from '../core/cli-force-exit.ts';
|
||||
import { readFileSync, readdirSync, lstatSync, existsSync } from 'fs';
|
||||
import { join, relative, dirname } from 'path';
|
||||
import type { BrainEngine, LinkBatchInput, TimelineBatchInput } from '../core/engine.ts';
|
||||
@@ -864,7 +865,7 @@ Status (v0.42):
|
||||
(r.first_batch_error ? ` (first error: ${r.first_batch_error})` : '') +
|
||||
` — timeline is incomplete.`,
|
||||
);
|
||||
process.exitCode = 1;
|
||||
setCliExitCode(1);
|
||||
}
|
||||
} else if (byMention || ner) {
|
||||
// v0.41.18.0 (T7): combined --by-mention + --ner walk shares one
|
||||
|
||||
@@ -137,3 +137,19 @@ describe('flushStdoutThenExit — deliberate exit after output drains', () => {
|
||||
expect(stream.drainListeners()).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('exit-verdict ownership — no raw process.exitCode assignments (#2084 class pin)', () => {
|
||||
test('every exit-code write in src/ routes through setCliExitCode', async () => {
|
||||
// A RAW `process.exitCode = N` is silently ZEROED by the deliberate
|
||||
// flush-exit: getCliExitCode() reads only gbrain's owned verdict (the
|
||||
// PGLite-Emscripten-pollution defense), so a command that bypasses the
|
||||
// setter reports success on failure. Caught live: doctor's FAIL path
|
||||
// exited 0 after the v0.42.41.0 merge introduced a raw write.
|
||||
const { execSync } = await import('child_process');
|
||||
const hits = execSync(
|
||||
`grep -rn "process.exitCode = " src --include='*.ts' | grep -v "core/cli-force-exit.ts" || true`,
|
||||
{ encoding: 'utf-8', cwd: new URL('..', import.meta.url).pathname },
|
||||
).trim();
|
||||
expect(hits).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user