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
+10 -3
View File
@@ -96,13 +96,19 @@ def child_run(args, log):
proc = subprocess.Popen(
cmd, stdout=f, stderr=subprocess.STDOUT, stdin=subprocess.DEVNULL, start_new_session=True
)
# Capture the PGID AT SPAWN (== proc.pid: start_new_session makes the
# child a session/group leader). Resolving it later via
# os.getpgid(proc.pid) raises ESRCH once the leader exits — a leader
# that died on the SIGTERM while a TERM-immune grandchild survived
# left that grandchild alive forever (codex adversarial finding).
pgid = proc.pid
if args.timeout and args.timeout > 0:
try:
code = proc.wait(timeout=args.timeout)
except subprocess.TimeoutExpired:
log_line(log, f"### gstack-detach WATCHDOG fired after {args.timeout}s — killing ### {_now()}")
try:
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
os.killpg(pgid, signal.SIGTERM)
except Exception:
pass
time.sleep(5)
@@ -110,9 +116,10 @@ def child_run(args, log):
# eval runs spawn claude/codex grandchildren that survive a
# proc.kill() and burn cores + API for hours (the observed
# 15-hour-orphan class). ESRCH here just means the group
# honored the SIGTERM.
# honored the SIGTERM. Uses the SAVED pgid so a dead leader
# cannot orphan its group.
try:
os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
os.killpg(pgid, signal.SIGKILL)
except Exception:
try:
proc.kill()