@codyswann/lisa 4.87.10 → 4.87.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +2 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +3 -2
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +4 -4
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +1 -1
- package/typescript/copy-overwrite/scripts/check-skipped-required-checks.mjs +146 -38
- package/typescript/create-only/.github/required-checks.json +1 -1
|
@@ -1848,12 +1848,12 @@ function normaliseBaseRef(ref) {
|
|
|
1848
1848
|
* Resolves the branch the pull request under inspection merges INTO.
|
|
1849
1849
|
*
|
|
1850
1850
|
* Most-explicit-first, the same order {@link resolvePullRequestNumber} uses:
|
|
1851
|
-
* an operator's `--base`, then
|
|
1852
|
-
* `
|
|
1853
|
-
*
|
|
1854
|
-
*
|
|
1855
|
-
*
|
|
1856
|
-
*
|
|
1851
|
+
* an operator's `--base`, then current metadata for the inspected PR, then
|
|
1852
|
+
* `GITHUB_BASE_REF` and the event payload's `pull_request.base.ref`. A rerun
|
|
1853
|
+
* replays its old event even after retargeting. The caller supplies metadata
|
|
1854
|
+
* from its existing head observation, so this pure selection adds no API call.
|
|
1855
|
+
* When current metadata is unavailable, the identity-checked event remains a
|
|
1856
|
+
* fallback. Returning null selects the reported union fallback.
|
|
1857
1857
|
*
|
|
1858
1858
|
* The run's own base describes the run's own pull request, and nothing else.
|
|
1859
1859
|
* When `options.pr` names the pull request being inspected, GITHUB_BASE_REF
|
|
@@ -1867,13 +1867,21 @@ function normaliseBaseRef(ref) {
|
|
|
1867
1867
|
*
|
|
1868
1868
|
* @param {ReadonlyArray<string>} argv - CLI arguments
|
|
1869
1869
|
* @param {NodeJS.ProcessEnv} [env] - Environment, injectable for tests
|
|
1870
|
-
* @param {{pr?: string, repo?: string}} [options] -
|
|
1870
|
+
* @param {{pr?: string, repo?: string, currentPullRequest?: object}} [options] - Inspected identity and its current metadata, when available
|
|
1871
1871
|
* @returns {{base: string|null, source: string|null, ignoredEventBase?: string}} The base and where it came from
|
|
1872
1872
|
*/
|
|
1873
1873
|
export function resolveBaseRef(argv, env = process.env, options = {}) {
|
|
1874
1874
|
const explicit = normaliseBaseRef(readFlagValue(argv, "--base"));
|
|
1875
1875
|
if (explicit !== null) return { base: explicit, source: "--base" };
|
|
1876
1876
|
|
|
1877
|
+
if (
|
|
1878
|
+
isInspectedPullRequest(options.currentPullRequest, options.pr, options.repo)
|
|
1879
|
+
) {
|
|
1880
|
+
const current = normaliseBaseRef(options.currentPullRequest.baseRefName);
|
|
1881
|
+
if (current !== null)
|
|
1882
|
+
return { base: current, source: "current PR metadata" };
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1877
1885
|
const eventPath = env.GITHUB_EVENT_PATH;
|
|
1878
1886
|
const payload =
|
|
1879
1887
|
eventPath !== undefined && eventPath !== "" && existsSync(eventPath)
|
|
@@ -1897,6 +1905,34 @@ export function resolveBaseRef(argv, env = process.env, options = {}) {
|
|
|
1897
1905
|
: { base: null, source: null, ignoredEventBase: found.base };
|
|
1898
1906
|
}
|
|
1899
1907
|
|
|
1908
|
+
/**
|
|
1909
|
+
* Match both native metadata identities before trusting its current base.
|
|
1910
|
+
* @param {object|undefined} current - Native PR metadata
|
|
1911
|
+
* @param {string|number|undefined} pr - Inspected PR
|
|
1912
|
+
* @param {string|undefined} repo - Inspected repository
|
|
1913
|
+
* @returns {boolean} Whether this is the requested PR in the requested repo
|
|
1914
|
+
*/
|
|
1915
|
+
function isInspectedPullRequest(current, pr, repo) {
|
|
1916
|
+
if (
|
|
1917
|
+
!current ||
|
|
1918
|
+
pr === undefined ||
|
|
1919
|
+
repo === undefined ||
|
|
1920
|
+
String(current.number) !== String(pr) ||
|
|
1921
|
+
typeof current.url !== "string"
|
|
1922
|
+
)
|
|
1923
|
+
return false;
|
|
1924
|
+
try {
|
|
1925
|
+
const url = new URL(current.url);
|
|
1926
|
+
return (
|
|
1927
|
+
["https:", "http:"].includes(url.protocol) &&
|
|
1928
|
+
url.pathname.replace(/\/$/u, "").toLowerCase() ===
|
|
1929
|
+
`/${repo}/pull/${pr}`.toLowerCase()
|
|
1930
|
+
);
|
|
1931
|
+
} catch {
|
|
1932
|
+
return false;
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1900
1936
|
/**
|
|
1901
1937
|
* True when the inspected repository is the one this run's event belongs to.
|
|
1902
1938
|
*
|
|
@@ -4051,6 +4087,45 @@ export function resolveHeadSha(pr, repo) {
|
|
|
4051
4087
|
}
|
|
4052
4088
|
}
|
|
4053
4089
|
|
|
4090
|
+
/**
|
|
4091
|
+
* Observe head and current base together using the existing PR metadata read.
|
|
4092
|
+
* A failed metadata read retains the old head probe, so an independently
|
|
4093
|
+
* readable head can still use the declared event/union base fallbacks.
|
|
4094
|
+
* @param {string|number} pr - Inspected PR
|
|
4095
|
+
* @param {string|undefined} repo - Inspected repository
|
|
4096
|
+
* @returns {{headSha: string|undefined, repo?: string, pullRequest?: object}} One observation
|
|
4097
|
+
*/
|
|
4098
|
+
function observePullRequest(pr, repo) {
|
|
4099
|
+
const slug = resolveRepoSlug(repo);
|
|
4100
|
+
if (slug === undefined) return { headSha: undefined };
|
|
4101
|
+
try {
|
|
4102
|
+
const current = JSON.parse(
|
|
4103
|
+
boundedExecFileSync(
|
|
4104
|
+
"gh",
|
|
4105
|
+
[
|
|
4106
|
+
"pr",
|
|
4107
|
+
"view",
|
|
4108
|
+
String(pr),
|
|
4109
|
+
"--repo",
|
|
4110
|
+
slug,
|
|
4111
|
+
"--json",
|
|
4112
|
+
"number,url,headRefOid,baseRefName",
|
|
4113
|
+
],
|
|
4114
|
+
{ encoding: "utf8" }
|
|
4115
|
+
)
|
|
4116
|
+
);
|
|
4117
|
+
if (
|
|
4118
|
+
isInspectedPullRequest(current, pr, slug) &&
|
|
4119
|
+
typeof current.headRefOid === "string" &&
|
|
4120
|
+
/^[a-f0-9]{40}$/iu.test(current.headRefOid)
|
|
4121
|
+
)
|
|
4122
|
+
return { headSha: current.headRefOid, repo: slug, pullRequest: current };
|
|
4123
|
+
} catch {
|
|
4124
|
+
// Current metadata is unavailable; preserve the existing head-only probe.
|
|
4125
|
+
}
|
|
4126
|
+
return { headSha: resolveHeadSha(pr, slug), repo: slug };
|
|
4127
|
+
}
|
|
4128
|
+
|
|
4054
4129
|
/**
|
|
4055
4130
|
* How a finding cites the commit its evidence was read at.
|
|
4056
4131
|
*
|
|
@@ -4386,7 +4461,7 @@ function sleepSync(ms) {
|
|
|
4386
4461
|
* @param {object} declaration - The per-repo declaration
|
|
4387
4462
|
* @param {string|number} pr - Pull request number
|
|
4388
4463
|
* @param {string|undefined} repo - `OWNER/NAME`, or undefined
|
|
4389
|
-
* @param {{timeoutSeconds?: number, intervalSeconds?: number, fetch?: Function, now?: Function, sleep?: Function, headSha?: Function, requiredSet?: object, substitutes?: Set<string>, substituteHead?: string}} [options] -
|
|
4464
|
+
* @param {{timeoutSeconds?: number, intervalSeconds?: number, fetch?: Function, now?: Function, sleep?: Function, headSha?: Function, observe?: Function, initialObservation?: object, requiredSet?: object, requiredSetFor?: Function, substitutes?: Set<string>, substituteHead?: string}} [options] -
|
|
4390
4465
|
* Injection seams; the suite drives the whole loop through them so nothing
|
|
4391
4466
|
* here has to sleep in real time
|
|
4392
4467
|
* @returns {{checks: object[], settled: boolean, headSha: string|undefined, registration: object}} Rows, reviewer completion, head and required-registration observations
|
|
@@ -4411,16 +4486,20 @@ export function fetchSettledChecks(declaration, pr, repo, options = {}) {
|
|
|
4411
4486
|
);
|
|
4412
4487
|
});
|
|
4413
4488
|
const resolveHead = options.headSha ?? resolveHeadSha;
|
|
4489
|
+
const observe =
|
|
4490
|
+
options.observe ??
|
|
4491
|
+
((request, slug) => ({ headSha: resolveHead(request, slug) }));
|
|
4414
4492
|
const clock = options.now ?? Date.now;
|
|
4415
4493
|
const sleep = options.sleep ?? sleepSync;
|
|
4416
4494
|
const started = clock();
|
|
4417
4495
|
const deadline = started + timeoutMs;
|
|
4418
|
-
const
|
|
4496
|
+
const defaultRequiredSet =
|
|
4419
4497
|
options.requiredSet ??
|
|
4420
4498
|
selectRequiredContexts(declaration, { base: null, source: null });
|
|
4421
|
-
const
|
|
4422
|
-
|
|
4423
|
-
|
|
4499
|
+
const selectSet = options.requiredSetFor ?? (() => defaultRequiredSet);
|
|
4500
|
+
const missing = observed =>
|
|
4501
|
+
observed.requiredSet.contexts.filter(
|
|
4502
|
+
name => !observed.checks.some(check => check.name === name)
|
|
4424
4503
|
);
|
|
4425
4504
|
// A substitute is useful only at the head it was actually read for. Pending
|
|
4426
4505
|
// rows still wait, and a missing required reviewer still needs a real row.
|
|
@@ -4435,29 +4514,39 @@ export function fetchSettledChecks(declaration, pr, repo, options = {}) {
|
|
|
4435
4514
|
);
|
|
4436
4515
|
});
|
|
4437
4516
|
|
|
4438
|
-
// Bracket
|
|
4439
|
-
//
|
|
4440
|
-
//
|
|
4441
|
-
|
|
4442
|
-
// were never evaluated. Matching observations on both sides bind the roster
|
|
4443
|
-
// to that head; a mismatch is discarded and re-read, never reported.
|
|
4517
|
+
// Bracket checks with coherent head/base observations. The early substitute
|
|
4518
|
+
// read can supply the first observation without another metadata request.
|
|
4519
|
+
// A push or retarget during the read is discarded within this same deadline.
|
|
4520
|
+
let initial = options.initialObservation;
|
|
4444
4521
|
const snapshot = () => {
|
|
4445
|
-
const before =
|
|
4446
|
-
|
|
4522
|
+
const before = initial?.headSha === undefined ? observe(pr, repo) : initial;
|
|
4523
|
+
initial = undefined;
|
|
4524
|
+
const beforeSet = selectSet(before);
|
|
4525
|
+
if (before.headSha === undefined) {
|
|
4447
4526
|
return {
|
|
4448
4527
|
checks: [],
|
|
4449
4528
|
headSha: undefined,
|
|
4450
4529
|
stable: false,
|
|
4451
4530
|
after: undefined,
|
|
4531
|
+
requiredSet: beforeSet,
|
|
4532
|
+
baseBefore: beforeSet.base,
|
|
4533
|
+
baseAfter: undefined,
|
|
4452
4534
|
};
|
|
4453
4535
|
}
|
|
4454
|
-
const checks = read(pr, repo, before);
|
|
4455
|
-
const after =
|
|
4536
|
+
const checks = read(pr, repo, before.headSha);
|
|
4537
|
+
const after = observe(pr, repo);
|
|
4538
|
+
const afterSet = selectSet(after);
|
|
4456
4539
|
return {
|
|
4457
4540
|
checks,
|
|
4458
|
-
headSha: before,
|
|
4459
|
-
stable:
|
|
4460
|
-
|
|
4541
|
+
headSha: before.headSha,
|
|
4542
|
+
stable:
|
|
4543
|
+
after.headSha !== undefined &&
|
|
4544
|
+
before.headSha === after.headSha &&
|
|
4545
|
+
beforeSet.base === afterSet.base,
|
|
4546
|
+
after: after.headSha,
|
|
4547
|
+
requiredSet: afterSet,
|
|
4548
|
+
baseBefore: beforeSet.base,
|
|
4549
|
+
baseAfter: afterSet.base,
|
|
4461
4550
|
};
|
|
4462
4551
|
};
|
|
4463
4552
|
|
|
@@ -4465,20 +4554,24 @@ export function fetchSettledChecks(declaration, pr, repo, options = {}) {
|
|
|
4465
4554
|
while (
|
|
4466
4555
|
(!observed.stable ||
|
|
4467
4556
|
!evidenceReady(observed) ||
|
|
4468
|
-
missing(observed
|
|
4557
|
+
missing(observed).length > 0) &&
|
|
4469
4558
|
clock() < deadline
|
|
4470
4559
|
) {
|
|
4471
4560
|
sleep(Math.min(intervalMs, deadline - clock()));
|
|
4472
4561
|
observed = snapshot();
|
|
4473
4562
|
}
|
|
4474
4563
|
if (!observed.stable) {
|
|
4564
|
+
if (observed.headSha !== undefined && observed.headSha === observed.after)
|
|
4565
|
+
throw new Error(
|
|
4566
|
+
`check-skipped-required-checks: the selected pull request base changed while its checks were being read (${observed.baseBefore ?? "unresolved"} -> ${observed.baseAfter ?? "unresolved"}). Refusing to judge checks against another base; re-read the pull request after retargeting settles.`
|
|
4567
|
+
);
|
|
4475
4568
|
throw new Error(
|
|
4476
4569
|
`check-skipped-required-checks: the pull request head changed while its checks were being read (${observed.headSha ?? "unresolved"} -> ${observed.after ?? "unresolved"}). Refusing to attach one commit's review evidence to another; re-read the pull request after the push settles.`
|
|
4477
4570
|
);
|
|
4478
4571
|
}
|
|
4479
4572
|
const elapsedSeconds = Math.max(0, clock() - started) / 1000;
|
|
4480
|
-
const unregistered = missing(observed
|
|
4481
|
-
const total = requiredSet.contexts.length;
|
|
4573
|
+
const unregistered = missing(observed);
|
|
4574
|
+
const total = observed.requiredSet.contexts.length;
|
|
4482
4575
|
const present = total - unregistered.length;
|
|
4483
4576
|
const expired = unregistered.length > 0;
|
|
4484
4577
|
const settled = checksSettled(declaration, observed.checks);
|
|
@@ -4506,6 +4599,7 @@ export function fetchSettledChecks(declaration, pr, repo, options = {}) {
|
|
|
4506
4599
|
headSha: observed.headSha,
|
|
4507
4600
|
registration,
|
|
4508
4601
|
evidence,
|
|
4602
|
+
requiredSet: observed.requiredSet,
|
|
4509
4603
|
};
|
|
4510
4604
|
}
|
|
4511
4605
|
|
|
@@ -4701,7 +4795,7 @@ function readSecondsFlag(argv, name, fallback) {
|
|
|
4701
4795
|
*
|
|
4702
4796
|
* @param {ReadonlyArray<string>} argv - CLI arguments
|
|
4703
4797
|
* @param {object} declaration - The per-repo declaration
|
|
4704
|
-
* @param {{trustRequiredContexts?: boolean, env?: NodeJS.ProcessEnv, fetch?: Function, probeBranch?: Function, now?: Function, sleep?: Function, headSha?: Function, reviewActivity?: Function}} [options] -
|
|
4798
|
+
* @param {{trustRequiredContexts?: boolean, env?: NodeJS.ProcessEnv, fetch?: Function, probeBranch?: Function, now?: Function, sleep?: Function, headSha?: Function, observe?: Function, reviewActivity?: Function}} [options] -
|
|
4705
4799
|
* Injection seams for the suite
|
|
4706
4800
|
* @returns {{pr: string|undefined, prSource: string|null, headSha: string|undefined, checked: number, violations: object[], settled: boolean, refusal: {kind: string, reason: string}|null}|undefined} The inspection
|
|
4707
4801
|
*/
|
|
@@ -4755,19 +4849,30 @@ export function inspectVacuity(argv, declaration, options = {}) {
|
|
|
4755
4849
|
const declaredReviewers = Object.keys(
|
|
4756
4850
|
declaration.evidence_bearing_checks ?? {}
|
|
4757
4851
|
);
|
|
4758
|
-
const
|
|
4759
|
-
|
|
4852
|
+
const injectedHead = options.headSha;
|
|
4853
|
+
const observe =
|
|
4854
|
+
options.observe ??
|
|
4855
|
+
(injectedHead
|
|
4856
|
+
? (request, slug) => ({ headSha: injectedHead(request, slug) })
|
|
4857
|
+
: observePullRequest);
|
|
4858
|
+
const earlyObservation = requireReviewEvidence
|
|
4859
|
+
? observe(pr, repo)
|
|
4760
4860
|
: undefined;
|
|
4861
|
+
const earlyHead = earlyObservation?.headSha;
|
|
4761
4862
|
const earlySubstitutes = readSubstitutes(earlyHead);
|
|
4762
4863
|
const allStoodIn =
|
|
4763
4864
|
declaredReviewers.length > 0 &&
|
|
4764
4865
|
declaredReviewers.every(name => earlySubstitutes.has(name));
|
|
4765
|
-
//
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4866
|
+
// Registration and absence share the selection returned with stable checks.
|
|
4867
|
+
const requiredSetFor = observed =>
|
|
4868
|
+
selectRequiredContexts(
|
|
4869
|
+
declaration,
|
|
4870
|
+
resolveBaseRef(argv, options.env ?? process.env, {
|
|
4871
|
+
pr,
|
|
4872
|
+
repo: repo ?? observed.repo,
|
|
4873
|
+
currentPullRequest: observed.pullRequest,
|
|
4874
|
+
})
|
|
4875
|
+
);
|
|
4771
4876
|
let read;
|
|
4772
4877
|
try {
|
|
4773
4878
|
read = fetchSettledChecks(declaration, pr, repo, {
|
|
@@ -4785,13 +4890,16 @@ export function inspectVacuity(argv, declaration, options = {}) {
|
|
|
4785
4890
|
now: options.now,
|
|
4786
4891
|
sleep: options.sleep,
|
|
4787
4892
|
headSha: options.headSha,
|
|
4788
|
-
|
|
4893
|
+
observe,
|
|
4894
|
+
initialObservation: earlyObservation,
|
|
4895
|
+
requiredSetFor,
|
|
4789
4896
|
substitutes: allStoodIn ? earlySubstitutes : undefined,
|
|
4790
4897
|
substituteHead: earlyHead,
|
|
4791
4898
|
});
|
|
4792
4899
|
} catch (error) {
|
|
4793
4900
|
return refused(vacuityRefusal({ declaration, pr, error }));
|
|
4794
4901
|
}
|
|
4902
|
+
const requiredSet = read.requiredSet;
|
|
4795
4903
|
|
|
4796
4904
|
const refusal = vacuityRefusal({ declaration, pr, checks: read.checks });
|
|
4797
4905
|
if (refusal !== null) {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"IT REFUSES RATHER THAN REPORTING AN EMPTY INSPECTION. An unresolvable pull request, a `gh` it could not read, a roster with no checks in it, or an empty `evidence_bearing_checks` all print the same \"nothing vacuous here\" that a genuinely clean run prints — so the guard fails instead and names which of the four it hit (`vacuity_pr_unresolved`, `vacuity_checks_unreadable`, `vacuity_no_checks_reported`, `vacuity_none_declared`). A refusal is NOT a finding: NOBODY LOOKED and THE REVIEW WAS FAKE are opposite facts, and a single red job would otherwise report them identically.",
|
|
19
19
|
"`evidence_bearing_checks` names the checks whose GREEN is supposed to mean something reviewed the code. Use `{}` to accept the shipped description vocabulary, or add `proof` / `no_work` arrays to extend it — extensions ADD to the defaults, they do not replace them. Undeclared checks are never examined, because most CI jobs ship an empty description and flagging them all would bury the one finding that matters.",
|
|
20
20
|
"This arm REPORTS AND NEVER BLOCKS, in every enforcement mode. A review bot can go hollow because an org-wide SPENDING CAP was hit, and a gate that reddens every PR on a billing state is worse than the one it criticises. What it changes is what you may CLAIM: a PR carrying a `vacuous_required_check` finding has not been shown to be reviewed, so do not record it as reviewed. Once you have made the governance call, `--fail-on-vacuous` is the supported way to ask for an exit code — add it to the command in `review-evidence.yml`, instead of writing a wrapper that reads `--json`.",
|
|
21
|
-
"PER-BRANCH SETS (CodySwannGT/lisa#4484). `required_contexts` is the UNION across every protected branch, which is the wrong set for judging which required contexts did NOT REPORT on one pull request: a context only `dev` requires was reported absent on every staging-base pull request. Optionally add `required_contexts_by_branch: { \"<branch>\": [ ...contexts ] }`, each set transcribed byte for byte from `gh api repos/OWNER/NAME/rules/branches/<branch> --jq '.[] | select(.type==\"required_status_checks\") | .parameters.required_status_checks[].context'` (read access only). The absent arm
|
|
21
|
+
"PER-BRANCH SETS (CodySwannGT/lisa#4484). `required_contexts` is the UNION across every protected branch, which is the wrong set for judging which required contexts did NOT REPORT on one pull request: a context only `dev` requires was reported absent on every staging-base pull request. Optionally add `required_contexts_by_branch: { \"<branch>\": [ ...contexts ] }`, each set transcribed byte for byte from `gh api repos/OWNER/NAME/rules/branches/<branch> --jq '.[] | select(.type==\"required_status_checks\") | .parameters.required_status_checks[].context'` (read access only). The absent arm judges the PR against its current base (`--base`, else current metadata from the existing PR head read). If current metadata is unreadable it uses only a matching PR/repository event (`GITHUB_BASE_REF`, else `pull_request.base.ref`). A rerun replays the old event, so matching identity alone does not establish the current base. Head/base observations bracket each check read; a retarget retries within the same settlement deadline, and registration and absence share the resulting selection. Without a set for that base it falls back to the union — same findings as before — and says so as `required_contexts_branch_fallback`; every run prints which set it used. Every per-branch context must also appear in `required_contexts`, and the one `baseline_fetched_at` stamp covers both."
|
|
22
22
|
],
|
|
23
23
|
"enforcement": "warn",
|
|
24
24
|
"ruleset": {
|