test: repair the CI reds the retarget onto main surfaced (test-only)

Seven test files, no product change. The pull_request run at 2d73fadd
failed 5 Linux shards and 4 Windows shards:

- test/ship-frozen-scope-actor.test.ts imported only test code, so the
  test-of-test ratchet refused it; the first case now recomputes the loop
  summary with summarizeReviewLoop/reviewLoopLine from lib/review-scope and
  asserts the exact REVIEW_LOOP line. Its three cases replay the bash
  workflow through bash -c and the shebang bins, so they are POSIX-only.
- test/codex-host.test.ts: the new gate case is Claude-specific (33 -> 34).
- test/paid-retry-supervision.test.ts: the gate census fixture now carries a
  trial record for the one planned behavior-kind gate case, the way
  test/ci-paid-coordination.test.ts already does.
- test/review-fix-range.test.ts asserted the pre-#3487 DIFF_BASE sentence;
  it now asserts the ${RANGE_BASE:-merge-base} clause that carries the same
  contract (every reviewer reads the range from pass 2 on).
- test/gstack-coauthor-trailers.test.ts: the fixture sets its own git
  identity; a CI runner has none to auto-detect ("Committer identity
  unknown").
- test/review-scope-followups.test.ts and test/gstack-ship-receipt-docs.test.ts:
  the gh and old-git stand-ins are sh scripts on a colon-joined PATH, which
  CreateProcess cannot run, so those three cases skip on win32.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-26 21:06:25 +00:00
1 parent 2d73fadd56
commit f9e8f7b1e2
7 files changed
+23 -11

No files matched your search

+2 -2
View File
@@ -128,13 +128,13 @@ describe('per-case host metadata', () => {
for (const id of Object.keys(E2E_HOSTS)) expect(Object.hasOwn(E2E_TOUCHFILES, id), id).toBe(true);
});
test('classifies 52 adapter-only, 33 Claude-specific, 26 rework and 1 host-neutral case', () => {
test('classifies 52 adapter-only, 34 Claude-specific, 26 rework and 1 host-neutral case', () => {
const counts: Record<string, number> = {};
for (const support of Object.values(E2E_HOSTS)) counts[support] = (counts[support] ?? 0) + 1;
expect(counts.both).toBe(52);
expect(counts.rework).toBe(26);
expect(counts['host-neutral']).toBe(1);
expect(['pty', 'sdk', 'subagents', 'skill-tool', 'hermetic', 'self-host'].reduce((sum, reason) => sum + (counts[reason] ?? 0), 0)).toBe(33);
expect(['pty', 'sdk', 'subagents', 'skill-tool', 'hermetic', 'self-host'].reduce((sum, reason) => sum + (counts[reason] ?? 0), 0)).toBe(34);
});
});
+4 -1
View File
@@ -15,7 +15,10 @@ import { EXIT } from '../lib/headless-artifacts';
const BIN = path.resolve(import.meta.dir, '../bin/gstack-coauthor-trailers');
const temps: string[] = [];
afterAll(() => { for (const dir of temps) fs.rmSync(dir, { recursive: true, force: true }); });
const ENV = { ...process.env, GIT_CONFIG_GLOBAL: '/dev/null', GIT_CONFIG_SYSTEM: '/dev/null', GIT_CONFIG_NOSYSTEM: '1' };
const ENV = {
...process.env, GIT_CONFIG_GLOBAL: '/dev/null', GIT_CONFIG_SYSTEM: '/dev/null', GIT_CONFIG_NOSYSTEM: '1',
GIT_COMMITTER_NAME: 'Porter', GIT_COMMITTER_EMAIL: 'porter@example.invalid', GIT_AUTHOR_NAME: 'Porter', GIT_AUTHOR_EMAIL: 'porter@example.invalid',
};
function git(cwd: string, args: string[], input?: string) {
const r = spawnSync('git', args, { cwd, env: ENV, encoding: 'utf8', timeout: 30_000, input });
+2 -1
View File
@@ -170,7 +170,8 @@ describe('carry follow-ups: git floor, named refusal, branch-touched walk, digit
expect((plan as any).message.split(', ').length).toBe(CARRY_NAMED_PATHS);
});
test('carry refuses git below 2.39 by name (RECEIPT_GIT_TOO_OLD) and names a product path the branch touched', () => {
// The old-git stand-in is a sh script on a colon-joined PATH, which CreateProcess cannot run on Windows.
test.skipIf(process.platform === 'win32')('carry refuses git below 2.39 by name (RECEIPT_GIT_TOO_OLD) and names a product path the branch touched', () => {
const repo = fixture();
makePr(repo, 'pr-carry', { expects: '1.2.4.0' });
const body = path.join(repo.root, 'body.md');
+2 -1
View File
@@ -4,7 +4,7 @@ import { join } from 'node:path';
import {
buildPaidShardArgs, buildRunManifest, parseRunManifest, planPaidShards,
DEFAULT_JOBS, parseCliOptions, paidShardWallUpperBoundMs, resolvePaidShardBudget, retriesForFiles, verifySliceResults, collectPaidTestFiles, selectPaidTestFiles,
shardFile, sliceExecutionOrder, sliceSupervisedWallMs, CASE_SHARDED_FILES, sliceCiTimeoutMinutes, resolvePaidShardTimeoutMs,
shardFile, shardCaseId, shardTrial, sliceExecutionOrder, sliceSupervisedWallMs, CASE_SHARDED_FILES, sliceCiTimeoutMinutes, resolvePaidShardTimeoutMs,
} from '../scripts/test-paid-shards';
import {
ALL_TIERS, AUQ_CONSISTENCY_RETRY_BUDGET, FILE_RETRY_BUDGETS,
@@ -331,6 +331,7 @@ test('gate census requires all seven distinct slice results and its own reconcil
files: [row.file], status: 'passed' as const, exitCode: 0, elapsedMs: 1, skippedTests: 0,
executedTests: STRICT_RETRY_CASE_BUDGETS.find(budget => budget.file === row.file)?.cases ?? 1,
...(row.budget ? { budget: row.budget } : {}),
...(row.trial ? { trial: { case: shardCaseId(row.file)!, trial: shardTrial(row.file)!, ...row.trial, outcome: 'passed' as const, cost_usd: 0, duration_ms: 1 } } : {}),
})),
}));
expect(verifySliceResults(manifest, results)).toEqual({ ok: true, problems: [] });
+1 -1
View File
@@ -211,7 +211,7 @@ describe('ship Step 9 instructions', () => {
const army = fs.readFileSync(path.join(ROOT, 'ship/sections/review-army.md'), 'utf8').replace(/\s+/g, ' ');
test('pass 2+ reads the range since the previous pass under a full token; the fix-range token is /review\'s alone', () => {
expect(army).toContain('Every entry saves `PASS_HEAD=$(git rev-parse HEAD)`; from pass 2 on, `RANGE_BASE` is the previous pass\'s PASS_HEAD.');
expect(army).toContain('use `DIFF_BASE=$RANGE_BASE` instead, so every reviewer reads what changed since the previous pass.');
expect(army).toContain('`DIFF_BASE=${RANGE_BASE:-$(git merge-base origin/<base> HEAD)}`, so with `RANGE_BASE` exported from pass 2 on every reviewer reads what changed since the previous pass');
expect(army).toContain('Every pass captures a full token (no `--fix-range`), so the record binds the whole tree even when reviewers read only the range.');
expect(army).not.toContain('--start review --fix-range');
expect(army).toContain('gstack-review-scope classify --base <base> --pass $PASS --range-base $RANGE_BASE');
+3 -2
View File
@@ -54,7 +54,8 @@ describe('deferred-issue search page and the repository argument gh accepts', ()
return { dir, log };
};
test('an exactly-full search page is reported truncated and recorded on the issue it files; a short page is not', () => {
// The gh stand-in is a sh script on a colon-joined PATH, which CreateProcess cannot run on Windows.
test.skipIf(process.platform === 'win32')('an exactly-full search page is reported truncated and recorded on the issue it files; a short page is not', () => {
const repo = fixture();
const classified = path.join(repo.root, 'classified.json');
fs.writeFileSync(classified, JSON.stringify([finding('lib/legacy.ts:7:data-loss', 'Unbounded delete')]));
@@ -75,7 +76,7 @@ describe('deferred-issue search page and the repository argument gh accepts', ()
expect(JSON.parse(r2.out)[0]).toEqual({ fingerprint: 'lib/legacy.ts:7:data-loss', path: 'lib/legacy.ts:7', severity: 'CRITICAL', summary: 'Unbounded delete', issue: 900, url: 'https://example.test/acme/app/issues/900' });
});
test('with --repo the visibility read passes the repository positionally, so a MEDIUM finding on a public repository waits for a human and stays unfiled', () => {
test.skipIf(process.platform === 'win32')('with --repo the visibility read passes the repository positionally, so a MEDIUM finding on a public repository waits for a human and stays unfiled', () => {
const repo = fixture();
const classified = path.join(repo.root, 'classified.json');
fs.writeFileSync(classified, JSON.stringify([
+9 -3
View File
@@ -11,6 +11,7 @@ import { spawnSync } from 'node:child_process';
import {
createShipFrozenScopeFixture, FROZEN_SCOPE_DEFER_IDENTITY, FROZEN_SCOPE_FIX_IDENTITY, shipFrozenScopeFailures, shipFrozenScopeWorkflow,
} from './helpers/ship-frozen-scope-actor';
import { reviewLoopLine, summarizeReviewLoop } from '../lib/review-scope';
type Fixture = ReturnType<typeof createShipFrozenScopeFixture>;
let workflow = '';
@@ -78,7 +79,9 @@ async function act(f: Fixture, options: { fix?: boolean; passes?: 1 | 2 } = {})
sh(f, f.commands.continue!);
}
test('a scripted actor that fixes the diff, defers the pre-existing defect and converges on pass 2 passes the verdict', async () => {
// The actor replays the bash workflow through bash -c and the shebang bins, so it is POSIX-only like the paid case it mirrors.
const posixTest = test.skipIf(process.platform === 'win32');
posixTest('a scripted actor that fixes the diff, defers the pre-existing defect and converges on pass 2 passes the verdict', async () => {
const f = fixture();
await act(f);
const verdict = await shipFrozenScopeFailures(f, { exitReason: 'success' });
@@ -89,9 +92,12 @@ test('a scripted actor that fixes the diff, defers the pre-existing defect and c
expect(rows[0]!.findings.map((x: any) => [x.fingerprint, x.action])).toEqual([[FROZEN_SCOPE_FIX_IDENTITY, 'auto-fixed'], [FROZEN_SCOPE_DEFER_IDENTITY, 'deferred']]);
expect(rows[1]!.range_base).toBe(verdict.evidence.head);
expect(verdict.evidence.payments).toBe(verdict.evidence.originalPayments);
const summary = summarizeReviewLoop(rows, verdict.evidence.start.started_at);
expect(summary).toEqual(verdict.evidence.loop);
expect(reviewLoopLine(summary)).toBe('REVIEW_LOOP: passes=2 blocking_found=2 deferred=1 noted=0 fixed=1 scope=frozen');
}, 120_000);
test('the fixture interface refuses the undeclared interactions before any decision', async () => {
posixTest('the fixture interface refuses the undeclared interactions before any decision', async () => {
const f = fixture();
expect(await hook(f, 'Edit', { file_path: f.payments, old_string: 'card', new_string: '?' })).toBe('Edit outside invoice.ts');
expect(await hook(f, 'Write', { file_path: f.payments, content: '' })).toBe('Write outside invoice.ts and the review record');
@@ -104,7 +110,7 @@ test('the fixture interface refuses the undeclared interactions before any decis
expect(f.snapshot().executions.filter(e => !e.allowed)).toHaveLength(6);
}, 120_000);
test('leaving the diff defect in place or exiting after one pass are named failures', async () => {
posixTest('leaving the diff defect in place or exiting after one pass are named failures', async () => {
const f = fixture();
await act(f, { fix: false, passes: 1 });
const verdict = await shipFrozenScopeFailures(f, { exitReason: 'success' });