fix: pre-landing review fixes

The doctor's in-process config read reselected the state root after the
doctor set GSTACK_STATE_ROOT, so --check and --json printed 'selected by
GSTACK_STATE_ROOT' whatever selected the root. cfg now keeps _gstack_sr_var.
Adds the regression test, a CRLF/blank/200-byte launch-probe detail test,
and corrects the clamp comment.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-28 11:51:23 +00:00
1 parent 115355a38b
commit 0e2e112182
3 files changed
+24 -2

No files matched your search

+2 -2
View File
@@ -93,14 +93,14 @@ row() {
sq() { printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\\\\''/g")"; }
# clamp CHARSET MAX — stdin's first line reduced to CHARSET, at most MAX chars.
# Builtins only, bytewise like tr and cut: every caller pipes into it, and on
# Builtins only, bytewise like tr and cut: every caller feeds it stdin, and on
# Windows a head | tr | cut chain costs three process starts (~60 ms).
clamp() { local LC_ALL=C line pat="[^$1]"; IFS= read -r line; line=${line//$pat/}; printf '%s' "${line:0:$2}"; }
# cfg KEY DEFAULT — sets _cfg to KEY as `gstack-config get` reads it, or DEFAULT
# (gstack-config's own default) when unset. In-process through
# gstack-state-root.sh, sourced below: a gstack-config start costs ~200 ms on Windows.
cfg() { gstack_config_select "$1" 2>/dev/null; _cfg="${_gstack_cfg_value:-$2}"; }
cfg() { local sr_var=${_gstack_sr_var-}; gstack_config_select "$1" 2>/dev/null; _gstack_sr_var=$sr_var; _cfg="${_gstack_cfg_value:-$2}"; }
# epoch_of VALUE — epoch seconds for an epoch or an ISO-8601 UTC time; "" otherwise.
epoch_of() {
+14
View File
@@ -507,6 +507,20 @@ describe('gstack-doctor --check', () => {
expect(probeCalls(f)).not.toContain('probe-model');
});
// Value: protects=the --check state-root row names the variable that selected the root, after earlier rows read config;
// fails_when=an in-process config read reselects the root from the doctor's own GSTACK_STATE_ROOT;
// why_new=every other fixture sets GSTACK_STATE_ROOT itself, so a wrong "selected by" still reads GSTACK_STATE_ROOT; seam=none;
// no_claim=CLAUDE_PLUGIN_DATA and default selection (GSTACK_HOME stands in for every selector other than GSTACK_STATE_ROOT)
test('the state-root row names GSTACK_HOME when GSTACK_HOME selected the root, in text and JSON', () => {
const f = makeFixture();
installCodex(f);
const byHome = { GSTACK_STATE_ROOT: '', GSTACK_HOME: f.state };
const r = row(f, [], byHome);
expect(r.rows['state-root'].rest, r.out).toContain('(selected by GSTACK_HOME;');
const json = JSON.parse(doctor(f, ['--json'], byHome).out);
expect(json.rows.find((x: { id: string }) => x.id === 'state-root').detail).toContain('(selected by GSTACK_HOME;');
});
test('--for autoplan: healthy Capy machine with Claude subagents as the outside voice and no Codex CLI passes', () => {
const f = makeFixture();
installCodex(f);
+8
View File
@@ -51,6 +51,14 @@ describe.skipIf(process.platform === 'win32')('gstack-launch-probe.sh classifica
expect(probe(fakeBinary('echo "Unknown argument: --version" >&2; exit 3'))).toEqual({ state: 'broken', detail: 'exit 3: Unknown argument: --version' });
});
// Value: protects=the detail is the first non-blank line with CRs dropped, cut to 200 bytes (Windows CRLF output);
// fails_when=the builtin line picker keeps a CR, returns a blank line or cuts at another length;
// why_new=every other case prints one clean LF line; seam=none; no_claim=real Git Bash output (a sh fake prints the bytes)
test('a broken binary\'s detail is its first non-blank line, CRs dropped, at most 200 bytes', () => {
const long = 'y'.repeat(250);
expect(probe(fakeBinary(`printf '\\r\\n \\n\\t\\r\\n${long}\\r\\nnext\\n'; exit 3`))).toEqual({ state: 'broken', detail: `exit 3: ${'y'.repeat(200)}` });
});
test('an absent binary is missing', () => {
expect(probe(fakeBinary(null)).state).toBe('missing');
});