From 289aeda44329a49163757f1cf36182002f31cfab Mon Sep 17 00:00:00 2001 From: garrytan Date: Thu, 29 Oct 2026 16:27:40 +0000 Subject: [PATCH] test: base-red coverage additions (unreproduced head, unresolved head, readPause, wait unconfigured) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- test/base-red.test.ts | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/test/base-red.test.ts b/test/base-red.test.ts index b50ebb066..dc18cf407 100644 --- a/test/base-red.test.ts +++ b/test/base-red.test.ts @@ -184,3 +184,48 @@ describe('policy', () => { expect(codes(POLICY, null)).toEqual(['POLICY_INVALID@base_red']); }); }); + +describe('coverage audit additions', () => { + // Generated by /ship Step 7 coverage audit (PR #3611). + // Value: protects=a failure reproduced at base but not by the restricted run at the PR head stays in-branch, and one unreproduced case keeps the whole verdict in-branch; + // fails_when=the head reproduction or the every-case aggregation is dropped, so a PR that changes behaviour is paused as base-red; why_new=existing tests vary only the base run, with one case; + // seam=none; no_claim=real test runners (shell scripts stand in for the lane's tests) + test('a case the head run does not reproduce, or a case the base output never names, keeps the verdict in-branch', () => { + fixture(); + write('pr-only.txt', 'x\n'); git('add', '-A'); git('commit', '-qm', 'pr: marker'); + const headPasses = classifyBaseRed({ repoRoot: work, base: 'main', head: 'HEAD', evidence: evidence(), policy: { ...POLICY, select: `[ -f pr-only.txt ] && { echo "(pass) totals add up"; exit 0; }; ${SELECT}` } }); + expect([headPasses.code, headPasses.cases[0]!.reason]).toEqual(['IN_BRANCH', 'the restricted command passes at head']); + const ghost = { id: 'ghost case', file: 't/sum.test.sh', signature: 'error: expected 3 got 4' }; + const mixed = classifyBaseRed({ repoRoot: work, base: 'main', head: 'HEAD', evidence: evidence({ total: 2, failures: [evidence().failures[0]!, ghost] }), policy: POLICY }); + expect(mixed.code).toBe('IN_BRANCH'); + expect(mixed.cases.map(c => c.verdict)).toEqual(['BASE_RED', 'IN_BRANCH']); + expect(mixed.cases[1]!.reason).toStartWith('fails without naming this test at base '); + }); + + // Generated by /ship Step 7 coverage audit (PR #3611). + // Value: protects=an unresolvable PR head is BASE_RED_REPRO_ERROR with every case in-branch and nothing run; fails_when=the commit-resolution guard is removed or inverted; + // why_new=no existing test resolves a missing commit; seam=none; no_claim=none beyond protects + test('an unresolvable head is a reproduction error that runs nothing', () => { + fixture(); + const a = counting(); + const r = classifyBaseRed({ repoRoot: work, base: 'main', head: 'no-such-ref', evidence: evidence(), policy: POLICY, runner: a.runner }); + expect([r.code, r.cases.every(c => c.verdict === 'IN_BRANCH'), a.calls]).toEqual(['BASE_RED_REPRO_ERROR', true, []]); + }); + + // Generated by /ship Step 7 coverage audit (PR #3611). + // Value: protects=readPause rejects missing or non-pause files, and wait refuses BASE_RED_UNCONFIGURED once the base no longer declares base_red; + // fails_when=readPause accepts any JSON or wait polls without a usable base policy; why_new=existing tests read only valid pauses and never run the wait CLI; + // seam=none; no_claim=remote fetch over a network (local bare origin) + test('readPause rejects non-pause files and the wait CLI refuses when the base declares no base_red', () => { + fixture({ policy: null }); + const bogus = path.join(root, 'bogus.json'); + fs.writeFileSync(bogus, JSON.stringify({ kind: 'other', schema_version: 1, cases: [] })); + expect(readPause(bogus)).toContain('is not a base-red pause record'); + expect(readPause(path.join(root, 'missing.json'))).toStartWith('cannot read '); + const pauseFile = path.join(root, 'pause.json'); + fs.writeFileSync(pauseFile, JSON.stringify({ schema_version: 1, kind: 'base-red-pause', branch: 'feat', head: git('rev-parse', 'HEAD'), base: 'main', base_sha: git('rev-parse', 'origin/main'), lane: 'tests', cases: evidence().failures, created_at: '2026-10-29T00:00:00Z', expires_at: '2999-01-01T00:00:00Z' })); + const w = spawnSync('bun', [path.join(ROOT, 'bin', 'gstack-base-red'), 'wait', '--pause', pauseFile, '--timeout', '30', '--poll', '5'], { cwd: work, encoding: 'utf8', timeout: 60_000, env: { ...process.env, ...ID, GSTACK_STATE_ROOT: state } }); + expect(w.status).toBe(EXIT.refused); + expect(w.stderr).toContain('BASE_RED_UNCONFIGURED'); + }); +});