mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-05 08:23:59 +01:00
feat(exercised-map): union-only refresh with a fail-closed contract, census refresh, MAP_GAP and the replay receipt (A2-1, A2-4)
bun run test:exercised-map refreshes from a census run or local artifacts and writes nothing on unavailable (exit 3) or partial (exit 4) input. The paid report prints non-blocking MAP_GAP lines; --replay pins 0 misses over the 47 recorded gate reds. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
ba4c5aea00
commit
05f27c8de9
6 files changed
+842
No files matched your search
@@ -723,6 +723,34 @@ jobs:
|
||||
if-no-files-found: ignore
|
||||
retention-days: 90
|
||||
|
||||
# Exercised-path map (shadow, non-blocking; docs/TESTING_INTERNALS.md#exercised-path-map):
|
||||
# union this census's own recorded commands into the map, report MAP_GAP lines and
|
||||
# cases that recorded no commands, and print the refresh command. Never fails the run.
|
||||
- name: Refresh the exercised-path map from this census
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
run: |
|
||||
mkdir -p /tmp/exercised-map
|
||||
dirs=()
|
||||
for dir in /tmp/gate-census-report /tmp/paid-report; do [ -d "$dir" ] && dirs+=(--from-dir "$dir"); done
|
||||
status=0
|
||||
bun --no-install run scripts/exercised-map.ts "${dirs[@]}" \
|
||||
--run-id "$GITHUB_RUN_ID" --out /tmp/exercised-map/exercised-commands.json --report /tmp/exercised-map/report.md || status=$?
|
||||
if [ "$status" -ne 0 ]; then
|
||||
echo "exercised-path map refresh failed with exit $status (non-blocking; no map uploaded)" | tee -a "$GITHUB_STEP_SUMMARY"
|
||||
fi
|
||||
if [ -f /tmp/exercised-map/report.md ]; then cat /tmp/exercised-map/report.md >> "$GITHUB_STEP_SUMMARY"; fi
|
||||
|
||||
- name: Upload the refreshed exercised-path map
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: exercised-map-a${{ github.run_attempt }}
|
||||
path: /tmp/exercised-map
|
||||
if-no-files-found: ignore
|
||||
retention-days: 90
|
||||
|
||||
# Weekly pass-rate gate over the last 10 weekly runs (drift, rule cases
|
||||
# behaving like behavior, quarantine exit/expiry/cap). Fails closed when
|
||||
# history cannot be fetched.
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
"eval:bg:gate": "bun run scripts/eval-bg.ts gate",
|
||||
"eval:bg:periodic": "bun run scripts/eval-bg.ts periodic",
|
||||
"test:health": "bun run scripts/test-health-report.ts",
|
||||
"test:exercised-map": "bun run scripts/exercised-map.ts",
|
||||
"eval:list": "bun run scripts/eval-list.ts",
|
||||
"eval:compare": "bun run scripts/eval-compare.ts",
|
||||
"eval:summary": "bun run scripts/eval-summary.ts",
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
#!/usr/bin/env bun
|
||||
/**
|
||||
* test:exercised-map — maintain test/helpers/exercised-commands.json, the
|
||||
* observed half of the exercised-path consumer map (scripts/pr-dependencies.ts
|
||||
* exercisedConsumers; shadow mode, docs/TESTING_INTERNALS.md#exercised-path-map).
|
||||
*
|
||||
* Refreshes are union-only: an observation adds commands, never removes one.
|
||||
* A refresh whose input is unavailable or partial writes nothing, keeps the
|
||||
* committed union and exits non-zero with a stable code naming what was
|
||||
* missing: 2 usage, 3 input unavailable (missing directory, failed or HTTP 403
|
||||
* download), 4 input incomplete (no shards, no trial outcomes, an executed case
|
||||
* without a shard artifact, a missing or malformed exercised-commands.json).
|
||||
* Removing a command is a reviewed edit of the JSON file.
|
||||
*
|
||||
* Usage:
|
||||
* bun run test:exercised-map --from-run <id> [--out <file>]
|
||||
* download that census run's exercised-map artifact and union it into the committed map
|
||||
* bun run test:exercised-map --from-dir <downloaded exercised-map artifact dir> [--out <file>]
|
||||
* the same from a locally downloaded artifact (the fallback when the download hits HTTP 403)
|
||||
* bun run test:exercised-map --from-dir <dir> [--from-dir <dir>...] --run-id <id> [--out <file>] [--report <file>]
|
||||
* read paid-slice / gate-census report directories (shards/<shard>/...: transcripts, junit.xml,
|
||||
* PTY terminal.visible.log, trial-outcomes.jsonl) and union their commands into the map
|
||||
* bun run test:exercised-map --check
|
||||
* validate the committed map
|
||||
* bun run test:exercised-map --replay [<fixture>]
|
||||
* replay recorded red PR runs (default test/fixtures/exercised-map-replay.json) through
|
||||
* today's selector and its shadow; a MISS is a failed gate case the shadow would not run
|
||||
*/
|
||||
import * as fs from 'node:fs';
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import {
|
||||
checkoutExercisedConsumers, EXERCISED_MAP_PATH, parseExercisedMap, type ExercisedCase, type ExercisedConsumers, type ExercisedMap,
|
||||
} from './pr-dependencies';
|
||||
import { caseOwnerFile, EXERCISED_MAP_ANCHOR, PR_FULL_GATE_FILES, PR_PROFILE_MAPS } from './test-pr-profile';
|
||||
import { CASE_TEST_NAMES } from './lib/paid-cases';
|
||||
import { computePaidCaseSelection } from './test-paid-shards';
|
||||
|
||||
const ROOT = path.resolve(import.meta.dir, '..');
|
||||
export const EXERCISED_MAP_ARTIFACT = 'exercised-map';
|
||||
|
||||
/** Commands one shard directory recorded: per Bun test name, and shard-level (no test name). */
|
||||
export interface ShardCommands { shard: string; executed: string[]; perTest: Record<string, string[]>; shardLevel: string[] }
|
||||
|
||||
function walk(dir: string): string[] {
|
||||
return fs.readdirSync(dir, { withFileTypes: true }).flatMap(entry => entry.isDirectory() ? walk(path.join(dir, entry.name)) : [path.join(dir, entry.name)]);
|
||||
}
|
||||
|
||||
function toolCommands(node: unknown, out: string[]): void {
|
||||
if (Array.isArray(node)) { for (const item of node) toolCommands(item, out); return; }
|
||||
if (!node || typeof node !== 'object') return;
|
||||
const record = node as Record<string, any>;
|
||||
if (record.type === 'tool_use' && typeof record.input?.command === 'string') out.push(record.input.command);
|
||||
for (const value of Object.values(record)) if (value && typeof value === 'object') toolCommands(value, out);
|
||||
}
|
||||
|
||||
/** Every `shards/<shard>/` directory under `dir`, with the Bash commands its transcripts, JSONL logs and PTY screens recorded. */
|
||||
export function readShardCommands(dir: string): ShardCommands[] {
|
||||
if (!fs.existsSync(dir)) return [];
|
||||
const shardDirs = walk(dir).map(file => path.relative(dir, file).split(path.sep)).flatMap(parts => {
|
||||
const at = parts.lastIndexOf('shards');
|
||||
return at >= 0 && parts.length > at + 2 ? [path.join(dir, ...parts.slice(0, at + 2))] : [];
|
||||
});
|
||||
return [...new Set(shardDirs)].sort().map(shardDir => {
|
||||
const record: ShardCommands = { shard: path.basename(shardDir), executed: [], perTest: {}, shardLevel: [] };
|
||||
for (const file of walk(shardDir)) {
|
||||
const base = path.basename(file);
|
||||
try {
|
||||
if (base === 'junit.xml') {
|
||||
for (const match of fs.readFileSync(file, 'utf8').matchAll(/<testcase\b([^>]*?)(\/>|>([\s\S]*?)<\/testcase>)/g)) {
|
||||
const name = /\bname="([^"]*)"/.exec(match[1]!)?.[1];
|
||||
if (name && !/<skipped/.test(match[3] ?? '')) record.executed.push(name.replace(/"/g, '"').replace(/&/g, '&'));
|
||||
}
|
||||
} else if (base.endsWith('.json')) {
|
||||
const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
|
||||
if (Array.isArray(parsed?.tests) && parsed.tests.some((test: any) => test?.transcript)) {
|
||||
for (const test of parsed.tests) { const out: string[] = []; toolCommands(test.transcript ?? [], out); if (out.length) (record.perTest[test.name] ??= []).push(...out); }
|
||||
} else toolCommands(parsed, record.shardLevel);
|
||||
} else if (base.endsWith('.jsonl')) {
|
||||
for (const line of fs.readFileSync(file, 'utf8').split('\n')) if (line.includes('tool_use')) { try { toolCommands(JSON.parse(line), record.shardLevel); } catch { /* partial line */ } }
|
||||
} else if (base === 'terminal.visible.log') {
|
||||
for (const match of fs.readFileSync(file, 'utf8').matchAll(/Bash\(([^\r\n]{0,400})/g)) record.shardLevel.push(`PTY:${match[1]}`);
|
||||
}
|
||||
} catch { /* unreadable evidence file: its commands are simply not observed */ }
|
||||
}
|
||||
record.shardLevel = [...new Set(record.shardLevel)];
|
||||
for (const name of Object.keys(record.perTest)) record.perTest[name] = [...new Set(record.perTest[name])];
|
||||
return record;
|
||||
});
|
||||
}
|
||||
|
||||
const testNameCase = (name: string, ids: string[]): string | null =>
|
||||
ids.includes(name) ? name : Object.keys(CASE_TEST_NAMES).find(id => CASE_TEST_NAMES[id] === name && ids.includes(id)) ?? ids.find(id => name.includes(id)) ?? null;
|
||||
|
||||
/**
|
||||
* Raw commands per case. A case shard (`<stem>--<id>`) is that case; a file
|
||||
* shard's per-test commands go to the case its test name names, and its
|
||||
* file-level commands to every case of the file that ran (by JUnit name, else
|
||||
* all of them): conservative over-attribution, as in the measured prototype.
|
||||
*/
|
||||
export function attributeCommands(shards: ShardCommands[], maps = PR_PROFILE_MAPS): Map<string, string[]> {
|
||||
const ids = Object.keys(maps.e2eTouchfiles);
|
||||
const byFile = new Map<string, string[]>();
|
||||
for (const id of ids) { const owner = caseOwnerFile(id, maps); if (owner) byFile.set(owner, [...byFile.get(owner) ?? [], id]); }
|
||||
const out = new Map<string, string[]>();
|
||||
const add = (id: string, commands: string[]) => out.set(id, [...out.get(id) ?? [], ...commands]);
|
||||
for (const shard of shards) {
|
||||
const [stem, caseKey] = shard.shard.split('--');
|
||||
const caseId = caseKey?.replace(/\.t\d+$/, '');
|
||||
const owned = byFile.get(`test/${stem}.test.ts`) ?? [];
|
||||
const ran = owned.filter(id => shard.executed.some(name => testNameCase(name, [id]) === id));
|
||||
const targets = caseId && ids.includes(caseId) ? [caseId] : ran.length ? ran : owned;
|
||||
for (const id of targets) add(id, shard.shardLevel);
|
||||
for (const [name, commands] of Object.entries(shard.perTest)) {
|
||||
const id = testNameCase(name, targets) ?? testNameCase(name, ids);
|
||||
for (const target of id ? [id] : targets) add(target, commands);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Known trial cost per case summed over the trial-outcomes.jsonl files under `dir` (executed trials only). */
|
||||
export function readCaseCosts(dir: string): Map<string, number> {
|
||||
const out = new Map<string, number>();
|
||||
if (!fs.existsSync(dir)) return out;
|
||||
for (const file of walk(dir).filter(file => path.basename(file) === 'trial-outcomes.jsonl')) {
|
||||
for (const line of fs.readFileSync(file, 'utf8').split('\n').filter(Boolean)) {
|
||||
try {
|
||||
const record = JSON.parse(line);
|
||||
if (record.execution === 'executed' && record.cost_known !== false && typeof record.case === 'string') out.set(record.case, (out.get(record.case) ?? 0) + (Number(record.cost_usd) || 0));
|
||||
} catch { /* malformed line */ }
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** One run's observations as a map: the bins each attributed case invoked, and its known cost. */
|
||||
export function observeRun(commandsByCase: Map<string, string[]>, ex: Pick<ExercisedConsumers, 'binsInCommand'>, run: { runId: string; observedAt: string; costs?: Map<string, number> }): ExercisedMap {
|
||||
const cases: Record<string, ExercisedCase> = {};
|
||||
for (const [id, commands] of commandsByCase) {
|
||||
cases[id] = { observations: 1, withCommands: commands.length ? 1 : 0, commands: [...new Set(commands.flatMap(command => ex.binsInCommand(command)))].sort() };
|
||||
}
|
||||
for (const [id, cost] of run.costs ?? []) {
|
||||
cases[id] ??= { observations: 1, withCommands: 0, commands: [] };
|
||||
Object.assign(cases[id], { costUsd: Math.round(cost * 10000) / 10000, costRuns: 1 });
|
||||
}
|
||||
return { schema: 1, generatedAt: run.observedAt, observedThrough: run.observedAt, sourceRuns: [run.runId], cases };
|
||||
}
|
||||
|
||||
/**
|
||||
* Union-only merge: commands are unioned, counts add for runs the base has
|
||||
* not seen, costs average by run count, and nothing the base holds is ever
|
||||
* removed (an absent or empty case in `fresh` changes nothing).
|
||||
*/
|
||||
export function mergeExercisedMap(base: ExercisedMap, fresh: ExercisedMap, generatedAt = new Date().toISOString()): ExercisedMap {
|
||||
const counts = fresh.sourceRuns.some(run => !base.sourceRuns.includes(run));
|
||||
const cases: Record<string, ExercisedCase> = structuredClone(base.cases);
|
||||
for (const [id, entry] of Object.entries(fresh.cases)) {
|
||||
const old = cases[id];
|
||||
const merged: ExercisedCase = {
|
||||
observations: (old?.observations ?? 0) + (counts ? entry.observations : 0),
|
||||
withCommands: (old?.withCommands ?? 0) + (counts ? entry.withCommands : 0),
|
||||
commands: [...new Set([...old?.commands ?? [], ...entry.commands])].sort(),
|
||||
};
|
||||
const oldRuns = old?.costRuns ?? 0, freshRuns = counts && entry.costUsd !== undefined ? entry.costRuns ?? 1 : 0;
|
||||
if (freshRuns) Object.assign(merged, { costUsd: Math.round(((old?.costUsd ?? 0) * oldRuns + entry.costUsd! * freshRuns) / (oldRuns + freshRuns) * 10000) / 10000, costRuns: oldRuns + freshRuns });
|
||||
else if (old?.costUsd !== undefined) Object.assign(merged, { costUsd: old.costUsd, costRuns: oldRuns });
|
||||
cases[id] = merged;
|
||||
}
|
||||
return {
|
||||
schema: 1, generatedAt,
|
||||
observedThrough: [base.observedThrough, fresh.observedThrough].sort().at(-1)!,
|
||||
sourceRuns: [...new Set([...base.sourceRuns, ...fresh.sourceRuns])].sort(),
|
||||
cases: Object.fromEntries(Object.entries(cases).sort(([a], [b]) => a.localeCompare(b))),
|
||||
};
|
||||
}
|
||||
|
||||
export function formatExercisedMap(map: ExercisedMap): string {
|
||||
return `${JSON.stringify(map, null, 2)}\n`;
|
||||
}
|
||||
|
||||
/** `MAP_GAP <case> <command>`: a recorded command whose files all lie outside the case's static-plus-observed exercised closure. */
|
||||
export function mapGaps(commandsByCase: Map<string, string[]>, ex: ExercisedConsumers): Array<{ id: string; command: string }> {
|
||||
const gaps: Array<{ id: string; command: string }> = [];
|
||||
for (const [id, commands] of [...commandsByCase].sort(([a], [b]) => a.localeCompare(b))) {
|
||||
const closure = ex.closure(id);
|
||||
for (const command of [...new Set(commands.flatMap(raw => ex.binsInCommand(raw)))].sort()) {
|
||||
const files = ex.commandFiles(command);
|
||||
if (files.length && !files.some(file => closure.has(file))) gaps.push({ id, command });
|
||||
}
|
||||
}
|
||||
return gaps;
|
||||
}
|
||||
|
||||
/** Executed cases that recorded no command although their loaded skill's shell runs bins: blind to gap detection. */
|
||||
export function blindCases(commandsByCase: Map<string, string[]>, ex: ExercisedConsumers): string[] {
|
||||
return [...commandsByCase].filter(([id, commands]) => commands.length === 0
|
||||
&& [...ex.closure(id)].some(([file, label]) => file.startsWith('bin/') && label.startsWith('skill bash via'))).map(([id]) => id).sort();
|
||||
}
|
||||
|
||||
/** Stable exit codes of test:exercised-map (docs/TESTING_INTERNALS.md#exercised-path-map). */
|
||||
export const REFRESH_EXIT = { usage: 2, unavailable: 3, incomplete: 4 } as const;
|
||||
|
||||
/** A refresh that cannot be trusted: nothing is written and the committed union stays as it was. */
|
||||
export class RefreshError extends Error {
|
||||
constructor(readonly exitCode: typeof REFRESH_EXIT.unavailable | typeof REFRESH_EXIT.incomplete, message: string) { super(message); }
|
||||
}
|
||||
|
||||
/** One MAP_GAP line, saying who it is for and what follows from it. */
|
||||
export function formatMapGap(gap: { id: string; command: string }): string {
|
||||
return `MAP_GAP ${gap.id} ${gap.command}: non-blocking for this PR; the next census refresh widens the map (${EXERCISED_MAP_ANCHOR})`;
|
||||
}
|
||||
|
||||
function writeAtomically(file: string, text: string): void {
|
||||
fs.mkdirSync(path.dirname(path.resolve(file)), { recursive: true });
|
||||
const temp = `${file}.${process.pid}.tmp`;
|
||||
fs.writeFileSync(temp, text);
|
||||
fs.renameSync(temp, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Census refresh from local report directories (paid-slice artifacts under
|
||||
* shards/, plus trial-outcomes.jsonl). Every executed case must have shard
|
||||
* evidence; a missing directory, no shards, no trial outcomes or an executed
|
||||
* case without a shard throws before anything is written.
|
||||
*/
|
||||
export function refreshFromReportDirs(dirs: string[], runId: string, base: ExercisedMap, ex: ExercisedConsumers, observedAt = new Date().toISOString(), maps = PR_PROFILE_MAPS) {
|
||||
const missing = dirs.filter(dir => !fs.existsSync(dir));
|
||||
if (missing.length) throw new RefreshError(REFRESH_EXIT.unavailable, `report director${missing.length > 1 ? 'ies' : 'y'} not found: ${missing.join(', ')}`);
|
||||
const shards = dirs.flatMap(readShardCommands);
|
||||
if (shards.length === 0) throw new RefreshError(REFRESH_EXIT.incomplete, `no shards/<shard>/ directories under ${dirs.join(', ')}; download every paid-slice-* artifact of the run first`);
|
||||
const outcomes = dirs.flatMap(dir => walk(dir).filter(file => path.basename(file) === 'trial-outcomes.jsonl'));
|
||||
if (outcomes.length === 0) throw new RefreshError(REFRESH_EXIT.incomplete, `no trial-outcomes.jsonl under ${dirs.join(', ')}, so the executed cases cannot be checked against the shard evidence`);
|
||||
const commands = attributeCommands(shards, maps);
|
||||
const executed = new Set(outcomes.flatMap(file => fs.readFileSync(file, 'utf8').split('\n').flatMap(line => {
|
||||
try { const record = JSON.parse(line); return record.execution === 'executed' && typeof record.case === 'string' ? [record.case as string] : []; } catch { return []; }
|
||||
})));
|
||||
const uncovered = [...executed].filter(id => Object.hasOwn(maps.e2eTouchfiles, id) && !commands.has(id)).sort();
|
||||
if (uncovered.length) throw new RefreshError(REFRESH_EXIT.incomplete, `${uncovered.length} executed case(s) have no shard artifact: ${uncovered.slice(0, 10).join(', ')}${uncovered.length > 10 ? ' ...' : ''}`);
|
||||
const costs = new Map<string, number>();
|
||||
for (const dir of dirs) for (const [id, cost] of readCaseCosts(dir)) costs.set(id, (costs.get(id) ?? 0) + cost);
|
||||
const merged = mergeExercisedMap(base, observeRun(commands, ex, { runId, observedAt, costs }), observedAt);
|
||||
return { merged, commands };
|
||||
}
|
||||
|
||||
function census(dirs: string[], runId: string, out: string, reportPath: string | undefined): void {
|
||||
const ex = checkoutExercisedConsumers(PR_PROFILE_MAPS, ROOT, PR_FULL_GATE_FILES);
|
||||
const base = ex.map!;
|
||||
const { merged, commands } = refreshFromReportDirs(dirs, runId, base, ex);
|
||||
writeAtomically(out, formatExercisedMap(merged));
|
||||
const added = Object.entries(merged.cases).flatMap(([id, entry]) => entry.commands.filter(command => !base.cases[id]?.commands.includes(command)).map(command => `${id} ${command}`));
|
||||
const gaps = mapGaps(commands, ex);
|
||||
const blind = blindCases(commands, ex);
|
||||
const lines = [
|
||||
'## Exercised-path map (shadow, non-blocking)', '',
|
||||
`- ${commands.size} executed case(s), ${[...commands.values()].reduce((sum, list) => sum + list.length, 0)} recorded command(s); ${added.length} new observed edge(s).`,
|
||||
`- Refresh: \`bun run test:exercised-map --from-run ${runId}\`, then open the change as an ordinary PR (shadow-only data: it selects no paid case).`,
|
||||
`- MAP_GAP (a command outside its case's static-plus-observed closure): ${gaps.length}`,
|
||||
...gaps.map(gap => ` - ${formatMapGap(gap)}`),
|
||||
`- Cases that recorded no commands although their skill runs bins (PTY capture is the activation prerequisite): ${blind.length ? blind.join(', ') : 'none'}`,
|
||||
...added.slice(0, 50).map(edge => ` - new: ${edge}`),
|
||||
`- Docs: ${EXERCISED_MAP_ANCHOR}`,
|
||||
];
|
||||
console.log(lines.join('\n'));
|
||||
if (reportPath) fs.writeFileSync(reportPath, `${lines.join('\n')}\n`);
|
||||
}
|
||||
|
||||
/** Union every exercised-commands.json of a downloaded exercised-map artifact into `base`; any missing or malformed file throws. */
|
||||
export function mergeArtifactDir(dir: string, base: ExercisedMap, generatedAt = new Date().toISOString()): ExercisedMap {
|
||||
const files = fs.existsSync(dir) ? walk(dir).filter(file => path.basename(file) === 'exercised-commands.json') : [];
|
||||
if (files.length === 0) throw new RefreshError(REFRESH_EXIT.incomplete, `no exercised-commands.json in ${dir} (the census refresh step failed or its ${EXERCISED_MAP_ARTIFACT}-a<attempt> artifact is partial)`);
|
||||
let map = base;
|
||||
for (const file of files.sort()) {
|
||||
let fresh: ExercisedMap;
|
||||
try { fresh = parseExercisedMap(fs.readFileSync(file, 'utf8')); }
|
||||
catch (error) { throw new RefreshError(REFRESH_EXIT.incomplete, `${path.relative(dir, file)} is not a complete exercised map: ${error instanceof Error ? error.message : String(error)}`); }
|
||||
map = mergeExercisedMap(map, fresh, generatedAt);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
export type ArtifactDownload = (runId: string, dir: string) => { status: number | null; stderr: string };
|
||||
|
||||
const ghDownload: ArtifactDownload = (runId, dir) => {
|
||||
const result = spawnSync('gh', ['run', 'download', runId, '--pattern', `${EXERCISED_MAP_ARTIFACT}-*`, '--dir', dir], { encoding: 'utf8', timeout: 120_000 });
|
||||
return { status: result.status, stderr: result.stderr || result.error?.message || '' };
|
||||
};
|
||||
|
||||
/** Download a census run's exercised-map artifact and union it into `target`; on any failure nothing is written. */
|
||||
export function refreshFromRun(runId: string, target: string, download: ArtifactDownload = ghDownload): ExercisedMap {
|
||||
if (!/^\d+$/.test(runId)) throw new RefreshError(REFRESH_EXIT.unavailable, `--from-run needs a numeric GitHub run id, got ${runId}`);
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'exercised-map-'));
|
||||
try {
|
||||
const result = download(runId, dir);
|
||||
if (result.status !== 0) {
|
||||
const reason = result.stderr.trim();
|
||||
const hint = /\b403\b/.test(reason)
|
||||
? `HTTP 403 (the installation's artifact download limit); download the ${EXERCISED_MAP_ARTIFACT}-a<attempt> artifact from the run page and pass its directory with --from-dir`
|
||||
: `check \`gh auth status\` and that run ${runId} uploaded an ${EXERCISED_MAP_ARTIFACT}-a<attempt> artifact`;
|
||||
throw new RefreshError(REFRESH_EXIT.unavailable, `gh run download ${runId} failed: ${reason || `exit ${result.status}`}; ${hint}`);
|
||||
}
|
||||
const map = mergeArtifactDir(dir, parseExercisedMap(fs.readFileSync(target, 'utf8')));
|
||||
writeAtomically(target, formatExercisedMap(map));
|
||||
return map;
|
||||
} finally { fs.rmSync(dir, { recursive: true, force: true }); }
|
||||
}
|
||||
|
||||
export const REPLAY_FIXTURE = 'test/fixtures/exercised-map-replay.json';
|
||||
|
||||
export interface ReplayRun { runId: number; pr: number; packageVersionOnly: boolean; failedGateCases: string[]; changedFiles: string[] }
|
||||
|
||||
/** One recorded red run under today's selection and its shadow: which failed gate cases each would run. */
|
||||
export interface ShadowReplayRow { runId: number; pr: number; mode: string; today: number; shadow: number; savingUsd: number; caughtToday: string[]; misses: string[]; retired: string[] }
|
||||
|
||||
export function replayShadow(runs: readonly ReplayRun[]): ShadowReplayRow[] {
|
||||
const gateIds = Object.keys(PR_PROFILE_MAPS.tiers).filter(id => PR_PROFILE_MAPS.tiers[id] === 'gate');
|
||||
return runs.map(run => {
|
||||
const result = computePaidCaseSelection({ profile: 'pr', env: {}, changedFiles: run.changedFiles, packageVersionOnly: run.packageVersionOnly });
|
||||
const today = new Set(result.selection.e2e ?? gateIds);
|
||||
const shadow = result.coverage?.shadow;
|
||||
if (shadow?.error) throw new Error(`run ${run.runId}: shadow unavailable (${shadow.error})`);
|
||||
const shadowSet = new Set(shadow?.e2e ?? today);
|
||||
const live = run.failedGateCases.filter(id => PR_PROFILE_MAPS.tiers[id] === 'gate');
|
||||
return { runId: run.runId, pr: run.pr, mode: result.coverage?.mode ?? 'full', today: today.size, shadow: shadowSet.size, savingUsd: shadow?.predictedSavingUsd ?? 0,
|
||||
caughtToday: live.filter(id => today.has(id)), misses: live.filter(id => !shadowSet.has(id)), retired: run.failedGateCases.filter(id => !live.includes(id)) };
|
||||
});
|
||||
}
|
||||
|
||||
export function formatShadowReplay(rows: readonly ShadowReplayRow[]): string[] {
|
||||
const pairs = (list: readonly ShadowReplayRow[]) => list.reduce((sum, row) => sum + new Set([...row.caughtToday, ...row.misses]).size, 0);
|
||||
const misses = rows.flatMap(row => row.misses.map(id => `${row.runId} #${row.pr} ${id}`));
|
||||
const modes = new Map<string, number>();
|
||||
for (const row of rows) modes.set(row.mode, (modes.get(row.mode) ?? 0) + 1);
|
||||
const mean = (pick: (row: ShadowReplayRow) => number) => rows.length ? (rows.reduce((sum, row) => sum + pick(row), 0) / rows.length).toFixed(1) : 'n/a';
|
||||
return [
|
||||
`Exercised-path shadow replay over ${rows.length} recorded red PR run(s) on this checkout`,
|
||||
`- failed gate (run, case) pairs: ${pairs(rows)}, ${pairs(rows.filter(row => row.mode !== 'full-fallback'))} of them in runs that do not fall back to the full gate (${rows.reduce((sum, row) => sum + row.retired.length, 0)} more on cases no longer in the gate)`,
|
||||
`- today's selection runs ${rows.reduce((sum, row) => sum + row.caughtToday.length, 0)} of them; modes ${[...modes].map(([mode, n]) => `${mode} ${n}`).join(', ')}`,
|
||||
`- mean gate cases: today ${mean(row => row.today)}, shadow ${mean(row => row.shadow)}; predicted shadow saving over these runs $${rows.reduce((sum, row) => sum + row.savingUsd, 0).toFixed(2)}`,
|
||||
`- MISSES (failed, not in the shadow selection): ${misses.length}`,
|
||||
...misses.map(miss => ` - ${miss}`),
|
||||
];
|
||||
}
|
||||
|
||||
const USAGE = 'usage: bun run test:exercised-map --from-run <id> [--out <file>] | --from-dir <dir>... [--run-id <id>] [--out <file>] [--report <file>] | --check | --replay [<fixture>]';
|
||||
|
||||
if (import.meta.main) {
|
||||
const argv = process.argv.slice(2);
|
||||
const values = (flag: string) => argv.flatMap((arg, index) => arg === flag && argv[index + 1] ? [argv[index + 1]!] : []);
|
||||
const out = values('--out')[0] ?? path.join(ROOT, EXERCISED_MAP_PATH);
|
||||
try {
|
||||
if (argv.includes('--check')) {
|
||||
const map = parseExercisedMap(fs.readFileSync(path.join(ROOT, EXERCISED_MAP_PATH), 'utf8'));
|
||||
console.log(`${EXERCISED_MAP_PATH}: ${Object.keys(map.cases).length} cases, ${map.sourceRuns.length} source runs, observed through ${map.observedThrough}`);
|
||||
} else if (argv.includes('--replay')) {
|
||||
const fixture = JSON.parse(fs.readFileSync(path.resolve(ROOT, values('--replay')[0] ?? REPLAY_FIXTURE), 'utf8')) as { runs: ReplayRun[] };
|
||||
const rows = replayShadow(fixture.runs);
|
||||
console.log(formatShadowReplay(rows).join('\n'));
|
||||
if (rows.some(row => row.misses.length)) process.exit(1);
|
||||
} else if (values('--from-run').length) {
|
||||
const runId = values('--from-run')[0]!;
|
||||
const map = refreshFromRun(runId, out);
|
||||
console.log(`union-merged run ${runId}'s ${EXERCISED_MAP_ARTIFACT} artifact into ${path.relative(ROOT, out)} (${Object.keys(map.cases).length} cases, observed through ${map.observedThrough}); review the diff and open it as a PR`);
|
||||
} else if (values('--from-dir').length) {
|
||||
const dirs = values('--from-dir');
|
||||
if (dirs.length === 1 && fs.existsSync(dirs[0]!) && readShardCommands(dirs[0]!).length === 0 && walk(dirs[0]!).some(file => path.basename(file) === 'exercised-commands.json')) {
|
||||
const map = mergeArtifactDir(dirs[0]!, parseExercisedMap(fs.readFileSync(out, 'utf8')));
|
||||
writeAtomically(out, formatExercisedMap(map));
|
||||
console.log(`union-merged the ${EXERCISED_MAP_ARTIFACT} artifact in ${dirs[0]} into ${path.relative(ROOT, out)}; review the diff and open it as a PR`);
|
||||
} else {
|
||||
const runId = values('--run-id')[0];
|
||||
if (!runId) { console.error(`test:exercised-map: --from-dir with report directories needs --run-id <id> (the run whose artifacts these are)\n${USAGE}`); process.exit(REFRESH_EXIT.usage); }
|
||||
census(dirs, runId, out, values('--report')[0]);
|
||||
}
|
||||
} else {
|
||||
console.error(USAGE);
|
||||
process.exit(REFRESH_EXIT.usage);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`test:exercised-map: ${error instanceof Error ? error.message : String(error)}${error instanceof RefreshError ? '; nothing was written, the committed union is unchanged' : ''}`);
|
||||
process.exit(error instanceof RefreshError ? error.exitCode : 1);
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,9 @@ import { type ManifestEntry, PAID_TEST_DURATIONS_FILE, type PaidRunManifest, typ
|
||||
import { DEFAULT_JOBS, type PaidCaseSelection, type PaidTier, ROOT, type ShardTrialRecord } from './paid-types';
|
||||
import { collectPaidTestFiles, isAllSkippedPass, shardSlug, paidSelectionEnv } from './paid-select';
|
||||
import type { RunShardsOptions } from '../test-paid-shards';
|
||||
import { attributeCommands, formatMapGap, mapGaps, readShardCommands } from '../exercised-map';
|
||||
import { checkoutExercisedConsumers } from '../pr-dependencies';
|
||||
import { PR_FULL_GATE_FILES, PR_PROFILE_MAPS } from '../test-pr-profile';
|
||||
|
||||
// ─── Local diagnosis: one case through the CI panel runner (A9) ────────────
|
||||
|
||||
@@ -482,6 +485,30 @@ export function infraOnly(problems: readonly string[]): boolean {
|
||||
return problems.length > 0 && problems.every(problem => INFRA_PROBLEMS.some(re => re.test(problem)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shadow gap detection (docs/TESTING_INTERNALS.md#exercised-path-map): a
|
||||
* command an executed case ran outside its static-plus-observed exercised
|
||||
* closure prints a MAP_GAP line (formatMapGap: non-blocking for this PR, the
|
||||
* next census refresh widens the map) and lands in map-gaps.txt. It is its own
|
||||
* result: never a case verdict, a lane problem or a re-dispatch input.
|
||||
*/
|
||||
export function reportMapGaps(reportDir: string, executedCases: ReadonlySet<string>, rootDir = ROOT): string[] {
|
||||
const out = path.join(reportDir, 'map-gaps.txt');
|
||||
try {
|
||||
const commands = new Map([...attributeCommands(readShardCommands(reportDir))].filter(([id, list]) => executedCases.has(id) && list.length > 0));
|
||||
const lines = commands.size === 0 ? [] : mapGaps(commands, checkoutExercisedConsumers(PR_PROFILE_MAPS, rootDir, PR_FULL_GATE_FILES)).map(formatMapGap);
|
||||
fs.writeFileSync(out, lines.length ? `${lines.join('\n')}\n` : '');
|
||||
console.log(`[test:paid] exercised-path map (shadow, non-blocking): ${lines.length} MAP_GAP line(s) over ${commands.size} executed case(s) with recorded commands`);
|
||||
for (const line of lines) console.log(` ${line}`);
|
||||
return lines;
|
||||
} catch (error) {
|
||||
const reason = error instanceof Error ? error.message : String(error);
|
||||
fs.writeFileSync(out, `MAP_GAP unavailable: ${reason}\n`);
|
||||
console.log(`[test:paid] exercised-path map (shadow, non-blocking): MAP_GAP unavailable: ${reason}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report mode: reconcile slice artifacts against the manifest (fail-closed),
|
||||
* compute every panel verdict with panelVerdict(), write collector-outcomes
|
||||
@@ -743,6 +770,7 @@ export function runPaidReport(reportDir: string, options: { writeDurations?: boo
|
||||
...(t.exit_reason ? { exit_reason: t.exit_reason } : {}), ...(t.error ? { error: t.error } : {}) })) })),
|
||||
// evals.yml wraps these in a fixed fence for the PR comment.
|
||||
failures: failureLines.map(line => sanitizeFixedFenceLine(line)) }, null, 2) + '\n');
|
||||
reportMapGaps(reportDir, new Set(executed.map(record => record.case)), rootDir);
|
||||
if (verdict.problems.length) {
|
||||
console.error(`[test:paid] report: ${verdict.problems.length} problem(s):`);
|
||||
for (const problem of verdict.problems) console.error(` ✗ ${problem}`);
|
||||
|
||||
@@ -0,0 +1,357 @@
|
||||
/**
|
||||
* Exercised-path consumer map (W2-A2, shadow mode): edge classes on a
|
||||
* synthetic tree, the five variant-c miss shapes as negative controls,
|
||||
* union-only refreshes, the refresh contract on unavailable or partial input,
|
||||
* shadow-only map data selecting nothing, shadow output that never changes the
|
||||
* real selection, MAP_GAP detection, and parity with the
|
||||
* measured prototype (docs/TESTING_INTERNALS.md#exercised-path-map).
|
||||
*/
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import * as fs from 'node:fs';
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import {
|
||||
deriveDependencies, EXERCISED_MAP_PATH, exercisedConsumers, parseExercisedMap, type ExercisedMap,
|
||||
} from '../scripts/pr-dependencies';
|
||||
import {
|
||||
formatPrCoverageSummary, PR_FULL_GATE_FILES, PR_PROFILE_MAPS, selectPrProfile,
|
||||
} from '../scripts/test-pr-profile';
|
||||
import {
|
||||
attributeCommands, blindCases, formatExercisedMap, formatMapGap, formatShadowReplay, mapGaps, mergeExercisedMap, observeRun, readCaseCosts, readShardCommands,
|
||||
REFRESH_EXIT, RefreshError, refreshFromReportDirs, refreshFromRun, REPLAY_FIXTURE, replayShadow, type ArtifactDownload, type ReplayRun,
|
||||
} from '../scripts/exercised-map';
|
||||
import { reportMapGaps } from '../scripts/lib/paid-report';
|
||||
import { computePaidCaseSelection } from '../scripts/test-paid-shards';
|
||||
import { prototypeConsumers } from './helpers/exercised-prototype';
|
||||
|
||||
const ROOT = path.resolve(import.meta.dir, '..');
|
||||
|
||||
function fixtureRepo(files: Record<string, string>): string {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'exercised-map-'));
|
||||
for (const [file, text] of Object.entries(files)) {
|
||||
fs.mkdirSync(path.dirname(path.join(root, file)), { recursive: true });
|
||||
fs.writeFileSync(path.join(root, file), text);
|
||||
}
|
||||
for (const args of [['init', '-q'], ['add', '-A']]) {
|
||||
const result = spawnSync('git', args, { cwd: root, encoding: 'utf8', timeout: 10_000 });
|
||||
if (result.status !== 0) throw new Error(`git ${args[0]} failed: ${result.stderr}`);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
const map = (cases: ExercisedMap['cases'], sourceRuns = ['1'], observedThrough = '2026-10-01T00:00:00Z'): ExercisedMap =>
|
||||
({ schema: 1, generatedAt: observedThrough, observedThrough, sourceRuns, cases });
|
||||
|
||||
const FENCE = '```';
|
||||
const skill = [
|
||||
'# alpha', '', 'Prose naming gstack-prose and /gstack-slash is not run.', '', FENCE + 'bash',
|
||||
'gstack-start --quiet',
|
||||
'echo "see gstack-echoed for details"',
|
||||
'echo "now $(gstack-subst --print)"',
|
||||
'# gstack-commented',
|
||||
'case "$x" in gstack-casepat) true ;; esac',
|
||||
'VAR=gstack-bare',
|
||||
'"$ROOT/bin/gstack-pathed" run',
|
||||
'. "$ROOT/lib/sourced.sh"',
|
||||
"cat <<'EOF'", 'gstack-quoted-heredoc', 'EOF',
|
||||
'cat <<EOF', '$(gstack-expanding)', 'gstack-heredoc-prose', 'EOF',
|
||||
"bash <<'EOF'", 'gstack-interp', 'EOF',
|
||||
'$B goto https://example.com',
|
||||
'bun run build-thing',
|
||||
'./setup --quiet',
|
||||
FENCE, '',
|
||||
].join('\n');
|
||||
const bins = ['echoed', 'subst', 'commented', 'casepat', 'bare', 'pathed', 'quoted-heredoc', 'expanding', 'heredoc-prose', 'interp', 'prose', 'slash', 'observed', 'gapper'];
|
||||
const tree = {
|
||||
'test/skill-e2e-alpha.test.ts': "import './helpers/h';\n",
|
||||
'test/helpers/h.ts': "const a = path.join(ROOT, 'lib', 'joined.ts');\nconst b = 'lib/quoted.ts';\nexport { a, b };\n",
|
||||
'lib/joined.ts': '', 'lib/quoted.ts': '', 'lib/deep.ts': '', 'lib/sourced.sh': '#!/bin/sh\n', 'lib/unreached.ts': '',
|
||||
'alpha/SKILL.md.tmpl': skill,
|
||||
'bin/gstack-start': '#!/usr/bin/env bash\ngstack-helper "$@"\n',
|
||||
'bin/gstack-helper': "#!/usr/bin/env bun\nimport '../lib/deep';\n",
|
||||
'bin/gstack-config': '#!/usr/bin/env bash\necho config\n',
|
||||
...Object.fromEntries(bins.map(name => [`bin/gstack-${name}`, '#!/bin/sh\n'])),
|
||||
'test/skill-e2e-beta.test.ts': '', 'test/skill-e2e-gamma.test.ts': '', 'test/skill-e2e-delta.test.ts': '',
|
||||
'gamma/SKILL.md.tmpl': `# gamma\n\n${FENCE}bash\ngstack-config get proactive\n${FENCE}\n`,
|
||||
'scripts/build.sh': 'bun build --compile browse/src/cli.ts --outfile browse/dist/browse\n', 'browse/src/cli.ts': "import './page';\n", 'browse/src/page.ts': '',
|
||||
'scripts/thing.ts': '', 'scripts/resolvers/index.ts': '', 'setup': '#!/usr/bin/env bash\n',
|
||||
'package.json': JSON.stringify({ scripts: { 'build-thing': 'bun run scripts/thing.ts' } }),
|
||||
};
|
||||
const maps = {
|
||||
e2eTouchfiles: {
|
||||
alpha: ['test/skill-e2e-alpha.test.ts', 'alpha/**'], beta: ['test/skill-e2e-beta.test.ts'],
|
||||
gamma: ['test/skill-e2e-gamma.test.ts', 'gamma/**'], delta: ['test/skill-e2e-delta.test.ts', 'bin/gstack-config', 'lib/deep.ts'],
|
||||
},
|
||||
judgeTouchfiles: {}, globalTouchfiles: [] as string[],
|
||||
};
|
||||
const profileMaps = { ...maps, tiers: { alpha: 'gate', beta: 'gate', gamma: 'gate', delta: 'gate' } as const };
|
||||
const observed = map({ beta: { observations: 3, withCommands: 2, commands: ['bin/gstack-observed'], costUsd: 2, costRuns: 3 },
|
||||
alpha: { observations: 4, withCommands: 4, commands: [], costUsd: 5, costRuns: 4 }, gamma: { observations: 2, withCommands: 0, commands: [] } });
|
||||
|
||||
describe('exercised consumers on a synthetic tree', () => {
|
||||
const root = fixtureRepo(tree);
|
||||
const ex = exercisedConsumers(maps, root, { observed, stopAt: ['setup'] });
|
||||
const alpha = ex.closure('alpha');
|
||||
|
||||
test('each kept edge class reaches its file, with its provenance', () => {
|
||||
expect(alpha.get('alpha/SKILL.md.tmpl')).toBe('touchfile');
|
||||
expect(alpha.get('bin/gstack-start')).toBe('skill bash via bin/gstack-start');
|
||||
expect(alpha.get('lib/deep.ts')).toBe('skill bash via bin/gstack-start');
|
||||
expect(alpha.get('lib/joined.ts')).toBe('import');
|
||||
expect(alpha.get('lib/quoted.ts')).toBe('import');
|
||||
for (const file of ['bin/gstack-subst', 'bin/gstack-pathed', 'lib/sourced.sh', 'bin/gstack-expanding', 'bin/gstack-interp', 'browse/src/page.ts', 'scripts/thing.ts', 'setup']) {
|
||||
expect(alpha.has(file), file).toBe(true);
|
||||
}
|
||||
expect(ex.closure('beta').get('bin/gstack-observed')).toBe('observed bin/gstack-observed');
|
||||
});
|
||||
|
||||
test('messages, comments, case patterns, bare assignments, quoted and expanded heredoc prose, prose and slash commands are not edges', () => {
|
||||
for (const name of ['echoed', 'commented', 'casepat', 'bare', 'quoted-heredoc', 'heredoc-prose', 'prose', 'slash']) {
|
||||
expect(alpha.has(`bin/gstack-${name}`), name).toBe(false);
|
||||
}
|
||||
expect(ex.e2e.get('lib/unreached.ts')).toBeUndefined();
|
||||
});
|
||||
|
||||
test('the closure stops at a full-gate file and at the global set', () => {
|
||||
const stopped = exercisedConsumers({ ...maps, globalTouchfiles: ['bin/gstack-start'] }, fixtureRepo(tree), { observed, stopAt: ['setup'] });
|
||||
expect(stopped.closure('alpha').has('bin/gstack-start')).toBe(true);
|
||||
expect(stopped.closure('alpha').has('lib/deep.ts')).toBe(false);
|
||||
});
|
||||
|
||||
test('bins in recorded commands: paths, bare names, PTY lines and compiled outfiles', () => {
|
||||
expect(ex.binsInCommand('gstack-start --x && "$B" goto y')).toEqual(['bin/gstack-start', 'browse/dist/browse']);
|
||||
expect(ex.binsInCommand('PTY:gstack-config-get proactive')).toEqual(['bin/gstack-config']);
|
||||
expect(ex.binsInCommand('"$ROOT/bin/gstack-start" --x')).toEqual(['bin/gstack-start']);
|
||||
expect(ex.binsInCommand('run /gstack-start next')).toEqual([]);
|
||||
expect(ex.commandFiles('browse/dist/browse').sort()).toEqual(['browse/src/cli.ts', 'browse/src/page.ts']);
|
||||
});
|
||||
|
||||
test('the variant-c miss shapes stay selected in the shadow (negative controls)', () => {
|
||||
const shadow = (changedFiles: string[], selectedE2E: string[]) => selectPrProfile({
|
||||
maps: profileMaps, profile: ['alpha', 'beta', 'gamma', 'delta'], selectedE2E, selectedJudges: [], changedFiles,
|
||||
derived: deriveDependencies(maps, root), exercised: ex,
|
||||
}).shadow!;
|
||||
// A preamble hub a touchfile maps only for another case (skill-start/end x3; gstack-config for the PTY case with no observations).
|
||||
expect(shadow(['bin/gstack-config'], ['delta']).e2e).toEqual(['delta', 'gamma']);
|
||||
expect(observed.cases.gamma!.withCommands).toBe(0);
|
||||
// A lib reached only through a bin the skill runs (redact-patterns via gstack-redact).
|
||||
expect(shadow(['lib/deep.ts'], ['delta']).e2e).toEqual(['alpha', 'delta']);
|
||||
expect(shadow(['lib/deep.ts'], ['delta']).provenance).toEqual([{ file: 'lib/deep.ts', summary: 'selects 2 case(s): skill bash via bin/gstack-start (1), touchfile (1)' }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('the five recorded variant-c misses on this checkout', () => {
|
||||
const shadowOf = (file: string) => computePaidCaseSelection({ profile: 'pr', env: {}, changedFiles: [file], packageVersionOnly: true }).coverage!.shadow!;
|
||||
|
||||
test('skill-start reds stay in the shadow of a gstack-skill-start change', () => {
|
||||
const shadow = shadowOf('bin/gstack-skill-start');
|
||||
expect(shadow.error).toBeUndefined();
|
||||
for (const id of ['qa-functional-webhook-fix', 'qa-functional-cli-report', 'ship-exploratory-plan-checks']) expect(shadow.e2e, id).toContain(id);
|
||||
}, 60_000);
|
||||
|
||||
test('gstack-config reaches the PTY case that records no commands; redact-patterns reaches ship-docsync-store', () => {
|
||||
expect(shadowOf('bin/gstack-config').e2e).toContain('plan-mode-no-op');
|
||||
const committed = parseExercisedMap(fs.readFileSync(path.join(ROOT, EXERCISED_MAP_PATH), 'utf8'));
|
||||
const ex = exercisedConsumers(PR_PROFILE_MAPS, ROOT, { observed: committed, stopAt: PR_FULL_GATE_FILES });
|
||||
expect(ex.closure('plan-mode-no-op').get('bin/gstack-config')).toStartWith('skill bash via');
|
||||
expect(ex.closure('ship-docsync-store').has('lib/redact-patterns.ts')).toBe(true);
|
||||
}, 60_000);
|
||||
});
|
||||
|
||||
describe('shadow output never changes the real selection', () => {
|
||||
test('mode, cases, judges and reasons equal the selection without a shadow', () => {
|
||||
for (const files of [['bin/gstack-config'], ['design/src/evolve.ts'], ['review/SKILL.md.tmpl'], ['lib/fs-utils.ts', 'docs/x.md'], ['ETHOS.md']]) {
|
||||
const withShadow = selectPrProfile({ selectedE2E: [], selectedJudges: [], changedFiles: files });
|
||||
const without = selectPrProfile({ selectedE2E: [], selectedJudges: [], changedFiles: files, exercised: null });
|
||||
expect(withShadow.shadow, files.join()).toBeDefined();
|
||||
const { shadow, ...rest } = withShadow;
|
||||
expect(rest, files.join()).toEqual(without);
|
||||
if (withShadow.mode === 'full-fallback') expect(shadow!.e2e).toEqual(withShadow.e2e);
|
||||
}
|
||||
}, 60_000);
|
||||
|
||||
test('the coverage summary prints one shadow line; a broken map is reported, not fatal', () => {
|
||||
const result = computePaidCaseSelection({ profile: 'pr', env: {}, changedFiles: ['design/src/evolve.ts'], packageVersionOnly: true });
|
||||
const lines = formatPrCoverageSummary({ profile: 'pr', selection: result.selection, prCoverage: result.coverage });
|
||||
expect(lines.filter(line => line.includes('Shadow exercised-path map (not active)'))).toHaveLength(1);
|
||||
const broken = selectPrProfile({ selectedE2E: [], selectedJudges: [], changedFiles: ['design/src/evolve.ts'], exercised: null });
|
||||
expect(formatPrCoverageSummary({ prCoverage: { ...broken, shadow: { e2e: broken.e2e, wouldDrop: [], wouldAdd: [], provenance: [], predictedSavingUsd: 0, unpricedCases: 0, unknownCostShare: 0, error: 'bad map' } } })
|
||||
.some(line => line.includes('unavailable (bad map); selection unaffected'))).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('union-only refreshes', () => {
|
||||
const base = map({ a: { observations: 2, withCommands: 1, commands: ['bin/x'], costUsd: 4, costRuns: 2 } }, ['1']);
|
||||
|
||||
test('disjoint branches merge to the same union in either order, and nothing is removed', () => {
|
||||
const left = map({ a: { observations: 1, withCommands: 1, commands: ['bin/y'] } }, ['2'], '2026-10-02T00:00:00Z');
|
||||
const right = map({ b: { observations: 1, withCommands: 1, commands: ['bin/z'], costUsd: 1, costRuns: 1 } }, ['3'], '2026-10-03T00:00:00Z');
|
||||
const one = mergeExercisedMap(mergeExercisedMap(base, left, 't'), right, 't');
|
||||
const two = mergeExercisedMap(mergeExercisedMap(base, right, 't'), left, 't');
|
||||
expect(one).toEqual(two);
|
||||
expect(one.cases.a!.commands).toEqual(['bin/x', 'bin/y']);
|
||||
expect(one.cases.b!.commands).toEqual(['bin/z']);
|
||||
expect(one.sourceRuns).toEqual(['1', '2', '3']);
|
||||
expect(one.observedThrough).toBe('2026-10-03T00:00:00Z');
|
||||
expect(one.cases.a!.costUsd).toBe(4);
|
||||
});
|
||||
|
||||
test('empty or missing artifacts never erase consumers, and a run already merged is not counted twice', () => {
|
||||
expect(mergeExercisedMap(base, map({}, ['9']), 't').cases).toEqual(base.cases);
|
||||
expect(mergeExercisedMap(base, map({ a: { observations: 1, withCommands: 0, commands: [] } }, ['9']), 't').cases.a!.commands).toEqual(['bin/x']);
|
||||
expect(mergeExercisedMap(base, map({ a: { observations: 5, withCommands: 5, commands: ['bin/x'], costUsd: 9, costRuns: 1 } }, ['1']), 't').cases.a)
|
||||
.toEqual(base.cases.a!);
|
||||
const costed = mergeExercisedMap(base, map({ a: { observations: 1, withCommands: 1, commands: [], costUsd: 7, costRuns: 1 } }, ['4']), 't');
|
||||
expect(costed.cases.a).toMatchObject({ observations: 3, costUsd: 5, costRuns: 3 });
|
||||
expect(parseExercisedMap(formatExercisedMap(costed))).toEqual(costed);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shadow-only map data', () => {
|
||||
test('a map-only diff selects no paid case and says why', () => {
|
||||
const selection = selectPrProfile({ selectedE2E: [], selectedJudges: [], changedFiles: [EXERCISED_MAP_PATH] });
|
||||
expect(selection).toMatchObject({ mode: 'pr', e2e: [], judges: [], unknownFiles: [], derivedFiles: [], noConsumerFiles: [] });
|
||||
expect(selection.shadow!.e2e).toEqual([]);
|
||||
expect(selection.reasons).toContain(`${EXERCISED_MAP_PATH} is shadow-only data (it changes no selection yet), so it selects no paid case (docs/TESTING_INTERNALS.md#exercised-path-map)`);
|
||||
const plan = computePaidCaseSelection({ profile: 'pr', env: {}, changedFiles: [EXERCISED_MAP_PATH, 'package.json'], packageVersionOnly: true });
|
||||
expect(plan.selection.e2e).toEqual([]);
|
||||
expect(plan.selection.judges).toEqual([]);
|
||||
}, 60_000);
|
||||
});
|
||||
|
||||
describe('refresh contract: unavailable or partial input writes nothing', () => {
|
||||
const root = fixtureRepo(tree);
|
||||
const ex = exercisedConsumers(maps, root, { observed, stopAt: ['setup'] });
|
||||
const report = (files: Record<string, string>) => {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'exercised-refresh-'));
|
||||
for (const [file, text] of Object.entries(files)) { fs.mkdirSync(path.dirname(path.join(dir, file)), { recursive: true }); fs.writeFileSync(path.join(dir, file), text); }
|
||||
return dir;
|
||||
};
|
||||
const outcome = (id: string) => JSON.stringify({ case: id, execution: 'executed', cost_usd: 1 });
|
||||
const shard = { 'paid-slice-1-a1/shards/skill-e2e-beta/junit.xml': '<testsuite><testcase name="beta"/></testsuite>' };
|
||||
const code = (run: () => unknown) => { try { run(); return 0; } catch (error) { return error instanceof RefreshError ? error.exitCode : -1; } };
|
||||
|
||||
test('report directories: missing is unavailable; no shards, no trial outcomes or an executed case without a shard is incomplete', () => {
|
||||
expect(code(() => refreshFromReportDirs([path.join(os.tmpdir(), 'no-such-census-dir')], '1', observed, ex, 't', profileMaps))).toBe(REFRESH_EXIT.unavailable);
|
||||
expect(code(() => refreshFromReportDirs([report({ 'trial-outcomes.jsonl': outcome('beta') })], '1', observed, ex, 't', profileMaps))).toBe(REFRESH_EXIT.incomplete);
|
||||
expect(code(() => refreshFromReportDirs([report(shard)], '1', observed, ex, 't', profileMaps))).toBe(REFRESH_EXIT.incomplete);
|
||||
expect(() => refreshFromReportDirs([report({ ...shard, 'trial-outcomes.jsonl': `${outcome('beta')}\n${outcome('alpha')}` })], '1', observed, ex, 't', profileMaps))
|
||||
.toThrow('1 executed case(s) have no shard artifact: alpha');
|
||||
const { merged } = refreshFromReportDirs([report({ ...shard, 'trial-outcomes.jsonl': outcome('beta') })], '9', observed, ex, 't', profileMaps);
|
||||
expect(merged.sourceRuns).toEqual(['1', '9']);
|
||||
expect(merged.cases.beta!.observations).toBe(4);
|
||||
});
|
||||
|
||||
test('--from-run: a 403, a missing map or a malformed map leaves the target byte-identical; a complete artifact is unioned', () => {
|
||||
const target = path.join(fs.mkdtempSync(path.join(os.tmpdir(), 'exercised-target-')), 'exercised-commands.json');
|
||||
fs.writeFileSync(target, formatExercisedMap(observed));
|
||||
const before = fs.readFileSync(target, 'utf8');
|
||||
const artifact = (files: Record<string, string>): ArtifactDownload => (_runId, dir) => {
|
||||
for (const [file, text] of Object.entries(files)) { fs.mkdirSync(path.dirname(path.join(dir, file)), { recursive: true }); fs.writeFileSync(path.join(dir, file), text); }
|
||||
return { status: 0, stderr: '' };
|
||||
};
|
||||
let forbidden: unknown;
|
||||
try { refreshFromRun('42', target, () => ({ status: 1, stderr: 'HTTP 403: Resource not accessible by integration' })); } catch (error) { forbidden = error; }
|
||||
expect(forbidden).toBeInstanceOf(RefreshError);
|
||||
expect((forbidden as RefreshError).exitCode).toBe(REFRESH_EXIT.unavailable);
|
||||
expect((forbidden as Error).message).toContain('pass its directory with --from-dir');
|
||||
expect(code(() => refreshFromRun('42', target, artifact({ 'exercised-map-a1/report.md': 'x' })))).toBe(REFRESH_EXIT.incomplete);
|
||||
expect(code(() => refreshFromRun('42', target, artifact({ 'exercised-map-a1/exercised-commands.json': '{"schema":1,"cases":' })))).toBe(REFRESH_EXIT.incomplete);
|
||||
expect(code(() => refreshFromRun('42', target, artifact({ 'exercised-map-a1/exercised-commands.json': formatExercisedMap(map({}, ['5'])), 'exercised-map-a2/exercised-commands.json': '{}' })))).toBe(REFRESH_EXIT.incomplete);
|
||||
expect(code(() => refreshFromRun('not-a-run', target))).toBe(REFRESH_EXIT.unavailable);
|
||||
expect(fs.readFileSync(target, 'utf8')).toBe(before);
|
||||
const fresh = map({ beta: { observations: 1, withCommands: 1, commands: ['bin/gstack-new'] } }, ['5'], '2026-10-09T00:00:00Z');
|
||||
refreshFromRun('5', target, artifact({ 'exercised-map-a1/exercised-commands.json': formatExercisedMap(fresh) }));
|
||||
const after = parseExercisedMap(fs.readFileSync(target, 'utf8'));
|
||||
expect(after.cases.beta!.commands).toEqual(['bin/gstack-new', 'bin/gstack-observed']);
|
||||
expect(after.sourceRuns).toEqual(['1', '5']);
|
||||
});
|
||||
|
||||
test('the CLI exits 2 on usage and 3 on a missing report directory, writing nothing', () => {
|
||||
const out = path.join(fs.mkdtempSync(path.join(os.tmpdir(), 'exercised-cli-')), 'map.json');
|
||||
const cli = (args: string[]) => spawnSync('bun', ['run', path.join(ROOT, 'scripts/exercised-map.ts'), ...args], { cwd: ROOT, encoding: 'utf8', timeout: 60_000 });
|
||||
expect(cli([]).status).toBe(REFRESH_EXIT.usage);
|
||||
const missing = cli(['--from-dir', path.join(os.tmpdir(), 'no-such-census-dir'), '--run-id', '1', '--out', out]);
|
||||
expect(missing.status).toBe(REFRESH_EXIT.unavailable);
|
||||
expect(missing.stderr).toContain('nothing was written, the committed union is unchanged');
|
||||
expect(fs.existsSync(out)).toBe(false);
|
||||
}, 90_000);
|
||||
});
|
||||
|
||||
describe('recorded commands and MAP_GAP', () => {
|
||||
const root = fixtureRepo(tree);
|
||||
const ex = exercisedConsumers(maps, root, { observed, stopAt: ['setup'] });
|
||||
const report = fs.mkdtempSync(path.join(os.tmpdir(), 'exercised-report-'));
|
||||
const write = (file: string, text: string) => { fs.mkdirSync(path.dirname(path.join(report, file)), { recursive: true }); fs.writeFileSync(path.join(report, file), text); };
|
||||
write('paid-slice-1-a1/shards/skill-e2e-alpha--alpha.t1/result.json', JSON.stringify({ tests: [{ name: 'alpha', transcript: [{ type: 'tool_use', input: { command: 'gstack-start && $B goto x' } }] }] }));
|
||||
write('paid-slice-1-a1/shards/skill-e2e-beta/junit.xml', '<testsuite><testcase name="beta"/></testsuite>');
|
||||
write('paid-slice-1-a1/shards/skill-e2e-beta/session.jsonl', `${JSON.stringify({ type: 'tool_use', input: { command: 'bin/gstack-gapper --x' } })}\n`);
|
||||
write('paid-slice-1-a1/shards/skill-e2e-gamma/junit.xml', '<testsuite><testcase name="gamma"/></testsuite>');
|
||||
write('paid-slice-1-a1/trial-outcomes.jsonl', [{ case: 'alpha', execution: 'executed', cost_usd: 1.5 }, { case: 'alpha', execution: 'executed', cost_usd: 0, cost_known: false }, { case: 'beta', execution: 'reused', cost_usd: 3 }].map(record => JSON.stringify(record)).join('\n'));
|
||||
|
||||
test('commands are read per shard and attributed to their cases', () => {
|
||||
const commands = attributeCommands(readShardCommands(report), profileMaps);
|
||||
expect(commands.get('alpha')).toEqual(['gstack-start && $B goto x']);
|
||||
expect(commands.get('beta')).toEqual(['bin/gstack-gapper --x']);
|
||||
expect(commands.get('gamma')).toEqual([]);
|
||||
expect(observeRun(commands, ex, { runId: '7', observedAt: 't', costs: readCaseCosts(report) }).cases.alpha)
|
||||
.toEqual({ observations: 1, withCommands: 1, commands: ['bin/gstack-start', 'browse/dist/browse'], costUsd: 1.5, costRuns: 1 });
|
||||
});
|
||||
|
||||
test('a command outside the static-plus-observed closure is a MAP_GAP; a skill-running case with no commands is blind', () => {
|
||||
const commands = attributeCommands(readShardCommands(report), profileMaps);
|
||||
expect(mapGaps(commands, ex)).toEqual([{ id: 'beta', command: 'bin/gstack-gapper' }]);
|
||||
expect(blindCases(commands, ex)).toEqual(['gamma']);
|
||||
});
|
||||
|
||||
test('the paid report writes MAP_GAP lines without failing, and an unreadable checkout degrades to unavailable', () => {
|
||||
const live = fs.mkdtempSync(path.join(os.tmpdir(), 'exercised-live-'));
|
||||
const committed = parseExercisedMap(fs.readFileSync(path.join(ROOT, EXERCISED_MAP_PATH), 'utf8'));
|
||||
const ex = exercisedConsumers(PR_PROFILE_MAPS, ROOT, { observed: committed, stopAt: PR_FULL_GATE_FILES });
|
||||
const outside = fs.readdirSync(path.join(ROOT, 'bin')).map(name => `bin/${name}`).find(file => /^bin\/gstack-[a-z-]+$/.test(file) && !ex.closure('ship-docsync-store').has(file))!;
|
||||
fs.mkdirSync(path.join(live, 'paid-slice-2-a1/shards/skill-e2e-ship-docsync--ship-docsync-store.t1'), { recursive: true });
|
||||
fs.writeFileSync(path.join(live, 'paid-slice-2-a1/shards/skill-e2e-ship-docsync--ship-docsync-store.t1/r.json'),
|
||||
JSON.stringify({ tests: [{ name: 'ship-docsync-store', transcript: [{ type: 'tool_use', input: { command: `${path.basename(outside)} --help` } }] }] }));
|
||||
const line = `MAP_GAP ship-docsync-store ${outside}: non-blocking for this PR; the next census refresh widens the map (docs/TESTING_INTERNALS.md#exercised-path-map)`;
|
||||
expect(formatMapGap({ id: 'ship-docsync-store', command: outside })).toBe(line);
|
||||
expect(reportMapGaps(live, new Set(['ship-docsync-store']), ROOT)).toEqual([line]);
|
||||
expect(fs.readFileSync(path.join(live, 'map-gaps.txt'), 'utf8')).toBe(`${line}\n`);
|
||||
expect(reportMapGaps(live, new Set(['ship-docsync-store']), path.join(live, 'no-checkout'))).toEqual([]);
|
||||
expect(fs.readFileSync(path.join(live, 'map-gaps.txt'), 'utf8')).toStartWith('MAP_GAP unavailable:');
|
||||
}, 60_000);
|
||||
});
|
||||
|
||||
describe('parity with the measured prototype', () => {
|
||||
/** Files the shipped function reaches beyond the prototype, each with the reviewed edge class behind it. */
|
||||
const REVIEWED_SUPERSET: Record<string, string> = {
|
||||
setup: './setup, $ROOT/setup and join(..., "setup") exec edges (plan A2-2); setup is a full-gate file, so the closure stops there',
|
||||
};
|
||||
|
||||
test('the shipped map equals or is a reviewed superset of the prototype map on this checkout', () => {
|
||||
const committed = parseExercisedMap(fs.readFileSync(path.join(ROOT, EXERCISED_MAP_PATH), 'utf8'));
|
||||
const prototype = prototypeConsumers(PR_PROFILE_MAPS, ROOT, committed, PR_FULL_GATE_FILES);
|
||||
const shipped = exercisedConsumers(PR_PROFILE_MAPS, ROOT, { observed: committed, stopAt: PR_FULL_GATE_FILES });
|
||||
const missing = [...prototype].flatMap(([file, ids]) => [...ids].filter(id => !shipped.e2e.get(file)?.has(id)).map(id => `${file} ${id}`));
|
||||
expect(missing).toEqual([]);
|
||||
const unreviewed = [...new Set([...shipped.e2e].filter(([file, ids]) => [...ids].some(id => !prototype.get(file)?.has(id))).map(([file]) => file))]
|
||||
.filter(file => !Object.hasOwn(REVIEWED_SUPERSET, file));
|
||||
expect(unreviewed.map(file => `${file}: reached beyond the prototype; review the edge class and add it to REVIEWED_SUPERSET with its reason`)).toEqual([]);
|
||||
}, 60_000);
|
||||
});
|
||||
|
||||
describe('replay of the recorded red PR runs', () => {
|
||||
test('every recorded failed gate case stays in the shadow selection (the PR receipt: bun run test:exercised-map --replay)', () => {
|
||||
const fixture = JSON.parse(fs.readFileSync(path.join(ROOT, REPLAY_FIXTURE), 'utf8')) as { failedGateCases: number; runs: ReplayRun[] };
|
||||
expect(fixture.runs.reduce((sum, run) => sum + run.failedGateCases.length, 0)).toBe(fixture.failedGateCases);
|
||||
const rows = replayShadow(fixture.runs);
|
||||
expect(rows.flatMap(row => row.misses.map(id => `${row.runId}:${id}`))).toEqual([]);
|
||||
expect(formatShadowReplay(rows).at(-1)).toBe('- MISSES (failed, not in the shadow selection): 0');
|
||||
}, 120_000);
|
||||
|
||||
test('a red the shadow drops is reported as a miss', () => {
|
||||
const [row] = replayShadow([{ runId: 1, pr: 1, packageVersionOnly: true, failedGateCases: ['plan-mode-no-op'], changedFiles: ['docs/designs/x.md'] }]);
|
||||
expect(row!.misses).toEqual(['plan-mode-no-op']);
|
||||
expect(formatShadowReplay([row!]).slice(-2)).toEqual(['- MISSES (failed, not in the shadow selection): 1', ' - 1 #1 plan-mode-no-op']);
|
||||
});
|
||||
});
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"source": "evals.yml pull_request runs 2026-10-07..2026-10-17 (225 runs): every run with an executed failed gate trial, deduplicated per (run, case); changed files are the three-dot compare of the merge-base with the run head",
|
||||
"failedGateCases": 47,
|
||||
"runs": [
|
||||
{"runId":37560420246,"pr":3059,"headSha":"d6250a058af971dd697036acd6e05f7740e8e210","packageVersionOnly":true,"failedGateCases":["plan-mode-no-op"],"changedFiles":[".github/actionlint.yaml",".github/workflows/eval-sweep.yml","CHANGELOG.md","CONTRIBUTING.md","VERSION","agents-digest/gstack-AGENTS.md","bin/gstack-config","docs/TESTING_INTERNALS.md","package.json","scripts/eval-flake-rank.ts","scripts/harness-version.json","scripts/lib/measure-bar.ts","scripts/ship-measure-sweep.ts","scripts/ship-measure.ts","scripts/test-pr-profile.ts","ship/sections/measure.md","ship/sections/measure.md.tmpl","test/ci-image-tag-binding.test.ts","test/eval-sweep-workflow.test.ts","test/fixtures/module-size-ratchet.json","test/helpers/carve-guards.ts","test/helpers/touchfiles-data.ts","test/ship-measure-bar.test.ts","test/ship-measure-loop-skill.test.ts","test/ship-measure-seeded-fixture.test.ts","test/ship-measure-sweep.test.ts","test/ship-measure.test.ts"]},
|
||||
{"runId":37564096977,"pr":3059,"headSha":"36c0cf1579a2f823783c2ecee5c509e872b0c20a","packageVersionOnly":true,"failedGateCases":["qa-functional-cli-report"],"changedFiles":[".github/actionlint.yaml",".github/workflows/eval-sweep.yml","CHANGELOG.md","CONTRIBUTING.md","VERSION","agents-digest/gstack-AGENTS.md","bin/gstack-config","docs/TESTING_INTERNALS.md","package.json","scripts/eval-flake-rank.ts","scripts/harness-version.json","scripts/lib/measure-bar.ts","scripts/ship-measure-sweep.ts","scripts/ship-measure.ts","scripts/test-pr-profile.ts","ship/sections/measure.md","ship/sections/measure.md.tmpl","test/ci-image-tag-binding.test.ts","test/eval-sweep-workflow.test.ts","test/fixtures/module-size-ratchet.json","test/helpers/carve-guards.ts","test/helpers/touchfiles-data.ts","test/ship-measure-bar.test.ts","test/ship-measure-loop-skill.test.ts","test/ship-measure-seeded-fixture.test.ts","test/ship-measure-sweep.test.ts","test/ship-measure.test.ts","test/skill-e2e-plan-mode-no-op.test.ts"]},
|
||||
{"runId":37691665506,"pr":3069,"headSha":"068a3099baf660e995c693b5625b4b3e4546b7a8","packageVersionOnly":true,"failedGateCases":["shared-libs-read-only"],"changedFiles":[".github/ISSUE_TEMPLATE/bug_report.md",".github/docker/Dockerfile.ci",".github/workflows/evals-periodic.yml",".github/workflows/free-tests.yml",".github/workflows/measure-journal-read.yml","CHANGELOG.md","README.md","SKILL.md","TODOS.md","VERSION","agents-digest/gstack-AGENTS.md","autoplan/SKILL.md","autoplan/bin/guard-journal.ts","autoplan/bin/guard-log.ts","autoplan/bin/guard-reasons.ts","autoplan/bin/phase-publication-hook.ts","autoplan/sections/ceo-phase.md","autoplan/sections/ceo-phase.md.tmpl","autoplan/sections/design-phase.md","autoplan/sections/design-phase.md.tmpl","autoplan/sections/dx-phase.md","autoplan/sections/dx-phase.md.tmpl","autoplan/sections/eng-phase.md","autoplan/sections/eng-phase.md.tmpl","autoplan/sections/phase-close.md","autoplan/sections/phase-close.md.tmpl","benchmark-models/SKILL.md","benchmark/SKILL.md","bin/gstack-artifacts-init","bin/gstack-brain-lock.sh","bin/gstack-brain-restore","bin/gstack-brain-sync","bin/gstack-codex-probe","bin/gstack-codex-status.sh","bin/gstack-config","bin/gstack-doctor","bin/gstack-gbrain-source-wireup","bin/gstack-greptile-early","bin/gstack-post","bin/gstack-pr-title-rewrite.sh","bin/gstack-question-preference","bin/gstack-redact-prepush","bin/gstack-skill-start","bin/gstack-slug","browse/SKILL.md","browse/test/extension-sender-auth.test.ts","canary/SKILL.md","codex/SKILL.md","codex/SKILL.md.tmpl","codex/sections/challenge-mode.md","codex/sections/challenge-mode.md.tmpl","codex/sections/consult-mode.md","codex/sections/consult-mode.md.tmpl","codex/sections/review-mode.md","codex/sections/review-mode.md.tmpl","context-restore/SKILL.md","context-restore/SKILL.md.tmpl","context-save/SKILL.md","context-save/SKILL.md.tmpl","design-consultation/SKILL.md","design-consultation/sections/proposal-and-preview.md","design-html/SKILL.md","design-review/SKILL.md","design-shotgun/SKILL.md","devex-review/SKILL.md","diagram/SKILL.md","docs/autoplan-guard-troubleshooting.md","docs/designs/FOLLOWUP_WAVE_2026_10_07.md","docs/gbrain-sync-errors.md","docs/gbrain-sync.md","docs/gbrain-write-surfaces.md","docs/troubleshooting.md","document-generate/SKILL.md","document-release/SKILL.md","document-release/sections/release-body.md","health/SKILL.md","investigate/SKILL.md","ios-clean/SKILL.md","ios-design-review/SKILL.md","ios-fix/SKILL.md","ios-qa/SKILL.md","ios-sync/SKILL.md","land-and-deploy/SKILL.md","landing-report/SKILL.md","learn/SKILL.md","lib/claude-journal-records.ts","lib/claude-owned-journal.ts","lib/claude-public-transcript.ts","lib/greptile-early.ts","lib/gstack-post.ts","lib/outside-review-result.ts","make-pdf/SKILL.md","office-hours/SKILL.md","office-hours/sections/design-and-handoff.md","open-gstack-browser/SKILL.md","package.json","pair-agent/SKILL.md","plan-ceo-review/SKILL.md","plan-ceo-review/sections/review-sections.md","plan-design-review/SKILL.md","plan-devex-review/SKILL.md","plan-devex-review/sections/review-sections.md","plan-eng-review/SKILL.md","plan-eng-review/sections/review-sections.md","plan-tune/SKILL.md","plan-tune/SKILL.md.tmpl","qa-only/SKILL.md","qa/SKILL.md","qa/sections/browser-setup.md","retro/SKILL.md","review/SKILL.md","review/greptile-triage.md","review/sections/adversarial.md","review/sections/review-army.md","scrape/SKILL.md","scripts/harness-version.json","scripts/lib/windows-curation.ts","scripts/measure-journal-read.ts","scripts/resolvers/aside.ts","scripts/resolvers/constants.ts","scripts/resolvers/design.ts","scripts/resolvers/gbrain.ts","scripts/resolvers/index.ts","scripts/resolvers/outside-voice-steps.ts","scripts/resolvers/outside-voice.ts","scripts/resolvers/preamble/generate-brain-sync-block.ts","scripts/resolvers/question-tuning.ts","scripts/resolvers/redact-doc.ts","scripts/resolvers/review-army.ts","scripts/resolvers/spec-review.ts","scripts/test-pr-profile.ts","scripts/typecheck-test-baseline.json","setup","setup-browser-cookies/SKILL.md","setup-deploy/SKILL.md","setup-gbrain/SKILL.md","ship/SKILL.md","ship/SKILL.md.tmpl","ship/sections/adversarial.md","ship/sections/documentation.md","ship/sections/greptile-early.md","ship/sections/greptile-early.md.tmpl","ship/sections/greptile.md","ship/sections/greptile.md.tmpl","ship/sections/manifest.json","ship/sections/pr-body.md","ship/sections/pr-body.md.tmpl","ship/sections/review-army.md","skillify/SKILL.md","spec/SKILL.md","spec/sections/gate-and-file.md","spec/sections/gate-and-file.md.tmpl","sync-gbrain/SKILL.md","test-audit/SKILL.md","test/aside-driver.test.ts","test/autoplan-bounded-journal.test.ts","test/autoplan-dual-voice-evidence.test.ts","test/autoplan-guard-log.test.ts","test/autoplan-guard-reasons.test.ts","test/autoplan-long-session-observer.test.ts","test/autoplan-publication-guard.test.ts","test/autoplan-publication-hook.test.ts","test/autoplan-publication-payload.test.ts","test/auLine truncated
|
||||
{"runId":37694473528,"pr":3069,"headSha":"c2d1aa1976a1403a0a6f7846a748080f61c8c726","packageVersionOnly":true,"failedGateCases":["qa-quick","shared-libs-read-only","shared-libs-unsupported-git"],"changedFiles":[".github/ISSUE_TEMPLATE/bug_report.md",".github/docker/Dockerfile.ci",".github/workflows/evals-periodic.yml",".github/workflows/free-tests.yml",".github/workflows/measure-journal-read.yml","CHANGELOG.md","README.md","SKILL.md","TODOS.md","VERSION","agents-digest/gstack-AGENTS.md","autoplan/SKILL.md","autoplan/bin/guard-journal.ts","autoplan/bin/guard-log.ts","autoplan/bin/guard-reasons.ts","autoplan/bin/phase-publication-hook.ts","autoplan/sections/ceo-phase.md","autoplan/sections/ceo-phase.md.tmpl","autoplan/sections/design-phase.md","autoplan/sections/design-phase.md.tmpl","autoplan/sections/dx-phase.md","autoplan/sections/dx-phase.md.tmpl","autoplan/sections/eng-phase.md","autoplan/sections/eng-phase.md.tmpl","autoplan/sections/phase-close.md","autoplan/sections/phase-close.md.tmpl","benchmark-models/SKILL.md","benchmark/SKILL.md","bin/gstack-artifacts-init","bin/gstack-brain-lock.sh","bin/gstack-brain-restore","bin/gstack-brain-sync","bin/gstack-codex-probe","bin/gstack-codex-status.sh","bin/gstack-config","bin/gstack-doctor","bin/gstack-gbrain-source-wireup","bin/gstack-greptile-early","bin/gstack-post","bin/gstack-pr-title-rewrite.sh","bin/gstack-question-preference","bin/gstack-redact-prepush","bin/gstack-skill-start","bin/gstack-slug","browse/SKILL.md","browse/test/extension-sender-auth.test.ts","canary/SKILL.md","codex/SKILL.md","codex/SKILL.md.tmpl","codex/sections/challenge-mode.md","codex/sections/challenge-mode.md.tmpl","codex/sections/consult-mode.md","codex/sections/consult-mode.md.tmpl","codex/sections/review-mode.md","codex/sections/review-mode.md.tmpl","context-restore/SKILL.md","context-restore/SKILL.md.tmpl","context-save/SKILL.md","context-save/SKILL.md.tmpl","design-consultation/SKILL.md","design-consultation/sections/proposal-and-preview.md","design-html/SKILL.md","design-review/SKILL.md","design-shotgun/SKILL.md","devex-review/SKILL.md","diagram/SKILL.md","docs/autoplan-guard-troubleshooting.md","docs/designs/FOLLOWUP_WAVE_2026_10_07.md","docs/gbrain-sync-errors.md","docs/gbrain-sync.md","docs/gbrain-write-surfaces.md","docs/troubleshooting.md","document-generate/SKILL.md","document-release/SKILL.md","document-release/sections/release-body.md","health/SKILL.md","investigate/SKILL.md","ios-clean/SKILL.md","ios-design-review/SKILL.md","ios-fix/SKILL.md","ios-qa/SKILL.md","ios-sync/SKILL.md","land-and-deploy/SKILL.md","landing-report/SKILL.md","learn/SKILL.md","lib/claude-journal-records.ts","lib/claude-owned-journal.ts","lib/claude-public-transcript.ts","lib/greptile-early.ts","lib/gstack-post.ts","lib/outside-review-result.ts","make-pdf/SKILL.md","office-hours/SKILL.md","office-hours/sections/design-and-handoff.md","open-gstack-browser/SKILL.md","package.json","pair-agent/SKILL.md","plan-ceo-review/SKILL.md","plan-ceo-review/sections/review-sections.md","plan-design-review/SKILL.md","plan-devex-review/SKILL.md","plan-devex-review/sections/review-sections.md","plan-eng-review/SKILL.md","plan-eng-review/sections/review-sections.md","plan-tune/SKILL.md","plan-tune/SKILL.md.tmpl","qa-only/SKILL.md","qa/SKILL.md","qa/sections/browser-setup.md","retro/SKILL.md","review/SKILL.md","review/greptile-triage.md","review/sections/adversarial.md","review/sections/review-army.md","scrape/SKILL.md","scripts/harness-version.json","scripts/lib/windows-curation.ts","scripts/measure-journal-read.ts","scripts/resolvers/aside.ts","scripts/resolvers/constants.ts","scripts/resolvers/design.ts","scripts/resolvers/gbrain.ts","scripts/resolvers/index.ts","scripts/resolvers/outside-voice-steps.ts","scripts/resolvers/outside-voice.ts","scripts/resolvers/preamble/generate-brain-sync-block.ts","scripts/resolvers/question-tuning.ts","scripts/resolvers/redact-doc.ts","scripts/resolvers/review-army.ts","scripts/resolvers/spec-review.ts","scripts/test-pr-profile.ts","scripts/typecheck-test-baseline.json","setup","setup-browser-cookies/SKILL.md","setup-deploy/SKILL.md","setup-gbrain/SKILL.md","ship/SKILL.md","ship/SKILL.md.tmpl","ship/sections/adversarial.md","ship/sections/documentation.md","ship/sections/greptile-early.md","ship/sections/greptile-early.md.tmpl","ship/sections/greptile.md","ship/sections/greptile.md.tmpl","ship/sections/manifest.json","ship/sections/pr-body.md","ship/sections/pr-body.md.tmpl","ship/sections/review-army.md","skillify/SKILL.md","spec/SKILL.md","spec/sections/gate-and-file.md","spec/sections/gate-and-file.md.tmpl","sync-gbrain/SKILL.md","test-audit/SKILL.md","test/aside-driver.test.ts","test/autoplan-bounded-journal.test.ts","test/autoplan-dual-voice-evidence.test.ts","test/autoplan-guard-log.test.ts","test/autoplan-guard-reasons.test.ts","test/autoplan-long-session-observer.test.ts","test/autoplan-publication-guard.test.ts","test/autoplan-publication-hook.test.ts","test/autopLine truncated
|
||||
{"runId":37731666423,"pr":3073,"headSha":"872e1542e42d40b3a95356d5284c6e4a3553c31f","packageVersionOnly":true,"failedGateCases":["plan-ceo-finding-floor","ship-docsync-missing-asset"],"changedFiles":[".github/workflows/model-policy-freshness.yml","CHANGELOG.md","CONTRIBUTING.md","README.md","VERSION","agents-digest/gstack-AGENTS.md","autoplan/SKILL.md","autoplan/SKILL.md.tmpl","autoplan/sections/ceo-phase.md","autoplan/sections/design-phase.md","autoplan/sections/dx-phase.md","autoplan/sections/eng-phase.md","bin/gstack-codex-probe","bin/gstack-config","bin/gstack-models","claude-code/SKILL.md.tmpl","codex/SKILL.md","codex/SKILL.md.tmpl","codex/sections/challenge-mode.md","codex/sections/challenge-mode.md.tmpl","codex/sections/consult-mode.md","codex/sections/consult-mode.md.tmpl","codex/sections/review-mode.md","codex/sections/review-mode.md.tmpl","docs/model-policy.md","docs/skills.md","docs/troubleshooting.md","lib/claude-code-migration.ts","lib/claude-code.ts","lib/model-catalog.ts","lib/model-policy-cli.ts","lib/model-policy-freshness-github.ts","lib/model-policy-freshness-parser-worker.ts","lib/model-policy-freshness-publication.ts","lib/model-policy-freshness-sources.ts","lib/model-policy-freshness.ts","lib/model-policy-notice.ts","lib/model-policy.ts","package.json","plan-ceo-review/sections/review-sections.md","plan-design-review/SKILL.md","plan-devex-review/sections/review-sections.md","plan-eng-review/sections/review-sections.md","plan-eng-review/sections/review-sections.md.tmpl","review/SKILL.md","scripts/harness-version.json","scripts/model-policy-freshness.ts","scripts/preflight-codex-overlap.ts","scripts/resolve-codex-generation-model.ts","scripts/resolvers/constants.ts","scripts/resolvers/design.ts","scripts/resolvers/index.ts","scripts/resolvers/outside-voice-steps.ts","scripts/resolvers/outside-voice.ts","scripts/resolvers/plan-review.ts","scripts/resolvers/qa.ts","scripts/test-pr-profile.ts","ship/sections/review-army.md","spec/SKILL.md","spec/SKILL.md.tmpl","spec/sections/gate-and-file.md","spec/sections/gate-and-file.md.tmpl","test/claude-code-migration.test.ts","test/claude-code-skill.test.ts","test/codex-hardening.test.ts","test/codex-probe-cache.test.ts","test/codex-under-codex-detection.test.ts","test/fixtures/model-policy-freshness.ts","test/fixtures/model-policy-freshness/anthropic-lifecycle.md","test/fixtures/model-policy-freshness/anthropic-models.md","test/fixtures/model-policy-freshness/openai-lifecycle.md","test/fixtures/model-policy-freshness/openai-models.md","test/fixtures/qa-caller-read-probe-mtb1007a.json","test/helpers/free-fixtures-data.ts","test/helpers/pty/launch.ts","test/helpers/qa-callers-fixture.ts","test/model-catalog-isolation.test.ts","test/model-policy-cli.test.ts","test/model-policy-freshness.test.ts","test/model-policy-workflow.test.ts","test/model-policy.test.ts","test/model-role-invocation.test.ts","test/outside-voice-invocation.test.ts","test/outside-voice-preflight.test.ts","test/plan-review-cases.test.ts","test/pty-output-wake.test.ts","test/qa-exploratory-callers.test.ts","test/qa-probe-gates.test.ts","test/run-in-background-guidance.test.ts","test/setup-claude-code-migration.test.ts","test/team-mode.test.ts"]},
|
||||
{"runId":37739845694,"pr":3077,"headSha":"e2e725ad3ddefac67b57f91c2a000848de56b752","packageVersionOnly":true,"failedGateCases":["ship-docsync-missing-asset"],"changedFiles":["CHANGELOG.md","TODOS.md","VERSION","agents-digest/gstack-AGENTS.md","careful/SKILL.md","careful/SKILL.md.tmpl","careful/bin/check-careful.sh","careful/bin/hook-extract.sh","docs/TESTING_INTERNALS.md","docs/skills.md","freeze/SKILL.md","freeze/SKILL.md.tmpl","freeze/bin/check-freeze.sh","guard/SKILL.md","guard/SKILL.md.tmpl","investigate/SKILL.md","investigate/SKILL.md.tmpl","package.json","scripts/harness-version.json","scripts/lib/windows-curation.ts","scripts/test-pr-profile.ts","test/fixtures/context-budget.json","test/hook-scripts.test.ts"]},
|
||||
{"runId":37743622252,"pr":3079,"headSha":"4637fae03baad83603ab7d554f4137c4702b4bd4","packageVersionOnly":true,"failedGateCases":["qa-quick"],"changedFiles":[".github/workflows/free-tests.yml",".github/workflows/make-pdf-gate.yml",".github/workflows/windows-setup-e2e.yml",".gitignore","CHANGELOG.md","README.md","TODOS.md","VERSION","agents-digest/gstack-AGENTS.md","bin/gstack-doctor","bin/gstack-global-discover.ts","bin/gstack-launch-probe.sh","browse/src/cli.ts","browse/src/find-browse.ts","browse/test/sidebar-ux.test.ts","docs/troubleshooting.md","extension/sidepanel-terminal.js","extension/sidepanel.css","make-pdf/src/cli.ts","package.json","scripts/build-cso.sh","scripts/build.sh","setup","test/binary-version-probe.test.ts","test/build-cso-nonfatal.test.ts","test/build-cso-result-record.test.ts","test/cso-windows-launcher.test.ts","test/gstack-doctor.test.ts","test/gstack-launch-probe.test.ts","test/setup-cso-degrade.test.ts","test/setup-cso-windows-probe.test.ts","test/setup-windows-launch-hint.test.ts"]},
|
||||
{"runId":37762901988,"pr":3079,"headSha":"b29f02250967df02f0e02dc4c8310155771cdf41","packageVersionOnly":true,"failedGateCases":["ship-exploratory-unavailable"],"changedFiles":[".github/workflows/free-tests.yml",".github/workflows/make-pdf-gate.yml",".github/workflows/windows-setup-e2e.yml",".gitignore","CHANGELOG.md","README.md","TODOS.md","VERSION","agents-digest/gstack-AGENTS.md","bin/gstack-doctor","bin/gstack-global-discover.ts","bin/gstack-launch-probe.sh","browse/src/cli.ts","browse/src/find-browse.ts","browse/test/sidebar-ux.test.ts","docs/troubleshooting.md","extension/sidepanel-terminal.js","extension/sidepanel.css","make-pdf/src/cli.ts","package.json","scripts/build-cso.sh","scripts/build.sh","setup","test/binary-version-probe.test.ts","test/build-cso-nonfatal.test.ts","test/build-cso-result-record.test.ts","test/cso-windows-launcher.test.ts","test/gstack-doctor.test.ts","test/gstack-launch-probe.test.ts","test/setup-cso-degrade.test.ts","test/setup-cso-windows-probe.test.ts","test/setup-windows-launch-hint.test.ts"]},
|
||||
{"runId":38087752336,"pr":3114,"headSha":"3e51fb06ba5c9c8943e7211ba32fb93fcccfe402","packageVersionOnly":false,"failedGateCases":["qa-functional-cli-report"],"changedFiles":["AGENTS.md","ETHOS.md","README.md","SKILL.md","autoplan/SKILL.md","benchmark-models/SKILL.md","benchmark/SKILL.md","bin/gstack-evidence","bin/gstack-gate-diff","bin/gstack-review-log","browse/SKILL.md","canary/SKILL.md","codex/SKILL.md","context-restore/SKILL.md","context-save/SKILL.md","design-consultation/SKILL.md","design-html/SKILL.md","design-review/SKILL.md","design-shotgun/SKILL.md","devex-review/SKILL.md","diagram/SKILL.md","docs/designs/HONEST_WORK_GATE_INTEGRITY.md","docs/designs/gate-diff-calibration.md","document-generate/SKILL.md","document-release/SKILL.md","health/SKILL.md","investigate/SKILL.md","ios-clean/SKILL.md","ios-design-review/SKILL.md","ios-fix/SKILL.md","ios-qa/SKILL.md","ios-sync/SKILL.md","land-and-deploy/SKILL.md","landing-report/SKILL.md","learn/SKILL.md","lib/gate-diff/classify.ts","lib/gate-diff/git.ts","lib/gate-diff/index.ts","lib/gate-diff/render.ts","lib/gate-diff/tags.ts","lib/gate-diff/types.ts","lib/review-evidence.ts","make-pdf/SKILL.md","office-hours/SKILL.md","open-gstack-browser/SKILL.md","pair-agent/SKILL.md","plan-ceo-review/SKILL.md","plan-ceo-review/sections/review-sections.md","plan-ceo-review/sections/review-sections.md.tmpl","plan-design-review/SKILL.md","plan-devex-review/SKILL.md","plan-eng-review/SKILL.md","plan-eng-review/sections/review-sections.md","plan-tune/SKILL.md","qa-only/SKILL.md","qa/SKILL.md","retro/SKILL.md","review/SKILL.md","review/SKILL.md.tmpl","review/checklist.md","review/gate-integrity.md","review/specialists/testing.md","scrape/SKILL.md","scripts/gate-diff-calibrate.ts","scripts/harness-version.json","scripts/question-registry.ts","scripts/resolvers/dispatch-rules.ts","scripts/resolvers/gate-scan.ts","scripts/resolvers/index.ts","scripts/resolvers/plan-gates.ts","scripts/resolvers/preamble/generate-completion-status.ts","scripts/resolvers/preamble/generate-evidence-directive.ts","scripts/resolvers/test-value.ts","scripts/resolvers/testing.ts","scripts/test-pr-profile.ts","setup-browser-cookies/SKILL.md","setup-deploy/SKILL.md","setup-gbrain/SKILL.md","ship/SKILL.md","ship/SKILL.md.tmpl","ship/sections/plan-completion.md","ship/sections/plan-completion.md.tmpl","ship/sections/pr-body.md","ship/sections/pr-body.md.tmpl","ship/sections/review-army.md","ship/sections/review-army.md.tmpl","ship/sections/test-coverage.md","ship/sections/test-coverage.md.tmpl","ship/sections/tests.md","ship/sections/tests.md.tmpl","skillify/SKILL.md","spec/SKILL.md","spec/SKILL.md.tmpl","spec/sections/gate-and-file.md","spec/sections/gate-and-file.md.tmpl","sync-gbrain/SKILL.md","test-audit/SKILL.md","test/dispatch-rules.test.ts","test/eng-finding-retry-budget.test.ts","test/env-host-runtime-assets.test.ts","test/evidence.test.ts","test/fixtures/context-budget.json","test/fixtures/gate-diff/adv-forged-measured.base.patch","test/fixtures/gate-diff/adv-forged-measured.patch","test/fixtures/gate-diff/adv-golden-beside-unrelated.base.patch","test/fixtures/gate-diff/adv-golden-beside-unrelated.patch","test/fixtures/gate-diff/adv-kotlin-ignore.base.patch","test/fixtures/gate-diff/adv-kotlin-ignore.patch","test/fixtures/gate-diff/control-added-test.base.patch","test/fixtures/gate-diff/control-added-test.patch","test/fixtures/gate-diff/control-rename.base.patch","test/fixtures/gate-diff/control-rename.patch","test/fixtures/gate-diff/control-snapshot-with-owner.base.patch","test/fixtures/gate-diff/control-snapshot-with-owner.patch","test/fixtures/gate-diff/control-spec-skill-dir.base.patch","test/fixtures/gate-diff/control-spec-skill-dir.patch","test/fixtures/gate-diff/control-test-deleted-with-source.base.patch","test/fixtures/gate-diff/control-test-deleted-with-source.patch","test/fixtures/gate-diff/package-json-scripts.base.patch","test/fixtures/gate-diff/package-json-scripts.patch","test/fixtures/gate-diff/rh1-removed.base.patch","test/fixtures/gate-diff/rh1-removed.patch","test/fixtures/gate-diff/rh1-skip.base.patch","test/fixtures/gate-diff/rh1-skip.patch","test/fixtures/gate-diff/rh12-env.base.patch","test/fixtures/gate-diff/rh12-env.patch","test/fixtures/gate-diff/rh13-pragma.base.patch","test/fixtures/gate-diff/rh13-pragma.patch","test/fixtures/gate-diff/rh14-bypass.base.patch","test/fixtures/gate-diff/rh14-bypass.patch","test/fixtures/gate-diff/rh15-bound.base.patch","test/fixtures/gate-diff/rh15-bound.patch","test/fixtures/gate-diff/rh15-timeout.base.patch","test/fixtures/gate-diff/rh15-timeout.patch","test/fixtures/gate-diff/rh16-swallow.base.patch","test/fixtures/gate-diff/rh16-swallow.patch","test/fixtures/gate-diff/rh3-golden.base.patch","test/fixtures/gate-diff/rh3-golden.patch","test/fixtures/gate-diff/rh3-snapshot-no-owner.base.patch","test/fixtures/gate-diff/rh3-snapshot-no-owner.patch","test/fixtures/gate-diff/rh4-placeholder.base.patch","test/fixtures/gate-diff/rh4-placeLine truncated
|
||||
{"runId":38095294863,"pr":3116,"headSha":"82828943447b168adbbdc173c2095fcf33ba6f53","packageVersionOnly":true,"failedGateCases":["ship-exploratory-plan-checks"],"changedFiles":["CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","benchmark/SKILL.md","bin/gstack-browser-ensure","bin/gstack-bun-version.sh","bin/gstack-capy-install","bin/gstack-doctor","bin/gstack-doctor-check.sh","bin/gstack-doctor-components.sh","bin/gstack-runtime-pins.ts","browse/SKILL.md","canary/SKILL.md","design-consultation/SKILL.md","design-review/SKILL.md","devex-review/SKILL.md","docs/capy-install.md","docs/state-root.md","docs/troubleshooting.md","land-and-deploy/SKILL.md","lib/doctor-components.ts","lib/result-codes.ts","lib/runtime-pins.ts","open-gstack-browser/SKILL.md","package.json","pair-agent/SKILL.md","qa/sections/browser-setup.md","scrape/SKILL.md","scripts/gen-doctor-components.ts","scripts/gen-skill-docs.ts","scripts/resolvers/browse.ts","scripts/typecheck-test-baseline.json","setup","setup-browser-cookies/SKILL.md","test/bun-version-drift.test.ts","test/doctor-components.test.ts","test/egress-receipt-wiring.test.ts","test/fixtures/module-size-ratchet.json","test/gen-skill-docs-checks.test.ts","test/gen-skill-docs-prune-stale.test.ts","test/gstack-browser-ensure.test.ts","test/gstack-capy-install.test.ts","test/gstack-doctor.test.ts","test/helpers/manual-judge-review-fixture.ts","test/host-conformance.test.ts","test/runtime-pins.test.ts","test/troubleshooting-anchors.test.ts"]},
|
||||
{"runId":38097941308,"pr":3117,"headSha":"d0febdf79b1608f3de47f3c1ec099f7829f709f5","packageVersionOnly":true,"failedGateCases":["qa-functional-cli-report"],"changedFiles":["CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","autoplan/SKILL.md","autoplan/SKILL.md.tmpl","autoplan/sections/manifest.json","autoplan/sections/unattended.md","autoplan/sections/unattended.md.tmpl","bin/gstack-autoplan","bin/gstack-codex-login","bin/gstack-doctor-components.sh","bin/gstack-office-hours-review","bin/gstack-outside-voice","docs/troubleshooting.md","docs/unattended.md","lib/autoplan-export.ts","lib/autoplan-gate.ts","lib/autoplan-prompts.ts","lib/autoplan-reconcile.ts","lib/autoplan-run.ts","lib/autoplan-state.ts","lib/headless-artifacts.ts","lib/office-hours-review.ts","lib/outside-voice-api.ts","lib/outside-voice-runner.ts","lib/result-codes.ts","lib/spec-review-cap.ts","lib/spend-ledger.ts","office-hours/sections/design-and-handoff.md","package.json","plan-ceo-review/SKILL.md","plan-ceo-review/sections/checklist.md","plan-ceo-review/sections/checklist.md.tmpl","plan-ceo-review/sections/manifest.json","plan-design-review/sections/checklist.md","plan-design-review/sections/checklist.md.tmpl","plan-design-review/sections/manifest.json","plan-devex-review/sections/checklist.md","plan-devex-review/sections/checklist.md.tmpl","plan-devex-review/sections/manifest.json","plan-eng-review/sections/checklist.md","plan-eng-review/sections/checklist.md.tmpl","plan-eng-review/sections/manifest.json","scripts/resolvers/sections.ts","scripts/resolvers/spec-review.ts","test/autoplan-answer-invalidation.test.ts","test/autoplan-run-concurrency.test.ts","test/autoplan-run-recovery.test.ts","test/egress-receipt-wiring.test.ts","test/fixtures/module-size-ratchet.json","test/fixtures/multi-agent-wave/fixture-reviewer.ts","test/helpers/autoplan-run-fixture.ts","test/helpers/free-fixtures-data.ts","test/helpers/office-hours-completion.ts","test/helpers/workflow-judge-input.ts","test/office-hours-completion.test.ts","test/office-hours-review.test.ts","test/outside-runner-contract.test.ts","test/review-checklists.test.ts","test/spend-ledger.test.ts","test/workflow-judge-input.test.ts"]},
|
||||
{"runId":38101502677,"pr":3119,"headSha":"c9a1b4c273a2479dd62d10ba1477d0fe5c6c5824","packageVersionOnly":true,"failedGateCases":["land-and-deploy-review-gate","qa-functional-cli-fix"],"changedFiles":["CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","autoplan/SKILL.md","autoplan/SKILL.md.tmpl","autoplan/sections/ceo-phase.md","autoplan/sections/ceo-phase.md.tmpl","autoplan/sections/eng-phase.md","autoplan/sections/eng-phase.md.tmpl","benchmark/SKILL.md","benchmark/SKILL.md.tmpl","bin/gstack-doctor-components.sh","bin/gstack-plan-reality","cso/SKILL.md","cso/SKILL.md.tmpl","docs/troubleshooting.md","investigate/SKILL.md","investigate/SKILL.md.tmpl","investigate/sections/backlog.md","investigate/sections/backlog.md.tmpl","investigate/sections/eval-bisect.md","investigate/sections/eval-bisect.md.tmpl","investigate/sections/flake.md","investigate/sections/flake.md.tmpl","investigate/sections/manifest.json","investigate/sections/polluter.md","investigate/sections/polluter.md.tmpl","investigate/sections/race.md","investigate/sections/race.md.tmpl","lib/plan-reality.ts","lib/result-codes.ts","package.json","plan-ceo-review/SKILL.md","plan-ceo-review/SKILL.md.tmpl","plan-ceo-review/sections/checklist.md","plan-ceo-review/sections/checklist.md.tmpl","plan-ceo-review/sections/review-sections.md","plan-ceo-review/sections/review-sections.md.tmpl","plan-eng-review/sections/checklist.md","plan-eng-review/sections/checklist.md.tmpl","plan-eng-review/sections/review-sections.md","plan-eng-review/sections/review-sections.md.tmpl","review/SKILL.md","review/SKILL.md.tmpl","review/checklist.md","review/sections/plan-completion.md","scripts/resolvers/index.ts","scripts/resolvers/plan-gates.ts","scripts/resolvers/plan-reality.ts","scripts/resolvers/sideways.ts","test/carve-section-loading.test.ts","test/fixtures/module-size-ratchet.json","test/fixtures/multi-agent-wave/INCIDENTS.md","test/fixtures/multi-agent-wave/reality-rows.json","test/helpers/carve-guards.ts","test/helpers/free-fixtures-data.ts","test/helpers/parity-harness.ts","test/helpers/touchfiles-data.ts","test/investigate-recipes.test.ts","test/plan-reality.test.ts","test/qa-supervision-selection.test.ts","test/sideways-review.test.ts","test/skill-fixture.test.ts"]},
|
||||
{"runId":38101616162,"pr":3121,"headSha":"819ef8e083162096a5259625b6cc74465d3889df","packageVersionOnly":true,"failedGateCases":["design-review-plugin-handoff"],"changedFiles":[".gitignore",".gstack/generated.json",".gstack/pregate.json","CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","bin/gstack-doctor-components.sh","bin/gstack-issue-links","bin/gstack-pregate","bin/gstack-regen","bin/gstack-ship-receipt","docs/pregate.md","docs/troubleshooting.md","lib/headless-artifacts.ts","lib/issue-links.ts","lib/pregate/checks/lanes.ts","lib/pregate/checks/literals.ts","lib/pregate/checks/regen.ts","lib/pregate/checks/secrets.ts","lib/pregate/checks/strays.ts","lib/pregate/config.ts","lib/pregate/context.ts","lib/pregate/import-graph.ts","lib/pregate/index.ts","lib/pregate/lane-selection.ts","lib/pregate/types.ts","lib/pregate/workflows.ts","lib/regen.ts","lib/result-codes.ts","lib/runtime-pins.ts","lib/ship-receipt.ts","package.json","scripts/gen-ship-goldens.ts","ship/sections/pr-body.md","ship/sections/pr-body.md.tmpl","ship/sections/tests.md","ship/sections/tests.md.tmpl","test/fixtures/module-size-ratchet.json","test/fixtures/multi-agent-wave/INCIDENTS.md","test/gstack-regen.test.ts","test/helpers/pregate-fixture.ts","test/pregate-invalidation.test.ts","test/pregate-selection.test.ts","test/ship-issue-intent.test.ts"]},
|
||||
{"runId":38336400566,"pr":3166,"headSha":"8bf348ddee3a31bed6e914f0cd95e49bf12f3d8e","packageVersionOnly":true,"failedGateCases":["ship-docsync-launch-failure"],"changedFiles":["CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","bin/gstack-doctor-components.sh","bin/gstack-eval-plan","bin/gstack-pregate","bin/gstack-redact-prepush","docs/designs/GSTACK_FIELD_WAVE_2026_10_12.md","docs/eval-calls.md","docs/pregate.md","docs/ship-policy.md","docs/troubleshooting.md","docs/unattended.md","eval-plan/SKILL.md","eval-plan/SKILL.md.tmpl","lib/coordinator-contract.ts","lib/eval-plan.ts","lib/pregate/checks/guards.ts","lib/pregate/checks/lanes.ts","lib/pregate/config.ts","lib/pregate/index.ts","lib/pregate/regate.ts","lib/pregate/runtime.ts","lib/pricing.ts","lib/restamp.ts","lib/result-codes.ts","lib/sealed-guard.ts","lib/ship-policy.ts","lib/tree-receipt.ts","package.json","scripts/lib/windows-curation.ts","scripts/pr-dependencies.ts","spec/sections/gate-and-file.md","test/benchmark-runner.test.ts","test/fixtures/module-size-ratchet.json","test/helpers/capy-host.ts","test/helpers/placeholder-allowlist.ts","test/lane-coordination.test.ts","test/pr-dependencies.test.ts","test/pregate-guards.test.ts","test/pregate-invalidation.test.ts","test/pregate-regate.test.ts","test/pregate-selection.test.ts","test/pricing-eval-plan.test.ts","test/restamp-command-boundary.test.ts","test/sealed-guard.test.ts","test/stamp-templates.test.ts"]},
|
||||
{"runId":38337974933,"pr":3164,"headSha":"f6997e51f4351963fc198bf389872a92ee5b95c1","packageVersionOnly":true,"failedGateCases":["tpa-apple-ban"],"changedFiles":["CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","bin/gstack-bun-version.sh","bin/gstack-capy-install","bin/gstack-capy-session","bin/gstack-doctor","bin/gstack-doctor-check.sh","bin/gstack-doctor-components.sh","bin/gstack-install-verdict.sh","bin/gstack-skill-end","bin/gstack-skill-start","bin/gstack-upgrade","capy/skill/gstack/SKILL.md","capy/skill/gstack/scripts/install.sh","capy/support.env","docs/CHANGELOG_STYLE.md","docs/capy-install.md","docs/designs/GSTACK_FIELD_WAVE_2026_10_12.md","docs/troubleshooting.md","docs/unattended.md","lib/doctor-components.ts","lib/install-verdict.ts","lib/result-codes.ts","package.json","scripts/harness-version.json","scripts/test-pr-profile.ts","test/capy-skill-wrapper.test.ts","test/fixtures/context-budget.json","test/gstack-capy-install.test.ts","test/gstack-doctor.test.ts","test/gstack-skill-start.test.ts","test/gstack-upgrade-bin.test.ts","test/helpers/capy-host.ts","test/install-verdict.test.ts","test/test-pr-profile.test.ts"]},
|
||||
{"runId":38345572852,"pr":3164,"headSha":"2dc7afe70762ddefd69c5ebbf15eea4cc3669fa4","packageVersionOnly":true,"failedGateCases":["qa-functional-webhook-report"],"changedFiles":["CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","bin/gstack-bun-version.sh","bin/gstack-capy-install","bin/gstack-capy-session","bin/gstack-doctor","bin/gstack-doctor-check.sh","bin/gstack-doctor-components.sh","bin/gstack-install-verdict.sh","bin/gstack-skill-end","bin/gstack-skill-start","bin/gstack-upgrade","capy/skill/gstack/SKILL.md","capy/skill/gstack/scripts/install.sh","capy/support.env","docs/CHANGELOG_STYLE.md","docs/capy-install.md","docs/designs/GSTACK_FIELD_WAVE_2026_10_12.md","docs/troubleshooting.md","docs/unattended.md","lib/doctor-components.ts","lib/install-verdict.ts","lib/result-codes.ts","package.json","scripts/harness-version.json","scripts/test-pr-profile.ts","test/capy-skill-wrapper.test.ts","test/fixtures/context-budget.json","test/gstack-capy-install.test.ts","test/gstack-doctor.test.ts","test/gstack-skill-start.test.ts","test/gstack-upgrade-bin.test.ts","test/helpers/capy-host.ts","test/install-verdict.test.ts","test/test-pr-profile.test.ts"]},
|
||||
{"runId":38418037093,"pr":3170,"headSha":"44d380c494816ea915db718c7e3e98889e8f3256","packageVersionOnly":true,"failedGateCases":["shared-libs-read-only"],"changedFiles":["CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","autoplan/DRIVER.md","autoplan/DRIVER.md.tmpl","autoplan/SKILL.md","autoplan/SKILL.md.tmpl","bin/gstack-artifact","bin/gstack-autoplan","bin/gstack-autoplan-snapshot.ts","bin/gstack-doctor-components.sh","bin/gstack-plan-reality","docs/troubleshooting.md","docs/unattended.md","lib/autoplan-admission.ts","lib/autoplan-gate.ts","lib/autoplan-migrate.ts","lib/autoplan-plan-text.ts","lib/autoplan-prompts.ts","lib/autoplan-reconcile.ts","lib/autoplan-revise.ts","lib/autoplan-run.ts","lib/autoplan-scope.ts","lib/autoplan-state.ts","lib/gate-list.ts","lib/headless-artifacts.ts","lib/plan-reality.ts","lib/result-codes.ts","lib/source-root.ts","package.json","scripts/gen-skill-docs.ts","scripts/resolvers/autoplan-driver.ts","scripts/resolvers/index.ts","test/autoplan-admission.test.ts","test/autoplan-answer-invalidation.test.ts","test/autoplan-capy-e2e.test.ts","test/autoplan-driver.test.ts","test/autoplan-gate-judgment.test.ts","test/autoplan-record.test.ts","test/autoplan-revise.test.ts","test/autoplan-run-concurrency.test.ts","test/autoplan-scope.test.ts","test/fixtures/module-size-ratchet.json","test/gen-skill-docs-checks.test.ts","test/helpers/autoplan-capy.ts","test/plan-reality.test.ts","test/review-checklists.test.ts"]},
|
||||
{"runId":38428252213,"pr":3171,"headSha":"e2b08d308cd72f6d9bfbfcf514f0ece0891da153","packageVersionOnly":true,"failedGateCases":["land-and-deploy-workflow","ship-docsync-stale-before","ship-exploratory-plan-checks"],"changedFiles":["CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","bin/gstack-doctor-check.sh","capy/skill/gstack/SKILL.md","docs/troubleshooting.md","lib/result-codes.ts","package.json","test/gstack-doctor.test.ts"]},
|
||||
{"runId":38478947158,"pr":3173,"headSha":"b6389e0631c99449be8f6ac8e9466f26b3daa611","packageVersionOnly":true,"failedGateCases":["ship-exploratory-plan-checks"],"changedFiles":["CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","autoplan/DRIVER.md","autoplan/DRIVER.md.tmpl","bin/gstack-autoplan","bin/gstack-capy-session","bin/gstack-doctor-components.sh","bin/gstack-gbrain-sync.ts","bin/gstack-harness-pid.sh","bin/gstack-lease","bin/gstack-skill-start","bin/gstack-upgrade","capy/skill/gstack/SKILL.md","capy/support.env","docs/capy-install.md","docs/designs/FIX_WAVE_2026_10_12.md","docs/troubleshooting.md","docs/unattended.md","lib/autoplan-admission.ts","lib/autoplan-export.ts","lib/autoplan-gate.ts","lib/autoplan-prompts.ts","lib/autoplan-run.ts","lib/gate-list.ts","lib/headless-artifacts.ts","lib/owner-brief.ts","lib/restamp.ts","lib/result-codes.ts","package.json","scripts/harness-version.json","test-setup.ts","test/auto-decide-fixture.test.ts","test/autoplan-answer-invalidation.test.ts","test/autoplan-capy-e2e.test.ts","test/autoplan-gate-judgment.test.ts","test/autoplan-preconfigured-onboarding-ar.test.ts","test/autoplan-residuals.test.ts","test/autoplan-revise.test.ts","test/capy-skill-wrapper.test.ts","test/ceo-finding-fixture.test.ts","test/gstack-lease.test.ts","test/gstack-skill-start.test.ts","test/gstack-upgrade-bin.test.ts","test/helpers/capy-host.ts","test/helpers/hermetic-env.ts"]},
|
||||
{"runId":38829994639,"pr":3209,"headSha":"2961edad7f56c982d78c97a85c87015bab29b155","packageVersionOnly":false,"failedGateCases":["qa-functional-cli-report"],"changedFiles":[".github/dependabot.yml",".github/workflows/arm-setup-smoke.yml",".github/workflows/cso-runtime-images.yml",".github/workflows/cso-runtime-promote.yml",".github/workflows/cso-runtime-qualification.yml",".github/workflows/cso-scanner-images.yml",".github/workflows/eval-sweep.yml",".github/workflows/evals-marathon.yml",".github/workflows/evals-periodic.yml",".github/workflows/evals.yml",".github/workflows/model-policy-freshness.yml",".github/workflows/native-qualification.yml",".github/workflows/scorecard.yml",".github/workflows/version-gate.yml",".github/workflows/windows-free-tests.yml",".github/workflows/windows-pregate-e2e.yml",".github/workflows/windows-setup-e2e.yml",".osv-scanner.toml","CHANGELOG.md","README.md","VERSION","agents-digest/gstack-AGENTS.md","bin/gstack-browser-ensure","bin/gstack-bun-version.sh","bin/gstack-ceo-plan-find","bin/gstack-claude-root.sh","bin/gstack-config","bin/gstack-doctor-components.sh","bin/gstack-evidence","bin/gstack-ff-update","bin/gstack-gate-diff","bin/gstack-gbrain-sync.ts","bin/gstack-memorable","bin/gstack-sanitize-echo.sh","bin/gstack-session-update","bin/gstack-skill-end","bin/gstack-timeline-log","browse/src/browser-manager.ts","browse/src/meta-commands.ts","browse/src/server.ts","browse/src/terminal-agent.ts","browse/test/tab-external-close-dispatch.test.ts","browse/test/tab-external-close.test.ts","browse/test/terminal-agent-signal-cleanup.test.ts","bun.lock","docs/autoplan-guard-troubleshooting.md","docs/designs/FIX_WAVE_2026_10_15.md","docs/howto-ios-testing-with-gstack.md","docs/troubleshooting.md","gstack-upgrade/SKILL.md","gstack-upgrade/SKILL.md.tmpl","hosts/claude/hooks/spawn-bin.ts","ios-qa/daemon/src/devicectl.ts","ios-qa/daemon/src/tunnel-bootstrap.ts","ios-qa/daemon/test/devicectl-launch-env.test.ts","lib/claude-journal-records.ts","lib/cso/docker.ts","lib/cso/process.ts","lib/cso/scanner-executor.ts","lib/cso/watchdog.c","lib/gate-diff/git.ts","lib/gbrain-exec.ts","lib/pregate/checks/secrets.ts","lib/pregate/import-graph.ts","lib/pregate/lane-selection.ts","lib/redact-engine.ts","lib/regen.ts","lib/restamp.ts","lib/result-codes.ts","lib/sanitize-echo.ts","lib/script-invocation.ts","package.json","plan-ceo-review/sections/review-sections.md","plan-devex-review/sections/review-sections.md","plan-eng-review/SKILL.md","plan-eng-review/SKILL.md.tmpl","plan-eng-review/sections/review-sections.md","scripts/harness-version.json","scripts/resolvers/outside-voice-steps.ts","scripts/test-pr-profile.ts","setup","setup.ps1","test/autoplan-compaction-preserved-segment.test.ts","test/bun-version-shells.test.ts","test/ceo-plan-find-cross-branch.test.ts","test/cso-docker-argv0.test.ts","test/cso-json-redaction.test.ts","test/cso-scanner-release.test.ts","test/dependency-security.test.ts","test/design-doc-data-guard.test.ts","test/fixtures/module-size-ratchet.json","test/fixtures/session-update-heartbeat.sh","test/fixtures/windows-bash-resolution.json","test/gbrain-source-gitignore.test.ts","test/gbrain-spawn-windows-shell.test.ts","test/gbrain-sync-no-bash-message.test.ts","test/gstack-browser-ensure.test.ts","test/gstack-ceo-plan-find.test.ts","test/gstack-ff-update.test.ts","test/gstack-memorable.test.ts","test/gstack-upgrade-fresh-shell.test.ts","test/held-install-recovery.test.ts","test/helpers/auq-sdk-capture.ts","test/helpers/carve-guards.ts","test/helpers/free-fixtures-data.ts","test/helpers/touchfiles-data.ts","test/model-policy-workflow.test.ts","test/osv-ignore-expiry.test.ts","test/outside-voice-native-deadline.test.ts","test/plan-tune-cathedral.test.ts","test/pregate-import-graph-paths.test.ts","test/pregate-manifest-paths.test.ts","test/readme-skill-lists.test.ts","test/redact-prepush-rebase-force-push.test.ts","test/redact-prepush-scan-range.test.ts","test/run-in-background-guidance.test.ts","test/sanitize-echo.test.ts","test/script-invocation-tripwire.test.ts","test/script-invocation.test.ts","test/section-capture-native-tools.test.ts","test/session-update-autostash.test.ts","test/session-update-heartbeat.test.ts","test/session-update-held-banner.test.ts","test/session-update-hook-hold.test.ts","test/session-update-stages.test.ts","test/setup-claude-code-migration.test.ts","test/setup-cursor-legacy-skills.test.ts","test/setup-hook-canonical-paths.test.ts","test/setup-hook-syntax-gate.test.ts","test/setup-playwright-best-effort.test.ts","test/setup-ps1.test.ts","test/ship-measure-sweep.test.ts","test/ship-measure.test.ts","test/skill-end-completion-durability.test.ts","test/state-root-config-merge.test.ts","test/team-mode.test.ts","test/test-value-bar.test.ts","test/timeline-stop-hook-slug.test.ts","test/upgrade-setup-recovery.test.ts","test/upgrade-template-pins.test.ts","test/workflow-action-pins.test.ts","test/wtree-consumers.test.ts"]},
|
||||
{"runId":38969924945,"pr":3225,"headSha":"09fe44fe435e7ccf6291f688d4883bcdcb5464da","packageVersionOnly":false,"failedGateCases":["qa-only-no-fix","ship-docsync-store"],"changedFiles":["benchmark/SKILL.md","bin/gstack-upgrade","browse/SKILL.md","canary/SKILL.md","design-consultation/SKILL.md","design-review/SKILL.md","devex-review/SKILL.md","land-and-deploy/SKILL.md","lib/redact-patterns.ts","plan-design-review/sections/review-sections.md","plan-design-review/sections/review-sections.md.tmpl","qa/sections/browser-setup.md","scrape/SKILL.md","scripts/resolvers/aside.ts","test/aside-driver.test.ts","test/cso-git-hardening.test.ts","test/gstack-upgrade-path-spelling.test.ts","test/redact-engine.test.ts","test/review-entry-and-design-clarity-au.test.ts"]},
|
||||
{"runId":38973329985,"pr":3225,"headSha":"c130a85ad516ff288a2d0840dfb3180b07b83eca","packageVersionOnly":false,"failedGateCases":["ship-exploratory-small-cli"],"changedFiles":["benchmark/SKILL.md","bin/gstack-upgrade","browse/SKILL.md","canary/SKILL.md","design-consultation/SKILL.md","design-review/SKILL.md","devex-review/SKILL.md","land-and-deploy/SKILL.md","lib/pregate/checks/secrets.ts","lib/redact-patterns.ts","plan-design-review/sections/review-sections.md","plan-design-review/sections/review-sections.md.tmpl","plan-devex-review/sections/review-sections.md","plan-devex-review/sections/review-sections.md.tmpl","qa/sections/browser-setup.md","scrape/SKILL.md","scripts/resolvers/aside.ts","test/aside-driver.test.ts","test/cso-git-hardening.test.ts","test/gstack-upgrade-path-spelling.test.ts","test/pregate-secrets-source-context.test.ts","test/redact-engine.test.ts","test/review-entry-and-design-clarity-au.test.ts"]},
|
||||
{"runId":38974669950,"pr":3190,"headSha":"03968f0a7c3f54d4181a20c37ee77594de26974f","packageVersionOnly":true,"failedGateCases":["qa-functional-webhook-fix"],"changedFiles":[".github/workflows/free-tests.yml","CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","autoplan/DRIVER.md","autoplan/DRIVER.md.tmpl","autoplan/sections/ceo-phase.md","autoplan/sections/eng-phase.md","bin/gstack-autoplan","bin/gstack-bun-version.sh","bin/gstack-capy-install","bin/gstack-capy-session","bin/gstack-doctor-check.sh","bin/gstack-doctor-components.sh","bin/gstack-gate","bin/gstack-install-verdict.sh","bin/gstack-issue-links","bin/gstack-plan-reality","bin/gstack-pregate","bin/gstack-ship-receipt","bin/gstack-upgrade","capy/skill/gstack/SKILL.md","capy/skill/gstack/scripts/install.sh","docs/capy-install.md","docs/pregate.md","docs/troubleshooting.md","docs/unattended.md","lib/autoplan-checkpoint.ts","lib/autoplan-export.ts","lib/autoplan-gate.ts","lib/autoplan-plan-text.ts","lib/autoplan-prompts.ts","lib/autoplan-reconcile.ts","lib/autoplan-revise.ts","lib/autoplan-run.ts","lib/autoplan-state.ts","lib/doctor-components.ts","lib/gate-list.ts","lib/headless-artifacts.ts","lib/install-verdict.ts","lib/issue-links.ts","lib/plan-reality.ts","lib/pregate/checks/guards.ts","lib/pregate/checks/lanes.ts","lib/pregate/config.ts","lib/pregate/context.ts","lib/pregate/index.ts","lib/pregate/runtime.ts","lib/pregate/supervise.ts","lib/pregate/types.ts","lib/result-codes.ts","lib/runtime-pins.ts","lib/ship-receipt.ts","package.json","scripts/lib/windows-curation.ts","scripts/resolvers/autoplan-driver.ts","scripts/resolvers/plan-reality.ts","scripts/ubicloud/ubi-runner.sh","setup","ship/SKILL.md","ship/SKILL.md.tmpl","ship/sections/handoff.md","ship/sections/handoff.md.tmpl","ship/sections/pr-body.md","ship/sections/pr-body.md.tmpl","ship/sections/tests.md","ship/sections/tests.md.tmpl","test/autoplan-answer-invalidation.test.ts","test/autoplan-capy-e2e.test.ts","test/autoplan-checkpoint.test.ts","test/autoplan-driver.test.ts","test/autoplan-gate-artifacts.test.ts","test/autoplan-gate-judgment.test.ts","test/autoplan-pairing.test.ts","test/autoplan-record.test.ts","test/autoplan-residuals.test.ts","test/autoplan-revise.test.ts","test/autoplan-run-concurrency.test.ts","test/autoplan-run-recovery.test.ts","test/bun-resolve.test.ts","test/bun-version-drift.test.ts","test/capy-skill-wrapper.test.ts","test/cso-distribution.test.ts","test/fixtures/autoplan-pairing/run-20261014-pairs.json","test/fixtures/context-budget.json","test/fixtures/golden/agy-ship-SKILL.md","test/fixtures/golden/claude-ship-SKILL.md","test/fixtures/golden/codex-ship-SKILL.md","test/fixtures/golden/factory-ship-SKILL.md","test/gate-list.test.ts","test/gstack-capy-install.test.ts","test/gstack-doctor.test.ts","test/gstack-upgrade-bin.test.ts","test/helpers/autoplan-capy.ts","test/helpers/autoplan-run-fixture.ts","test/helpers/carve-guards.ts","test/helpers/free-fixtures-data.ts","test/helpers/pregate-fixture.ts","test/host-conformance.test.ts","test/install-verdict.test.ts","test/plan-reality.test.ts","test/pregate-guards.test.ts","test/pregate-remote.test.ts","test/pregate-supervise.test.ts","test/redact-prepush-hook.test.ts","test/runtime-pins.test.ts","test/script-invocation-tripwire.test.ts","test/setup-hook-syntax-gate.test.ts","test/setup-playwright-best-effort.test.ts","test/ship-issue-intent.test.ts","test/ubicloud-runner.test.ts"]},
|
||||
{"runId":38976253774,"pr":3190,"headSha":"7d68dedae91ffadf494f4cd9a1ab5c253f4b73d6","packageVersionOnly":true,"failedGateCases":["autoplan-guard-pty"],"changedFiles":[".github/workflows/free-tests.yml","CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","autoplan/DRIVER.md","autoplan/DRIVER.md.tmpl","autoplan/sections/ceo-phase.md","autoplan/sections/eng-phase.md","bin/gstack-autoplan","bin/gstack-bun-version.sh","bin/gstack-capy-install","bin/gstack-capy-session","bin/gstack-doctor-check.sh","bin/gstack-doctor-components.sh","bin/gstack-gate","bin/gstack-install-verdict.sh","bin/gstack-issue-links","bin/gstack-plan-reality","bin/gstack-pregate","bin/gstack-ship-receipt","bin/gstack-upgrade","capy/skill/gstack/SKILL.md","capy/skill/gstack/scripts/install.sh","docs/capy-install.md","docs/pregate.md","docs/troubleshooting.md","docs/unattended.md","lib/autoplan-checkpoint.ts","lib/autoplan-export.ts","lib/autoplan-gate.ts","lib/autoplan-plan-text.ts","lib/autoplan-prompts.ts","lib/autoplan-reconcile.ts","lib/autoplan-revise.ts","lib/autoplan-run.ts","lib/autoplan-state.ts","lib/doctor-components.ts","lib/gate-list.ts","lib/headless-artifacts.ts","lib/install-verdict.ts","lib/issue-links.ts","lib/plan-reality.ts","lib/pregate/checks/guards.ts","lib/pregate/checks/lanes.ts","lib/pregate/config.ts","lib/pregate/context.ts","lib/pregate/index.ts","lib/pregate/runtime.ts","lib/pregate/supervise.ts","lib/pregate/types.ts","lib/result-codes.ts","lib/runtime-pins.ts","lib/ship-receipt.ts","package.json","scripts/lib/windows-curation.ts","scripts/resolvers/autoplan-driver.ts","scripts/resolvers/plan-reality.ts","scripts/ubicloud/ubi-runner.sh","setup","ship/SKILL.md","ship/SKILL.md.tmpl","ship/sections/handoff.md","ship/sections/handoff.md.tmpl","ship/sections/pr-body.md","ship/sections/pr-body.md.tmpl","ship/sections/tests.md","ship/sections/tests.md.tmpl","test/autoplan-answer-invalidation.test.ts","test/autoplan-capy-e2e.test.ts","test/autoplan-checkpoint.test.ts","test/autoplan-driver.test.ts","test/autoplan-gate-artifacts.test.ts","test/autoplan-gate-judgment.test.ts","test/autoplan-pairing.test.ts","test/autoplan-record.test.ts","test/autoplan-residuals.test.ts","test/autoplan-revise.test.ts","test/autoplan-run-concurrency.test.ts","test/autoplan-run-recovery.test.ts","test/bun-resolve.test.ts","test/bun-version-drift.test.ts","test/capy-skill-wrapper.test.ts","test/cso-distribution.test.ts","test/fixtures/autoplan-pairing/run-20261014-pairs.json","test/fixtures/context-budget.json","test/fixtures/golden/agy-ship-SKILL.md","test/fixtures/golden/claude-ship-SKILL.md","test/fixtures/golden/codex-ship-SKILL.md","test/fixtures/golden/factory-ship-SKILL.md","test/gate-list.test.ts","test/gstack-capy-install.test.ts","test/gstack-doctor.test.ts","test/gstack-upgrade-bin.test.ts","test/helpers/autoplan-capy.ts","test/helpers/autoplan-run-fixture.ts","test/helpers/carve-guards.ts","test/helpers/free-fixtures-data.ts","test/helpers/pregate-fixture.ts","test/helpers/qa-functional-fixture.ts","test/host-conformance.test.ts","test/install-verdict.test.ts","test/plan-reality.test.ts","test/pregate-guards.test.ts","test/pregate-remote.test.ts","test/pregate-supervise.test.ts","test/redact-prepush-hook.test.ts","test/runtime-pins.test.ts","test/script-invocation-tripwire.test.ts","test/setup-hook-syntax-gate.test.ts","test/setup-playwright-best-effort.test.ts","test/ship-issue-intent.test.ts","test/ubicloud-runner.test.ts"]},
|
||||
{"runId":38980005793,"pr":3225,"headSha":"3f4a98ecac3fc434f8aeef61bc9def17080718d9","packageVersionOnly":false,"failedGateCases":["design-review-detector-shim-dom","qa-quick"],"changedFiles":["benchmark/SKILL.md","bin/gstack-upgrade","browse/SKILL.md","canary/SKILL.md","design-consultation/SKILL.md","design-review/SKILL.md","devex-review/SKILL.md","land-and-deploy/SKILL.md","lib/pregate/checks/secrets.ts","lib/redact-patterns.ts","plan-design-review/sections/review-sections.md","plan-design-review/sections/review-sections.md.tmpl","plan-devex-review/sections/review-sections.md","plan-devex-review/sections/review-sections.md.tmpl","qa/sections/browser-setup.md","scrape/SKILL.md","scripts/resolvers/aside.ts","test/aside-driver.test.ts","test/cso-git-hardening.test.ts","test/gstack-upgrade-path-spelling.test.ts","test/pregate-secrets-source-context.test.ts","test/redact-engine.test.ts","test/review-entry-and-design-clarity-au.test.ts"]},
|
||||
{"runId":38981523623,"pr":3231,"headSha":"3ba8b460645b972f91042bb73e6a7a07eb4b05ab","packageVersionOnly":false,"failedGateCases":["ship-exploratory-plan-checks"],"changedFiles":["bin/gstack-skill-end","bin/gstack-skill-start","test/detector-corpus-ship-docsync-launch-failure.test.ts","test/docsync-command-grammar.test.ts","test/fixtures/detector-corpora/ship-docsync-launch-failure/38336400566-t1-fail-derived-current-claim.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/38336400566-t1-fail-derived-prose-claim.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/38336400566-t1-fail.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/38829994639-t1-pass.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/38972920715-t1-pass.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/inventory.json","test/fixtures/docsync-store-38969924945-bash.json","test/gstack-skill-start.test.ts","test/helpers/docsync-fault-eval.ts","test/helpers/docsync-observer.ts","test/helpers/free-fixtures-data.ts","test/helpers/qa-browser-deadline-evidence.ts","test/qa-browser-deadline-evidence.test.ts","test/test-of-test-ratchet.test.ts"]},
|
||||
{"runId":38983306684,"pr":3231,"headSha":"84c29e9ee3325c19626edff677dc1ff2ff4f21d9","packageVersionOnly":false,"failedGateCases":["qa-functional-cli-report","ship-docsync-missing-asset"],"changedFiles":["bin/gstack-skill-end","bin/gstack-skill-start","review/sections/review-army.md","scripts/resolvers/review-army.ts","ship/sections/review-army.md","test/detector-corpus-ship-docsync-launch-failure.test.ts","test/docsync-command-grammar.test.ts","test/fixtures/detector-corpora/ship-docsync-launch-failure/38336400566-t1-fail-derived-current-claim.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/38336400566-t1-fail-derived-prose-claim.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/38336400566-t1-fail.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/38829994639-t1-pass.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/38972920715-t1-pass.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/inventory.json","test/fixtures/docsync-store-38969924945-bash.json","test/gstack-skill-start.test.ts","test/helpers/docsync-fault-eval.ts","test/helpers/docsync-observer.ts","test/helpers/free-fixtures-data.ts","test/helpers/qa-browser-deadline-evidence.ts","test/qa-browser-deadline-evidence.test.ts","test/review-workflow-clarity.test.ts","test/test-of-test-ratchet.test.ts"]},
|
||||
{"runId":38984977679,"pr":3226,"headSha":"122638084111bcea20fc3f62e4a8cd286cbaa437","packageVersionOnly":false,"failedGateCases":["ship-docsync-failure"],"changedFiles":["README.md","autoplan/SKILL.md","autoplan/SKILL.md.tmpl","autoplan/sections/dx-phase.md","autoplan/sections/dx-phase.md.tmpl","bin/gstack-autoplan-snapshot.ts","bin/gstack-doctor-components.sh","bin/gstack-error-capture","devex-review/SKILL.md","devex-review/SKILL.md.tmpl","docs/agent-ready-errors.md","docs/skills.md","docs/troubleshooting.md","lib/autoplan-prompts.ts","lib/dx-error-capture.ts","lib/dx-error-contract.ts","lib/qa-deadline.ts","lib/result-codes.ts","plan-devex-review/SKILL.md","plan-devex-review/SKILL.md.tmpl","plan-devex-review/dx-hall-of-fame.md","plan-devex-review/sections/checklist.md","plan-devex-review/sections/checklist.md.tmpl","plan-devex-review/sections/review-sections.md","plan-devex-review/sections/review-sections.md.tmpl","scripts/resolvers/dx.ts","scripts/resolvers/index.ts","test/dx-error-capture.test.ts","test/dx-error-contract-grader.test.ts","test/dx-error-contract.test.ts","test/eng-finding-retry-budget.test.ts","test/fixtures/dx-error-contract-case.ts","test/helpers/touchfiles-data.ts","test/skill-e2e-dx-error-contract.test.ts"]},
|
||||
{"runId":38986120559,"pr":3231,"headSha":"6fd20bef0fe9387cf13dee88cb144e7b3914575b","packageVersionOnly":true,"failedGateCases":["qa-functional-webhook-fix"],"changedFiles":["CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","bin/gstack-skill-end","bin/gstack-skill-start","package.json","review/sections/review-army.md","scripts/resolvers/review-army.ts","ship/sections/review-army.md","test/detector-corpus-ship-docsync-launch-failure.test.ts","test/docsync-command-grammar.test.ts","test/fixtures/detector-corpora/ship-docsync-launch-failure/38336400566-t1-fail-derived-current-claim.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/38336400566-t1-fail-derived-prose-claim.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/38336400566-t1-fail.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/38829994639-t1-pass.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/38972920715-t1-pass.json","test/fixtures/detector-corpora/ship-docsync-launch-failure/inventory.json","test/fixtures/docsync-store-38969924945-bash.json","test/gstack-skill-start.test.ts","test/helpers/docsync-fault-eval.ts","test/helpers/docsync-observer.ts","test/helpers/free-fixtures-data.ts","test/helpers/qa-browser-deadline-evidence.ts","test/qa-browser-deadline-evidence.test.ts","test/review-workflow-clarity.test.ts","test/test-of-test-ratchet.test.ts"]},
|
||||
{"runId":38988927989,"pr":3232,"headSha":"641916c650257b7fb5719ec45bef70b00066874e","packageVersionOnly":false,"failedGateCases":["tpa-absent-linux"],"changedFiles":["bin/gstack-capy-install","bin/gstack-capy-session","bin/gstack-lease","bin/gstack-skill-start","capy/skill/gstack/SKILL.md","docs/capy-install.md","docs/troubleshooting.md","test/capy-skill-wrapper.test.ts","test/gstack-capy-install.test.ts","test/gstack-lease.test.ts","test/gstack-upgrade-bin.test.ts"]},
|
||||
{"runId":38990111230,"pr":3226,"headSha":"6c07d85c82d17bda81860cd0d78616de3dc14cc2","packageVersionOnly":false,"failedGateCases":["ship-docsync-stale-after"],"changedFiles":["README.md","autoplan/SKILL.md","autoplan/SKILL.md.tmpl","autoplan/sections/dx-phase.md","autoplan/sections/dx-phase.md.tmpl","bin/gstack-autoplan-snapshot.ts","bin/gstack-doctor-components.sh","bin/gstack-error-capture","devex-review/SKILL.md","devex-review/SKILL.md.tmpl","docs/agent-ready-errors.md","docs/skills.md","docs/troubleshooting.md","lib/autoplan-prompts.ts","lib/dx-error-capture.ts","lib/dx-error-contract.ts","lib/qa-deadline.ts","lib/result-codes.ts","plan-devex-review/SKILL.md","plan-devex-review/SKILL.md.tmpl","plan-devex-review/dx-hall-of-fame.md","plan-devex-review/sections/checklist.md","plan-devex-review/sections/checklist.md.tmpl","plan-devex-review/sections/review-sections.md","plan-devex-review/sections/review-sections.md.tmpl","scripts/resolvers/dx.ts","scripts/resolvers/index.ts","test/dx-error-capture.test.ts","test/dx-error-contract-grader.test.ts","test/dx-error-contract.test.ts","test/eng-finding-retry-budget.test.ts","test/fixtures/dx-error-contract-case.ts","test/helpers/touchfiles-data.ts","test/skill-e2e-dx-error-contract.test.ts"]},
|
||||
{"runId":38993076767,"pr":3234,"headSha":"b40d8418f9435804a4803981dcb01c7288d87e73","packageVersionOnly":false,"failedGateCases":["ship-docsync-store","ship-exploratory-small-cli"],"changedFiles":["autoplan/DRIVER.md","autoplan/DRIVER.md.tmpl","bin/gstack-artifact","bin/gstack-autoplan","bin/gstack-capy-install","bin/gstack-doctor-check.sh","bin/gstack-doctor-components.sh","bin/gstack-eval-plan","bin/gstack-install-verdict.sh","capy/skill/gstack/SKILL.md","capy/skill/gstack/scripts/install.sh","docs/capy-install.md","docs/designs/field-list-2-2026-10-16/PLAN.md","docs/designs/field-list-2-2026-10-16/ROUND2-OBLIGATIONS.md","docs/eval-models.md","docs/troubleshooting.md","docs/unattended.md","eval-plan/SKILL.md","eval-plan/SKILL.md.tmpl","lib/autoplan-budget.ts","lib/autoplan-checkpoint.ts","lib/autoplan-confirm.ts","lib/autoplan-export.ts","lib/autoplan-gate.ts","lib/autoplan-prompts.ts","lib/autoplan-public.ts","lib/autoplan-reconcile.ts","lib/autoplan-revise.ts","lib/autoplan-run.ts","lib/autoplan-state.ts","lib/coordinator-contract.ts","lib/doctor-components.ts","lib/eval-models.ts","lib/eval-plan.ts","lib/gate-list.ts","lib/headless-artifacts.ts","lib/install-verdict.ts","lib/result-codes.ts","lib/spend-ledger.ts","scripts/resolvers/autoplan-driver.ts","ship/sections/handoff.md","ship/sections/handoff.md.tmpl","spec/sections/gate-and-file.md","test/autoplan-budget.test.ts","test/autoplan-checkpoint.test.ts","test/autoplan-durability.test.ts","test/autoplan-public-export.test.ts","test/capy-review-voice.test.ts","test/capy-skill-wrapper.test.ts","test/doctor-components.test.ts","test/eval-models.test.ts","test/eval-plan-prereg-diagnostics.test.ts","test/fixtures/context-budget.json","test/fixtures/module-size-ratchet.json","test/gstack-capy-install.test.ts","test/gstack-doctor.test.ts"]},
|
||||
{"runId":39001107574,"pr":3236,"headSha":"79554ccaba38b47a06d55f43dc8fdbb922b738b9","packageVersionOnly":true,"failedGateCases":["qa-functional-cli-report"],"changedFiles":[".github/workflows/windows-pregate-e2e.yml","CHANGELOG.md","VERSION","agents-digest/gstack-AGENTS.md","bin/gstack-doctor","bin/gstack-doctor-components.sh","bin/gstack-pregate","bin/gstack-windows-bash.ts","docs/ADDING_A_HOST.md","docs/troubleshooting.md","lib/pregate/checks/lanes.ts","lib/pregate/context.ts","lib/pregate/import-graph.ts","lib/pregate/index.ts","lib/regen.ts","lib/result-codes-release.ts","lib/script-invocation.ts","package.json","scripts/lib/windows-curation.ts","scripts/resolvers/preamble.ts","scripts/resolvers/preamble/generate-completion-status.ts","test/fixtures/golden/agy-ship-SKILL.md","test/fixtures/golden/codex-ship-SKILL.md","test/fixtures/golden/factory-ship-SKILL.md","test/fixtures/skill-md-size-allowlist.json","test/gen-skill-docs.test.ts","test/gstack-doctor.test.ts","test/helpers/free-fixtures-data.ts","test/helpers/pregate-fixture.ts","test/helpers/restamp-fixture.ts","test/pregate-bats-nested.test.ts","test/pregate-wtree-refusal.test.ts","test/review-entry-and-design-clarity-au.test.ts","test/script-invocation-tripwire.test.ts","test/script-invocation.test.ts","test/skill-md-size-guard.test.ts"]},
|
||||
{"runId":39002269281,"pr":3239,"headSha":"8e878d9ee9f06a196ff04ccfb0a4d836c13cb1aa","packageVersionOnly":false,"failedGateCases":["ship-exploratory-plan-checks"],"changedFiles":[".github/dependabot.yml",".github/workflows/version-gate.yml",".osv-scanner.toml","TODOS.md","bun.lock","lib/diagram-render/bun.lock","lib/diagram-render/package.json","make-pdf/src/image-size.ts","make-pdf/src/orchestrator.ts","make-pdf/test/docx-image-size.test.ts","make-pdf/test/fixtures/docx-images/doc.md","make-pdf/test/fixtures/docx-images/document.golden.xml","make-pdf/test/fixtures/docx-images/square.gif","make-pdf/test/fixtures/docx-images/tall.jpg","make-pdf/test/fixtures/docx-images/wide.png","package.json","scripts/compare-pr-version.ts","scripts/typecheck-test-baseline.json","test/ceo-finding-fixture.test.ts","test/compare-pr-version.test.ts","test/osv-config-wiring.test.ts","test/osv-ignore-expiry.test.ts","test/workflow-action-pins.test.ts"]},
|
||||
{"runId":39004466422,"pr":3239,"headSha":"65ca746bda533a348a66032a6541647b43339416","packageVersionOnly":false,"failedGateCases":["plan-mode-no-op"],"changedFiles":[".github/dependabot.yml",".github/workflows/version-gate.yml",".osv-scanner.toml","TODOS.md","bun.lock","lib/diagram-render/bun.lock","lib/diagram-render/package.json","make-pdf/src/docx-images.ts","make-pdf/src/html-to-vdom.d.ts","make-pdf/src/orchestrator.ts","make-pdf/test/docx-image-size.test.ts","make-pdf/test/fixtures/docx-images/doc.md","make-pdf/test/fixtures/docx-images/document.golden.xml","make-pdf/test/fixtures/docx-images/square.gif","make-pdf/test/fixtures/docx-images/tall.jpg","make-pdf/test/fixtures/docx-images/wide.png","package.json","scripts/compare-pr-version.ts","scripts/typecheck-test-baseline.json","test/ceo-finding-fixture.test.ts","test/compare-pr-version.test.ts","test/osv-config-wiring.test.ts","test/osv-ignore-expiry.test.ts","test/workflow-action-pins.test.ts","tsconfig.test.json"]},
|
||||
{"runId":39006896632,"pr":3239,"headSha":"3449a9cd5fd1ed51fd9242bde3a5636ae8d97b77","packageVersionOnly":false,"failedGateCases":["qa-functional-webhook-report"],"changedFiles":[".github/dependabot.yml",".github/workflows/version-gate.yml",".osv-scanner.toml","CHANGELOG.md","TODOS.md","VERSION","agents-digest/gstack-AGENTS.md","bun.lock","lib/diagram-render/bun.lock","lib/diagram-render/package.json","make-pdf/src/docx-images.ts","make-pdf/src/html-to-vdom.d.ts","make-pdf/src/orchestrator.ts","make-pdf/test/docx-image-size.test.ts","make-pdf/test/fixtures/docx-images/doc.md","make-pdf/test/fixtures/docx-images/document.golden.xml","make-pdf/test/fixtures/docx-images/square.gif","make-pdf/test/fixtures/docx-images/tall.jpg","make-pdf/test/fixtures/docx-images/wide.png","package.json","scripts/compare-pr-version.ts","scripts/typecheck-test-baseline.json","test/ceo-finding-fixture.test.ts","test/compare-pr-version.test.ts","test/osv-config-wiring.test.ts","test/osv-ignore-expiry.test.ts","test/workflow-action-pins.test.ts","tsconfig.test.json"]},
|
||||
{"runId":39011101113,"pr":3239,"headSha":"599d3f044952ad9ca5f92e6e4f78d342278b44e9","packageVersionOnly":false,"failedGateCases":["tpa-absent-linux"],"changedFiles":[".github/dependabot.yml",".github/workflows/version-gate.yml",".osv-scanner.toml","CHANGELOG.md","TODOS.md","VERSION","agents-digest/gstack-AGENTS.md","bun.lock","lib/diagram-render/bun.lock","lib/diagram-render/package.json","make-pdf/src/docx-images.ts","make-pdf/src/html-to-vdom.d.ts","make-pdf/src/orchestrator.ts","make-pdf/test/docx-image-size.test.ts","make-pdf/test/fixtures/docx-images/doc.md","make-pdf/test/fixtures/docx-images/document.golden.xml","make-pdf/test/fixtures/docx-images/square.gif","make-pdf/test/fixtures/docx-images/tall.jpg","make-pdf/test/fixtures/docx-images/wide.png","package.json","scripts/compare-pr-version.ts","scripts/typecheck-test-baseline.json","test/ceo-finding-fixture.test.ts","test/compare-pr-version.test.ts","test/osv-config-wiring.test.ts","test/osv-ignore-expiry.test.ts","test/workflow-action-pins.test.ts","tsconfig.test.json"]}
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user