v1.91.77.0 feat(ship): two-stage gstack-pregate, gstack-regen generated-file registry, intent-based issue links (multi-agent wave C-pregate) (#3121)

* v1.91.77.0 feat(ship): two-stage gstack-pregate, gstack-regen registry, intent-based issue links (multi-agent wave C-pregate)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(pregate): keep the bin-driving pregate tests off the Windows subset; pin files are free-only for eval selection

The three C-pregate tests that spawn bin/gstack-regen, bin/gstack-pregate,
bin/gstack-issue-links and bin/gstack-ship-receipt do so through
test/helpers/pregate-fixture.ts runBin, so the Windows curation's source
scan of the test file never saw a bin/ spawn and shipped them to
windows-latest, where CreateProcess cannot exec a shebang (14 failures in
windows-free-shard 2 and 5). Each is now a KNOWN_WINDOWS_INCOMPATIBLE entry
with the precise reason. .gstack/generated.json and .gstack/pregate.json
join FREE_ONLY_PR_FILES: no paid case reads gstack's own pin files (the
tools read origin/<base> of the repo they run in, and paid cases run in
fixture repos), so touching them no longer restores every gate case.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(harness-version): record the FREE_ONLY_PR_FILES pin-file entries as non-behavioral

scripts/test-pr-profile.ts is a pinned shared-harness file; the two
.gstack pin-file entries change selection only, never a case verdict.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
Garry Tanandcapy-ai[bot] authored and GitHub committed 2026-10-11 01:57:16 +00:00
1 parent 4e5bf1e454
commit 8584d6ff49
47 files changed
+3394 -21

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
/**
* gen-ship-goldens — refresh the byte-pinned /ship renders under
* test/fixtures/golden/ (test/host-config.test.ts compares a fresh render to
* them). The claude golden is the tracked ship/SKILL.md; the codex, factory
* and agy goldens come from a `--out-dir` render of each host. Registered in
* .gstack/generated.json so `gstack-regen check` reports a stale golden
* before any remote gate and `gstack-regen write` refreshes it.
*/
import { spawnSync } from 'node:child_process';
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
const ROOT = path.resolve(import.meta.dir, '..');
const GOLDEN_DIR = path.join(ROOT, 'test', 'fixtures', 'golden');
const HOSTS: Array<{ host: string; dir: string }> = [
{ host: 'codex', dir: '.agents' },
{ host: 'factory', dir: '.factory' },
{ host: 'agy', dir: '.agy' },
];
export function generateShipGoldens(): string[] {
const written: string[] = [];
const out = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-ship-goldens-'));
try {
const copy = (from: string, to: string) => {
const bytes = fs.readFileSync(from);
const dest = path.join(GOLDEN_DIR, to);
if (!fs.existsSync(dest) || !fs.readFileSync(dest).equals(bytes)) { fs.writeFileSync(dest, bytes); written.push(path.relative(ROOT, dest)); }
};
copy(path.join(ROOT, 'ship', 'SKILL.md'), 'claude-ship-SKILL.md');
for (const { host, dir } of HOSTS) {
const r = spawnSync('bun', ['run', path.join(ROOT, 'scripts', 'gen-skill-docs.ts'), '--host', host, '--out-dir', out], { cwd: ROOT, encoding: 'utf8', timeout: 180_000 });
if (r.status !== 0) throw new Error(`gen-skill-docs --host ${host} --out-dir failed (exit ${r.status}):\n${r.stderr}`);
copy(path.join(out, dir, 'skills', 'gstack-ship', 'SKILL.md'), `${host}-ship-SKILL.md`);
}
} finally { fs.rmSync(out, { recursive: true, force: true }); }
return written;
}
if (import.meta.main) {
const written = generateShipGoldens();
console.log(written.length ? `GENERATED: ${written.join(' ')}` : 'ship goldens: fresh');
}
+1 -1
View File
@@ -16,7 +16,7 @@
"scripts/lib/published-text.ts": {"blob":"3f2e4d616b5dd0204035710c66b64d49055c5714","since":4},
"scripts/lib/shard-engine.ts": {"blob":"3cd0b1aaa84018b00bf9ea0ce48093f3c8492f66","since":4},
"scripts/test-paid-shards.ts": {"blob":"8ddee5f11ed7856876135520dd8025ab989e2db9","since":4},
"scripts/test-pr-profile.ts": {"blob":"2adf1e8dbc1129169fa6dccf2e0b14d7b7fdb698","since":4,"nonBehavioral":"HONEST_WORK_GATE_INTEGRITY: PR_PROFILE_CASE_IDS and PR_PROFILE_TEST_FILES gain review-gate-integrity; selection only, no case verdict rule changes"},
"scripts/test-pr-profile.ts": {"blob":"1b3c215f8f50901c16357665a585101eaa27ff31","since":4,"nonBehavioral":"C-pregate: FREE_ONLY_PR_FILES gains .gstack/generated.json and .gstack/pregate.json (gstack's own pin files, read by no paid case); selection only, no case verdict rule changes"},
"scripts/test-strict-output.ts": {"blob":"01185d20dc9761b04b9b2f751ec98664fe0eaf93","since":4},
"test/helpers/agent-sdk-runner.ts": {"blob":"210bba92d241a90df578b2c7fc943ac5755d0025","since":4},
"test/helpers/auq-substance-panel.ts": {"blob":"4881260ef793668e4963a062db6d06a5e1f7a40f","since":4},
+8
View File
@@ -51,6 +51,14 @@ const WINDOWS_FRAGILE_PATTERNS: Array<{ pattern: RegExp; reason: string }> = [
// when possible; this list is for environment-/runtime-specific tests where
// the failure mode is structural rather than detectable via source-file scan.
export const KNOWN_WINDOWS_INCOMPATIBLE: Array<{ file: string; reason: string }> = [
// C-pregate: these drive bin/gstack-regen, bin/gstack-pregate, bin/gstack-issue-links and
// bin/gstack-ship-receipt through test/helpers/pregate-fixture.ts runBin (spawnSync on the
// shebang file, which CreateProcess cannot exec) and run `node gen.js` / `node --test` fixture
// commands through the pre-gate's POSIX `bash -o pipefail` runner. The pure parsers and the
// import graph are covered by test/pregate-selection.test.ts, which the bin/ pattern excludes too.
{ file: 'test/gstack-regen.test.ts', reason: 'spawns bin/gstack-regen through test/helpers/pregate-fixture.ts runBin (shebang via CreateProcess) and POSIX fixture regen commands' },
{ file: 'test/pregate-invalidation.test.ts', reason: 'spawns bin/gstack-pregate and bin/gstack-ship-receipt through test/helpers/pregate-fixture.ts runBin (shebang via CreateProcess) and the pipefail lane runner' },
{ file: 'test/ship-issue-intent.test.ts', reason: 'spawns bin/gstack-issue-links and bin/gstack-ship-receipt through test/helpers/pregate-fixture.ts runBin (shebang via CreateProcess) with a `gh` shell shim on PATH' },
{
file: 'test/ship-measure-seeded-fixture.test.ts',
reason: 'drives a POSIX shell stub project (`./evals.sh` with a shebang) that CreateProcess cannot exec; the measure runner itself is covered by ship-measure.test.ts with in-process fake runners',
+2
View File
@@ -212,6 +212,8 @@ export const FREE_ONLY_PR_FILES = [
'scripts/ubicloud/**',
'tsconfig.test.json', // Read only by `tsc -p tsconfig.test.json` (typecheck:test); Bun's runtime reads tsconfig.json.
'.gitignore', // Changes which untracked files git reports, never tracked content a case reads.
'.gstack/generated.json', // gstack's own regen registry: gstack-regen/gstack-pregate read it from origin/<base> of the repo they run in; paid cases run in fixture repos.
'.gstack/pregate.json', // gstack's own pre-gate policy: same trust boundary, same reason.
'scripts/retired-command.ts', // One-release stubs for retired package scripts; no paid case imports it.
'careful/bin/check-careful.sh', // /careful PreToolUse hook: covered by test/hook-scripts.test.ts; no paid fixture copies or runs it.
// Reporting and launch tools: they read CI history or start a lane, never run inside a paid case.