From 77b47c05bd2c141692ada734c8c709bc1f81f6b8 Mon Sep 17 00:00:00 2001 From: garrytan Date: Tue, 3 Nov 2026 15:04:37 +0000 Subject: [PATCH] fix: pre-landing review fixes Assert the killed child's signal-and-elapsed log line; pin hookChildBudgetMs to literal values and stop exporting HOOK_EXIT_RESERVE_MS. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- hosts/claude/hooks/spawn-bin.ts | 2 +- test/question-log-hook.test.ts | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/hosts/claude/hooks/spawn-bin.ts b/hosts/claude/hooks/spawn-bin.ts index 95c26bbd4..5a000c9fc 100644 --- a/hosts/claude/hooks/spawn-bin.ts +++ b/hosts/claude/hooks/spawn-bin.ts @@ -44,7 +44,7 @@ export function runBin(name: string, args: string[], opts: SpawnSyncOptions) { /** Claude Code's timeout for a gstack hook, as setup registers it (`--timeout 5`). */ export const HOOK_TIMEOUT_MS = 5000; /** Kept back from HOOK_TIMEOUT_MS so a hook logs and exits before Claude Code kills it. */ -export const HOOK_EXIT_RESERVE_MS = 500; +const HOOK_EXIT_RESERVE_MS = 500; /** * What is left of a hook's registered budget for its next child. Every child diff --git a/test/question-log-hook.test.ts b/test/question-log-hook.test.ts index 3952f5d3b..60f8b1896 100644 --- a/test/question-log-hook.test.ts +++ b/test/question-log-hook.test.ts @@ -19,7 +19,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; import { spawnSync } from 'child_process'; -import { HOOK_EXIT_RESERVE_MS, HOOK_TIMEOUT_MS, hookChildBudgetMs } from '../hosts/claude/hooks/spawn-bin'; +import { hookChildBudgetMs } from '../hosts/claude/hooks/spawn-bin'; const ROOT = path.resolve(import.meta.dir, '..'); const HOOK = path.join(ROOT, 'hosts', 'claude', 'hooks', 'question-log-hook'); @@ -402,9 +402,9 @@ describe('PostToolUse hook (crash safety)', () => { describe('PostToolUse hook (budget)', () => { test('every child shares the registered 5 s budget, less the exit reserve', () => { - expect(hookChildBudgetMs(1_000, 1_000)).toBe(HOOK_TIMEOUT_MS - HOOK_EXIT_RESERVE_MS); - expect(hookChildBudgetMs(1_000, 3_000)).toBe(HOOK_TIMEOUT_MS - HOOK_EXIT_RESERVE_MS - 2_000); - expect(hookChildBudgetMs(1_000, 1_000 + HOOK_TIMEOUT_MS)).toBeLessThan(0); + expect(hookChildBudgetMs(1_000, 1_000)).toBe(4_500); + expect(hookChildBudgetMs(1_000, 3_000)).toBe(2_500); + expect(hookChildBudgetMs(1_000, 6_000)).toBeLessThan(0); }); test('slow children stop at the hook budget and the skipped questions are logged', () => { @@ -436,7 +436,9 @@ describe('PostToolUse hook (budget)', () => { }); expect(res.status).toBe(0); expect(readLog().length).toBeLessThan(questions.length); - expect(fs.readFileSync(path.join(stateRoot, 'hook-errors.log'), 'utf-8')).toContain('budget is spent'); + const errors = fs.readFileSync(path.join(stateRoot, 'hook-errors.log'), 'utf-8'); + expect(errors).toMatch(/exited null \(SIG\w+ after \d+ of \d+ ms\)/); + expect(errors).toContain('budget is spent'); } finally { fs.rmSync(fakeBin, { recursive: true, force: true }); }