fix(pregate): no empty no-lane line on mapped runs; trace [] refusals; absent lane flag stays strict (GST-775 review)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-11-01 13:04:15 +00:00
1 parent 9e8326f766
commit f2400e791b
4 files changed
+14 -2

No files matched your search

+2 -1
View File
@@ -353,7 +353,8 @@ function unfinished(ctx: PregateContext, r: Awaited<ReturnType<typeof runLocal>>
type NoLaneMode = 'no-policy' | 'warned' | 'strict';
function describe(ctx: PregateContext, sel: Selection, mode: NoLaneMode): string[] {
const lines = mode === 'warned' ? sel.noLane.map(f => `WARN lanes — ${f} has no test lane (warn: ["lanes"] in ${ctx.configLabel}; the selected tests are still judged)`)
const lines = !sel.noLane.length ? []
: mode === 'warned' ? sel.noLane.map(f => `WARN lanes — ${f} has no test lane (warn: ["lanes"] in ${ctx.configLabel}; the selected tests are still judged)`)
: mode === 'strict' ? sel.noLane.map(f => `FAIL lanes — ${f} has no test lane`)
: ctx.configKind === 'none' ? [`no policy: ${sel.noLane.join(' ')} have no test lane (a warning under no policy; the starter below maps them)`]
: [`no lane policy: ${sel.noLane.join(' ')} have no test lane (a warning while ${ctx.configLabel} declares no dependencies, empty_lanes, selection or local; the starter below maps them)`];
+1 -1
View File
@@ -247,7 +247,7 @@ export function buildContext(o: BuildContextOptions): ContextLoad {
return {
ctx: {
repoRoot: o.repoRoot, base, baseRef, baseSha: baseSha.out, mergeBase, head, wtree, touched: touchedFiles(o.repoRoot, mergeBase),
config, configLabel: configLoad.label, configKind: configLoad.kind, policyDeclaresLanes: configLoad.declaresLanes === true, scratch, configFile: configLoad.kind === 'user' && o.userConfigPath ? o.userConfigPath : PREGATE_CONFIG_PATH, ...(configLoad.digest ? { configDigest: configLoad.digest } : {}), ...(absentUserPolicy ? { absentUserPolicy } : {}), registry: registryLoad.registry as Registry, registryLabel: registryLoad.source.label,
config, configLabel: configLoad.label, configKind: configLoad.kind, policyDeclaresLanes: configLoad.declaresLanes !== false, scratch, configFile: configLoad.kind === 'user' && o.userConfigPath ? o.userConfigPath : PREGATE_CONFIG_PATH, ...(configLoad.digest ? { configDigest: configLoad.digest } : {}), ...(absentUserPolicy ? { absentUserPolicy } : {}), registry: registryLoad.registry as Registry, registryLabel: registryLoad.source.label,
lanes, platform, allowRepoCommands: o.allowRepoCommands, timeoutMs: o.timeoutMs ?? (config.timeout_s ?? 600) * 1000, timeoutSource: o.timeoutMs !== undefined ? '--timeout' : config.timeout_s ? `timeout_s from ${configLoad.label}` : 'the 600 s default',
stallTimeoutMs: o.stallTimeoutMs ?? (config.stall_timeout_s ?? DEFAULT_STALL_TIMEOUT_S) * 1000,
progress: o.progress ?? (line => process.stderr.write(`${line}\n`)),
+1
View File
@@ -230,6 +230,7 @@ export function selectLanes(ctx: PregateContext): Selection {
if (m.declaredNone) {
const r = gone.includes(file) ? removedPath(ctx, graph, goneSet, file) : null;
if (r && 'removed' in r) { waive(file, r); continue; }
if (r) provenance.push(`${file}: ${r.refused}; cleared by its [] declaration`);
if (isDocsEmptyLane(file, ctx.config.empty_lanes ?? [])) emptyLane.push(file);
continue;
}
+10
View File
@@ -65,6 +65,16 @@ describe('a policy that declares no lanes keeps the no-policy lane verdicts (GST
expect(r.ran).toContain('test/util.test.js');
});
// Value: protects=a fully mapped change prints no empty "have no test lane" line under no policy or a lane-less one; fails_when=the
// no-lane line is rendered for an empty list; why_new=the mode switch is new; seam=none; no_claim=none
test.each([['no policy', null], ['timeout-only', { $schema: SCHEMA, timeout_s: 1800 }]])('%s: a fully mapped change passes with no no-lane line', (_name, policy) => {
const repo = fixture({ pregate: policy, baseFiles: NO_PLATFORM_LANE });
commit(repo, { 'lib/util.js': 'exports.add = (a, b) => b + a;\n' });
const r = lanes(repo);
expect([r.status, r.row.status]).toEqual([EXIT.ok, 'pass']);
expect(r.lines.some(l => l.includes('have no test lane'))).toBe(false);
});
// Value: protects=the starter names the policy that exists instead of claiming there is none; fails_when=the starter header says
// "no .gstack/pregate.json" while one is on the base; why_new=new wording; seam=none; no_claim=none
test('the starter says the active policy declares no lanes, not that there is no policy', () => {