test: review-army + adversarial test hardening

- Tripwire scans execFileSync too (ceiling 8: two more grep-needle string
  exemptions); merge-introduced timeout-less spawnSync in
  question-preference-hook fixed — the tripwire caught a site that landed
  on main AFTER the sweep, on its first day.
- gstack-detach gains TWO watchdog kill regression tests: TERM-immune
  grandchild (the killpg-after-grace escalation) and the leader-dies
  variant (the pgid-at-spawn fix — the case the first test cannot see).
- eval-flake-rank gets its unit suite (final-attempt accounting, artifact
  exclusion, shard recursion, recency bound).
- Groupkill/startup-grace shim markers are per-run unique (pid-suffixed
  sleep durations): sibling Conductor worktrees run free suites with no
  machine lock, and fixed markers let one run pgrep/pkill the other's
  shims — a cross-run flake inside the anti-flake tests.
- flake-ledger test pins the project-scoped local default; stale empty
  section headers in touchfiles-data deleted (they invited entries under
  deliberately retired categories).

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 e4954aaebb
commit 5b04f05ba4
8 changed files with 148 additions and 25 deletions
+11 -7
View File
@@ -36,12 +36,16 @@ describe('session-runner timeout kills the whole process group', () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'groupkill-'));
const shimDir = path.join(dir, 'bin');
fs.mkdirSync(shimDir);
// Unique-ish sleep durations double as pgrep markers: they appear only
// in the shim's children's argv, never in this test process's cmdline.
// Markers are unique PER RUN (fractional seconds carry this process's
// pid): sibling Conductor worktrees run free suites concurrently with no
// machine lock, and fixed markers let one run pgrep/pkill the OTHER
// run's shims (review finding — a cross-run flake inside the anti-flake
// tests). GNU sleep accepts decimals, argv stays greppable.
const mark = (n: number) => `${n}.${process.pid}`;
const shim = [
'#!/bin/bash',
'sleep 6041 &', // the orphan-candidate grandchild
'exec sleep 6042', // the shim itself, wedged forever, no NDJSON
`sleep ${mark(6041)} &`, // the orphan-candidate grandchild
`exec sleep ${mark(6042)}`, // the shim itself, wedged forever, no NDJSON
].join('\n');
fs.writeFileSync(path.join(shimDir, 'claude'), `${shim}\n`, { mode: 0o755 });
@@ -71,13 +75,13 @@ describe('session-runner timeout kills the whole process group', () => {
// The kill is SIGKILL on the GROUP: give the OS a beat to reap, then
// require both the wedged shim and its grandchild gone.
await new Promise((r) => setTimeout(r, 1_000));
expect(aliveWithArg('sleep 6042'), 'the fake claude itself survived the timeout kill').toBe(false);
expect(aliveWithArg('sleep 6041'), 'the grandchild ORPHANED — group kill regressed to a direct-child kill').toBe(false);
expect(aliveWithArg(`sleep ${mark(6042)}`), 'the fake claude itself survived the timeout kill').toBe(false);
expect(aliveWithArg(`sleep ${mark(6041)}`), 'the grandchild ORPHANED — group kill regressed to a direct-child kill').toBe(false);
} finally {
process.env.PATH = realPath;
// Belt and braces: never leak the markers into later tests even on
// assertion failure.
spawnSync('pkill', ['-f', 'sleep 604[12]'], { stdio: 'ignore', timeout: 5_000 });
spawnSync('pkill', ['-f', `sleep 604[12]\\.${process.pid}`], { stdio: 'ignore', timeout: 5_000 });
fs.rmSync(dir, { recursive: true, force: true });
}
}, 60_000);