mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-17 02:15:31 +02:00
fix: resolve GBRAIN_HOME with gbrain's parent-dir semantics (#2521)
gstack treated GBRAIN_HOME as the config directory; gbrain's configDir() treats it as the PARENT and always appends `.gbrain` itself (the contract is explicit in gbrain's source: GBRAIN_HOME=/tmp/x → /tmp/x/.gbrain/ config.json). With GBRAIN_HOME set, gstack classified engine status from a file gbrain never reads — the probe's two halves (file checks vs the spawned `gbrain sources list`) looked at DIFFERENT installs, so any resulting status was arbitrary: missing-config/broken-config against healthy installs, or a thin-client marker gstack saw that gbrain itself reported as "No brain configured". New shared resolver `gbrainConfigDir()` in lib/gbrain-exec.ts is the single source of truth. All seven gstack sites route through the contract: - lib/gbrain-local-status.ts gbrainConfigPath (the classifier's file half) - bin/gstack-gbrain-detect GBRAIN_CONFIG + readRemoteMcpUrl - lib/gbrain-exec.ts buildGbrainEnv (the probe's DATABASE_URL seed — fixing only the classifier would have left the split-brain in the spawn half, flagged by the reporter) - lib/gbrain-guards.ts gbrainHome (clones-dir + autopilot-lock paths) - lib/gstack-memory-helpers.ts gbrainConfigPath (engine-tier fallback) - bin/gstack-gbrain-install pre-doctor config check (shell) Unit tests cover GBRAIN_HOME set (config found at $GBRAIN_HOME/.gbrain), the old flat layout explicitly NOT read (both classifier and buildGbrainEnv), and unset (~/.gbrain unchanged). Existing fixtures that encoded the deviant flat layout are updated to gbrain's contract. Root-cause analysis by @d-danielsun in #2521. Deviation from the 3-site plan spec: the same deviant resolution existed in four more sites (buildGbrainEnv, gbrain-guards, memory-helpers, gbrain-install); fixing only three would have left gstack disagreeing with itself as well as with gbrain, so the whole class moved to the shared resolver in one change. Fixes #2521 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
ce4a7bbb7e
commit
5854d122d3
@@ -269,20 +269,46 @@ describe("lib/gbrain-local-status — status classification", () => {
|
||||
expect(localEngineStatus({ noCache: true })).toBe("timeout");
|
||||
});
|
||||
|
||||
it("honors GBRAIN_HOME for config detection (codex D11)", () => {
|
||||
// Config lives ONLY at the alternate GBRAIN_HOME; ~/.gbrain has none.
|
||||
it("honors GBRAIN_HOME for config detection (codex D11) with gbrain's parent-dir semantics (#2521)", () => {
|
||||
// Config lives ONLY under the alternate GBRAIN_HOME; ~/.gbrain has none.
|
||||
// gbrain's configDir() treats GBRAIN_HOME as a PARENT dir and appends
|
||||
// `.gbrain` itself: GBRAIN_HOME=/x → /x/.gbrain/config.json.
|
||||
env = makeEnv({ withGbrain: true, gbrainBehavior: "ok", withConfig: false });
|
||||
restoreEnv = applyEnv(env);
|
||||
const altHome = join(env.tmp, "alt-gbrain");
|
||||
mkdirSync(join(altHome, ".gbrain"), { recursive: true });
|
||||
writeFileSync(
|
||||
join(altHome, ".gbrain", "config.json"),
|
||||
JSON.stringify({ engine: "pglite", database_url: "pglite:///fake" }),
|
||||
);
|
||||
// Without GBRAIN_HOME: misclassified as missing-config.
|
||||
expect(localEngineStatus({ noCache: true })).toBe("missing-config");
|
||||
// With GBRAIN_HOME: the relocated config is found at $GBRAIN_HOME/.gbrain.
|
||||
process.env.GBRAIN_HOME = altHome;
|
||||
expect(localEngineStatus({ noCache: true })).toBe("ok");
|
||||
});
|
||||
|
||||
it("does NOT read $GBRAIN_HOME/config.json directly — gbrain never reads that file (#2521)", () => {
|
||||
// A config placed at gstack's OLD (wrong) resolution must be invisible:
|
||||
// gbrain itself would report "No brain configured" for this layout, so
|
||||
// gstack classifying "ok" from it is the #2521 split-brain.
|
||||
env = makeEnv({ withGbrain: true, gbrainBehavior: "ok", withConfig: false });
|
||||
restoreEnv = applyEnv(env);
|
||||
const altHome = join(env.tmp, "alt-gbrain-flat");
|
||||
mkdirSync(altHome, { recursive: true });
|
||||
writeFileSync(
|
||||
join(altHome, "config.json"),
|
||||
JSON.stringify({ engine: "pglite", database_url: "pglite:///fake" }),
|
||||
);
|
||||
// Without GBRAIN_HOME: misclassified as missing-config.
|
||||
expect(localEngineStatus({ noCache: true })).toBe("missing-config");
|
||||
// With GBRAIN_HOME: the relocated config is found.
|
||||
process.env.GBRAIN_HOME = altHome;
|
||||
expect(localEngineStatus({ noCache: true })).toBe("missing-config");
|
||||
});
|
||||
|
||||
it("with GBRAIN_HOME unset, config resolution stays at ~/.gbrain (#2521 unset half)", () => {
|
||||
env = makeEnv({ withGbrain: true, gbrainBehavior: "ok", withConfig: true });
|
||||
restoreEnv = applyEnv(env);
|
||||
// applyEnv deletes GBRAIN_HOME; config was written at $HOME/.gbrain.
|
||||
expect(process.env.GBRAIN_HOME).toBeUndefined();
|
||||
expect(localEngineStatus({ noCache: true })).toBe("ok");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user