mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-14 00:49:00 +02:00
fix(review,ship): run the codex diff passes under the timeout wrapper (#1036)
The `_gstack_codex_timeout_wrapper` added in #1056 was wired into codex/SKILL.md but never into the /review and /ship diff passes, which kept running under a bare 5-minute Bash gate. An unwrapped stall returns no exit code and no output, which downstream reads as "Codex reviewed and found nothing" — a truncated pass silently became a clean bill. Measured on codex-cli 0.145.0: a pass was killed at 287s of a 300s budget mid-tool-call, and the same prompt completed in 336s. Both passes in scripts/resolvers/review.ts (adversarial `codex exec` and the structured `codex review --base` pass) now re-source gstack-codex-probe and run under `_gstack_codex_timeout_wrapper 540`, with the Bash tool gate raised to 600000 ms so the wrapper fires FIRST and a stall surfaces as a diagnosable exit 124. The timeout guidance now says a timed-out pass is MISSING COVERAGE, not a clean result, and points at the run's rollout log under ~/.codex/sessions/ for partial output. The stale "timeout doesn't exist on macOS" claim is gone — the wrapper resolves gtimeout, then timeout, then runs unwrapped, so it is safe without coreutils. Static guards in test/codex-hardening.test.ts pin all three sites (resolver, review/SKILL.md, ship/sections/adversarial.md): both calls wrapped, wrapper budget strictly under the Bash gate, and no reappearance of the macOS claim that steered these call sites away from the wrapper in the first place. The Claude-output path guard in test/gen-skill-docs.test.ts now scrubs ~/.codex/sessions/ (a user-facing Codex CLI path, same class as the ~/.codex/logs/ exemption) before banning Codex host paths. Generated files regenerated via gen:skill-docs; factory golden refreshed. Contributed by @aegixx (PR #2379). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
8c5bb4545b
commit
fad28d81ce
@@ -427,3 +427,51 @@ describe('codex SKILL.md.tmpl Step 2A: PROMPT + --base mutual exclusion guard',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Regression guard for #1036. The wrapper added in #1056 was wired into
|
||||
// codex/SKILL.md but not into the /review and /ship diff passes, which kept
|
||||
// running under a bare 5-minute Bash gate. Measured on codex-cli 0.145.0: a
|
||||
// pass was killed at 287s of a 300s budget mid-tool-call, and the same prompt
|
||||
// completed in 336s. An unwrapped stall returns no exit code and no output,
|
||||
// which downstream reads as "Codex reviewed and found nothing".
|
||||
describe('codex timeout wrapper: /review + /ship diff passes', () => {
|
||||
const WRAPPED_SITES = [
|
||||
'scripts/resolvers/review.ts', // generator (source of truth)
|
||||
'review/SKILL.md', // generated
|
||||
'ship/sections/adversarial.md', // ship section source
|
||||
];
|
||||
|
||||
// Outer Bash gate for the wrapped passes. The wrapper must be strictly
|
||||
// shorter so IT fires first and the failure is a diagnosable exit 124.
|
||||
const BASH_GATE_MS = 600000;
|
||||
|
||||
for (const relPath of WRAPPED_SITES) {
|
||||
const read = () => fs.readFileSync(path.join(ROOT, relPath), 'utf8');
|
||||
|
||||
test(`${relPath}: both diff-review Codex calls run under the wrapper`, () => {
|
||||
const wrapped =
|
||||
read().match(/_gstack_codex_timeout_wrapper\s+\d+\s+codex\s+(exec|review)\b/g) ?? [];
|
||||
// Adversarial pass + structured review pass.
|
||||
expect(wrapped.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
test(`${relPath}: does not claim \`timeout\` is unavailable on macOS`, () => {
|
||||
// _gstack_codex_timeout_wrapper resolves gtimeout -> timeout -> unwrapped,
|
||||
// so the coreutils-less case is already handled. The old claim is what
|
||||
// steered these call sites away from the wrapper in the first place.
|
||||
expect(read()).not.toMatch(/doesn't exist on macOS/);
|
||||
});
|
||||
|
||||
test(`${relPath}: wrapper budget stays under the outer Bash gate`, () => {
|
||||
const budgets = [...read().matchAll(/_gstack_codex_timeout_wrapper\s+(\d+)\s+codex\b/g)].map(
|
||||
(m) => Number(m[1]) * 1000,
|
||||
);
|
||||
expect(budgets.length).toBeGreaterThan(0);
|
||||
for (const ms of budgets) {
|
||||
// Inverting this makes the wrapper unreachable: the harness kills the
|
||||
// call first and the exit-124 branch below it becomes dead code.
|
||||
expect(ms).toBeLessThan(BASH_GATE_MS);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user