fix: adversarial-review runtime fixes across the telemetry + kill paths

- session-runner: exit-labeling keys off 'exit', not 'close' — an orphan
  holding the pipes could relabel a REAL exit (auth failure) as
  'timeout_startup' availability noise; the kill path still always
  group-kills and cancels the reader (labeling and unblocking are separate
  concerns). Work phase arms on a flag, not firstResponseMs===0 (a same-ms
  first byte left the startup timer live all run). The CI startup grace is
  now a real FLOOR (Math.max), matching its name and pinning test.
- gstack-detach: pgid captured AT SPAWN (== child pid under
  start_new_session) — resolving it after the grace raised ESRCH once the
  leader died on SIGTERM, orphaning TERM-immune grandchildren forever.
- test-free-shards: ledger entries carry branch + git_sha (rev-parse split:
  '--abbrev-ref HEAD HEAD' printed the branch twice and recorded it as the
  sha); local ledger default is per-PROJECT, not the machine-global tmpdir.
- eval-flake-rank: per-LINE ledger parse (one torn JSONL line vanished the
  whole series), 60-day recency bound (transcript-bearing files are MBs),
  shared isFinalizedEvalResultFile predicate (the artifact-taxonomy rule
  lived in three places); eval-store exports the predicate and finalize
  stops computing flakyRetries twice; paid-shards cleanup uses async rm
  (a SIGKILLed shard's git-workspace teardown blocked every sibling's
  stream classification on the parent event loop).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-31 05:38:26 +00:00
co-authored by Claude Fable 5
parent 5b04f05ba4
commit 513111a166
6 changed files with 116 additions and 21 deletions
+26 -1
View File
@@ -1037,10 +1037,28 @@ export interface FlakeLedgerEntry {
file: string;
/** Shard the original failure surfaced in, when attributable. */
shard?: number;
/** Code-state attribution (review finding): without branch/sha the series
* can't tie an entry to the state that produced it, and the WS16
* promotion evidence needs exactly that. */
branch?: string;
git_sha?: string;
}
export function flakeLedgerPath(env: NodeJS.ProcessEnv = process.env): string {
return env.GSTACK_FLAKE_LEDGER || path.join(os.tmpdir(), 'gstack-flake-ledger.jsonl');
if (env.GSTACK_FLAKE_LEDGER) return env.GSTACK_FLAKE_LEDGER;
// Local default: per-PROJECT, not the machine-global tmpdir — sibling
// Conductor worktrees of DIFFERENT repos must not interleave into one
// series (review finding). CI always sets GSTACK_FLAKE_LEDGER explicitly.
try {
const slug = spawnSync('bash', ['-c', '~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null'], { stdio: 'pipe', timeout: 3000 })
.stdout?.toString().match(/^SLUG=(.+)$/m)?.[1];
if (slug) {
const dir = path.join(os.homedir(), '.gstack', 'projects', slug);
fs.mkdirSync(dir, { recursive: true });
return path.join(dir, 'flake-ledger.jsonl');
}
} catch { /* fall through */ }
return path.join(os.tmpdir(), 'gstack-flake-ledger.jsonl');
}
export function appendFlakeLedger(
@@ -1552,6 +1570,11 @@ async function main(): Promise<number> {
// Durable record (WS1): console lines vanish with the scrollback; the
// ledger makes repeat offenders rankable across runs (eval:flake-rank).
const ts = new Date().toISOString();
// Two separate calls: `rev-parse --abbrev-ref HEAD HEAD` abbreviates
// BOTH revs, printing the branch twice — git_sha recorded the branch
// name (codex adversarial finding).
const ledgerBranch = (spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: ROOT, encoding: 'utf8', timeout: 5000 }).stdout ?? '').trim();
const ledgerSha = (spawnSync('git', ['rev-parse', 'HEAD'], { cwd: ROOT, encoding: 'utf8', timeout: 5000 }).stdout ?? '').trim();
appendFlakeLedger(
flakyFiles.map((file) => ({
ts,
@@ -1559,6 +1582,8 @@ async function main(): Promise<number> {
kind: 'flaky-pass' as const,
file,
shard: outcomes.find((o) => o.failingFiles.includes(file))?.shard,
...(ledgerBranch ? { branch: ledgerBranch } : {}),
...(ledgerSha ? { git_sha: ledgerSha.slice(0, 12) } : {}),
})),
flakeLedgerPath(),
);