chore(ship-policy): gstack runs land.merged_checks on stale-base lands (GST-1332) (#4029)

* chore(ship-policy): gstack runs land.merged_checks on stale-base lands (GST-1332)

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

* test(ship-policy): gstack's land.merged_checks names only test files that exist (GST-1332)

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

* fix(ship-policy): land.merged_checks run tests through the strict runner and catch untracked generated files (GST-1332)

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-11-05 06:06:09 +00:00
1 parent 74418edabc
commit 44f4875c9d
5 files changed
+44 -2

No files matched your search

+8 -1
View File
@@ -16,5 +16,12 @@
"train": { "gate_workflow": "evals.yml", "free_workflow": "free-tests.yml", "full_gate_check": "gstack/full-gate", "record_artifact": "gstack-train-record", "max_size": 5, "fill_hours": 1, "screen_selection": "gstack-paid", "trial_reservation_usd": 1.5 },
"changelog_fragments": { "dir": "changelog.d", "required_checks": ["free-tests", "windows-smoke", "Check VERSION is not stale vs queue", "quality", "check-freshness", "actionlint"] },
"merge": "direct",
"min_gstack_version": "1.95.0.0"
"land": {
"merged_checks": [
"bun run typecheck",
"bun run gen:skill-docs --host all && test -z \"$(git status --porcelain -- . ':(exclude)node_modules')\"",
"bun run scripts/test-free-shards.ts --files-from test/land-merged-checks.txt --wall-timeout 600"
]
},
"min_gstack_version": "1.96.0.0"
}
@@ -0,0 +1 @@
- **gstack's own policy turns on `land.merged_checks`.** When main has moved past a PR's merge base, `land --pin` now runs typecheck, the generated-docs freshness check, and the size and budget guards plus the core of `test:quick` (through the strict free runner, so a test that exits early fails the check) on the PR merged onto main's tip, and lands only when all three pass. This catches the stale-base break from #3886, which pushed `ship/DRIVER.md` past its 12 KB cap on main. `min_gstack_version` moves to 1.96.0.0, the release that added the key. (GST-1332)
+8 -1
View File
@@ -2099,7 +2099,14 @@ the filesystem: a command can still write the checkout's `.git` (the worktree
shares it) and the linked `node_modules`, so pass the flag only for a base
policy and PRs you trust to run. A list such
as typecheck plus the size ratchets takes about two minutes, against a main
merge, a CI round and a new receipt per PR. Without the key, land prints
merge, a CI round and a new receipt per PR. gstack's own policy runs
typecheck, the generated-docs freshness check, and the size and budget guards
plus the core files of `test:quick` through the strict free runner on
`test/land-merged-checks.txt` (`test/ship-driver.test.ts` holds the
`ship/DRIVER.md` cap #3886 broke). Raw `bun test` exits 0 when a test calls
`process.exit(0)` or a listed file is missing; the runner fails both. It
doesn't run `test:quick` itself, because its browser tests find no Chromium
under the throwaway `HOME`. Without the key, land prints
`STALE_BASE: warn … no land.merged_checks configured` and merges the stale
base untested, as it did before the key. Then land runs `gh pr merge
--squash --match-head-commit <pin>` (`--merge` under `history: merge-only`),
+11
View File
@@ -188,6 +188,17 @@ describe("gstack's own .gstack/ship-policy.json", () => {
expect(raw.changelog_fragments.required_checks.filter((n: string) => !jobs.has(n))).toEqual([]);
});
// Value: protects=land.merged_checks on gstack itself (GST-1332): its tests run through the strict free runner on a committed list that keeps the ship/DRIVER.md cap guard (#3886), so an early exit or a missing file fails instead of passing; fails_when=a command goes back to raw bun test (which exits 0 when a test calls process.exit(0) and skips a missing file), test/ship-driver.test.ts leaves the list, or a listed file is gone; why_new=gstack's own policy gained the land key; seam=the policy file and test/land-merged-checks.txt; no_claim=that the commands pass on a merged tree (ship-queue-land-direct covers the engine)
test('land.merged_checks runs its tests through the strict runner on a list that exists and keeps the ship/DRIVER.md cap guard', () => {
const root = path.join(import.meta.dir, '..');
const checks: string[] = JSON.parse(fs.readFileSync(path.join(root, '.gstack', 'ship-policy.json'), 'utf8')).land.merged_checks;
expect(checks.filter(c => /\bbun test\b/.test(c))).toEqual([]);
expect(checks).toContain('bun run scripts/test-free-shards.ts --files-from test/land-merged-checks.txt --wall-timeout 600');
const files = fs.readFileSync(path.join(root, 'test', 'land-merged-checks.txt'), 'utf8').split('\n').filter(Boolean);
expect(files).toContain('test/ship-driver.test.ts');
expect(files.filter(f => !fs.existsSync(path.join(root, f)))).toEqual([]);
});
// Value: protects=the fill rule the coordinator relies on: a train dispatches at 5 READY PRs or one hour after the first READY, whichever comes first
// (2026-10-26: 5 PRs / 3 hours left READY PRs waiting most of a day, so the fill went to 3 PRs / 1 hour; 2026-10-31: Garry's B1 raised the size back to 5, keeping the 1-hour fill); fails_when=the live block drifts back to a larger or slower fill; why_new=the values were unpinned; seam=the policy file; no_claim=fillDue's arithmetic (ship-queue-train-logic)
test('fills a train at 5 READY PRs or one hour after the first READY, whichever comes first', () => {
+16
View File
@@ -0,0 +1,16 @@
test/ship-driver.test.ts
test/skill-md-size-guard.test.ts
test/skill-size-budget.test.ts
test/module-size-ratchet.test.ts
test/context-budget-ratchet.test.ts
test/catalog-budget.test.ts
test/claude-md-size.test.ts
test/parity-suite.test.ts
test/gstack-ship-policy.test.ts
test/strict-output.test.ts
test/gen-skill-docs.test.ts
test/skill-check-driver.test.ts
test/skill-ceo-section-ordering.test.ts
test/qa-functional-observer.test.ts
test/qa-checkpoint-evidence.test.ts
test/test-free-shards-capture.test.ts