mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-18 10:52:24 +02:00
fix: whitelist engine-locked at all three gbrain-usable gates (#2456)
#2194 taught the classifier to report a PGLite lock held by a live \`gbrain serve\` as engine-locked instead of broken-config, but none of the three "is gbrain usable?" gates accepted the new status — so the symptom moved from a wrong error to a quieter wrong suppression: gbrain-refresh stripped GBRAIN_CONTEXT_LOAD / GBRAIN_SAVE_RESULTS blocks out of every generated SKILL.md after every upgrade, on the RECOMMENDED /setup-gbrain default (PGLite + local-stdio MCP spawns gbrain serve at session start). engine-locked is the same class as timeout (#1964): the engine is installed and healthy, a legitimate holder has the lock. All three gates now agree: - bin/gstack-gbrain-detect --is-ok exits 0 on engine-locked - bin/gstack-config gbrain-refresh case arm renders instead of suppressing - scripts/gen-skill-docs.ts --respect-detection treats it as detected Test mirrors the existing timeout case in test/gbrain-detection-override.test.ts (engine-locked renders brain blocks; the sibling no-cli case still proves suppression works). Applies the reporter's patch + test from the issue. Fixes #2456 Co-authored-by: Mateus Moraes <mmoraes@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Mateus Moraes
Claude Fable 5
parent
5b65f91a8c
commit
f9f3c9801a
+7
-4
@@ -434,11 +434,14 @@ case "${1:-}" in
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
case "$STATUS" in
|
case "$STATUS" in
|
||||||
ok|timeout|thin-client)
|
ok|timeout|thin-client|engine-locked)
|
||||||
# "timeout" = slow-but-healthy engine (#1964); "thin-client" =
|
# "timeout" = slow-but-healthy engine (#1964); "thin-client" =
|
||||||
# remote-HTTP MCP brain, no local engine by design (#2051) — same
|
# remote-HTTP MCP brain, no local engine by design (#2051);
|
||||||
# treatment as "ok", matching gstack-gbrain-detect --is-ok and
|
# "engine-locked" = same class (#2456): PGLite is single-writer, so a
|
||||||
# gen-skill-docs.
|
# live `gbrain serve` (typically an MCP server) holds the embedded DB.
|
||||||
|
# gbrain is installed and healthy; a transient lock must not strip
|
||||||
|
# brain blocks out of every SKILL.md. All get the same treatment as
|
||||||
|
# "ok", matching gstack-gbrain-detect --is-ok and gen-skill-docs.
|
||||||
echo "Detected gbrain v$VERSION (local-status: $STATUS)."
|
echo "Detected gbrain v$VERSION (local-status: $STATUS)."
|
||||||
# Render brain-aware blocks into an UNTRACKED out-dir (#2569) and
|
# Render brain-aware blocks into an UNTRACKED out-dir (#2569) and
|
||||||
# repoint the installed skills at it — the old in-place render wrote
|
# repoint the installed skills at it — the old in-place render wrote
|
||||||
|
|||||||
@@ -288,17 +288,23 @@ function main(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --is-ok: live engine-status gate. Exits 0 iff gbrain is usable ("ok";
|
// --is-ok: live engine-status gate. Exits 0 iff gbrain is usable ("ok";
|
||||||
// "timeout" — a slow-but-healthy engine, #1964; or "thin-client" — remote-HTTP
|
// "timeout" — a slow-but-healthy engine, #1964; "thin-client" — remote-HTTP
|
||||||
// MCP brain with no local engine by design, #2051 — neither slow nor remote
|
// MCP brain with no local engine by design, #2051; or "engine-locked" —
|
||||||
// must silently suppress brain features), 1 otherwise. Runs detection live
|
// PGLite is single-writer, so a live `gbrain serve` (typically an MCP
|
||||||
// (never reads the possibly-stale gbrain-detection.json), so callers — setup,
|
// server) holds the embedded DB, #2456 — gbrain is installed and healthy in
|
||||||
// bin/dev-setup, and `gstack-config gbrain-refresh` — can decide whether to
|
// all four; none must silently suppress brain features), 1 otherwise. Runs
|
||||||
// render the gbrain :user variant without duplicating the JSON grep.
|
// detection live (never reads the possibly-stale gbrain-detection.json), so
|
||||||
// Prints nothing on stdout.
|
// callers — setup, bin/dev-setup, and `gstack-config gbrain-refresh` — can
|
||||||
|
// decide whether to render the gbrain :user variant without duplicating the
|
||||||
|
// JSON grep. Prints nothing on stdout.
|
||||||
if (process.argv.includes("--is-ok")) {
|
if (process.argv.includes("--is-ok")) {
|
||||||
const noCache = process.env.GSTACK_DETECT_NO_CACHE === "1";
|
const noCache = process.env.GSTACK_DETECT_NO_CACHE === "1";
|
||||||
const status = localEngineStatus({ noCache });
|
const status = localEngineStatus({ noCache });
|
||||||
process.exit(status === "ok" || status === "timeout" || status === "thin-client" ? 0 : 1);
|
process.exit(
|
||||||
|
status === "ok" || status === "timeout" || status === "thin-client" || status === "engine-locked"
|
||||||
|
? 0
|
||||||
|
: 1,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|||||||
@@ -44,14 +44,14 @@ function loadGbrainOverride(): { detected: boolean } {
|
|||||||
try {
|
try {
|
||||||
const json = JSON.parse(fs.readFileSync(detectionPath, 'utf-8')) as { gbrain_local_status?: string };
|
const json = JSON.parse(fs.readFileSync(detectionPath, 'utf-8')) as { gbrain_local_status?: string };
|
||||||
// "timeout" = slow-but-healthy engine (#1964); "thin-client" = remote-HTTP
|
// "timeout" = slow-but-healthy engine (#1964); "thin-client" = remote-HTTP
|
||||||
// MCP brain with no local engine by design (#2051). Both usable — same
|
// MCP brain with no local engine by design (#2051); "engine-locked" = same
|
||||||
// treatment as "ok", matching gstack-gbrain-detect --is-ok.
|
// class (#2456): PGLite is single-writer, so a live `gbrain serve` (e.g.
|
||||||
return {
|
// an MCP server) owns the embedded DB — gbrain is installed and healthy,
|
||||||
detected:
|
// a legitimate holder has the lock, so a transient lock must not silently
|
||||||
json.gbrain_local_status === 'ok' ||
|
// strip brain blocks from every SKILL.md. All usable — same treatment as
|
||||||
json.gbrain_local_status === 'timeout' ||
|
// "ok", matching gstack-gbrain-detect --is-ok.
|
||||||
json.gbrain_local_status === 'thin-client',
|
const USABLE = ['ok', 'timeout', 'thin-client', 'engine-locked'];
|
||||||
};
|
return { detected: USABLE.includes(json.gbrain_local_status ?? '') };
|
||||||
} catch {
|
} catch {
|
||||||
return { detected: false };
|
return { detected: false };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,6 +157,33 @@ describe('gbrain detection override → gen-skill-docs', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('with status "engine-locked" (PGLite single-writer, #2456), brain blocks render like "ok"', () => {
|
||||||
|
const { tmpHome, cleanup } = makeFixture(
|
||||||
|
JSON.stringify({
|
||||||
|
gbrain_local_status: 'engine-locked',
|
||||||
|
gbrain_on_path: true,
|
||||||
|
gbrain_version: 'test-0.42.26',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
const snap = regenAndSnapshot({
|
||||||
|
respectDetection: true,
|
||||||
|
tmpHome,
|
||||||
|
files: PROBE_FILES,
|
||||||
|
});
|
||||||
|
const content = probeUnion(snap);
|
||||||
|
|
||||||
|
// PGLite is single-writer: a live `gbrain serve` (the recommended
|
||||||
|
// /setup-gbrain default spawns one at session start) legitimately owns
|
||||||
|
// the embedded DB. gbrain is installed and healthy — a transient lock
|
||||||
|
// must not silently strip brain blocks (same reasoning as "timeout").
|
||||||
|
expect(content).toContain('## Save Results to Brain');
|
||||||
|
expect(content).toContain('gbrain put "office-hours/');
|
||||||
|
} finally {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('with detected:false (status != "ok"), brain blocks stay suppressed', () => {
|
test('with detected:false (status != "ok"), brain blocks stay suppressed', () => {
|
||||||
const { tmpHome, cleanup } = makeFixture(
|
const { tmpHome, cleanup } = makeFixture(
|
||||||
JSON.stringify({ gbrain_local_status: 'no-cli', gbrain_on_path: false, gbrain_version: null }),
|
JSON.stringify({ gbrain_local_status: 'no-cli', gbrain_on_path: false, gbrain_version: null }),
|
||||||
|
|||||||
Reference in New Issue
Block a user