@codyswann/lisa 4.84.1 → 4.84.3
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 +10 -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.js +1 -1
- package/dist/opencode/plugin-templates/lisa-block-managed-file-edits.ts +11 -4
- package/dist/opencode/plugin-templates/lisa-block-no-verify.ts +12 -4
- package/dist/opencode/plugin-templates/lisa-discharge-work-item-gates.ts +10 -4
- package/dist/opencode/plugin-templates/lisa-parity-safety-net.ts +11 -4
- 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 +115 -35
|
@@ -2129,14 +2129,73 @@ export const REVIEW_GATE_CONDITIONS = Object.freeze({
|
|
|
2129
2129
|
pending: "pending",
|
|
2130
2130
|
unrecognised: "unrecognised",
|
|
2131
2131
|
undetermined: "undetermined",
|
|
2132
|
-
// A SATISFYING condition
|
|
2133
|
-
//
|
|
2134
|
-
//
|
|
2135
|
-
//
|
|
2136
|
-
// `objected` — a substitute does not overrule a review that ran and said no.
|
|
2132
|
+
// A SATISFYING condition: the reviewer could not or did not review this
|
|
2133
|
+
// head, and a writer posted a local adversarial review for it in its place.
|
|
2134
|
+
// See `substitutable` for exactly which readings qualify. Never from
|
|
2135
|
+
// `objected` or a review still in flight.
|
|
2137
2136
|
substituted: "substituted",
|
|
2138
2137
|
});
|
|
2139
2138
|
|
|
2139
|
+
/**
|
|
2140
|
+
* Review conditions where the reviewer FINISHED without reviewing, so a
|
|
2141
|
+
* writer's substitute may stand in.
|
|
2142
|
+
*
|
|
2143
|
+
* WHY WAIVERS QUALIFY. A rate limit or a vendor skip is a billing or
|
|
2144
|
+
* entitlement state, not a finding, and it must not pull a human into every
|
|
2145
|
+
* merge. Standing in for it is safe because the two things a substitute must
|
|
2146
|
+
* never hide are read from somewhere else: an objection from the review
|
|
2147
|
+
* OBJECTS at this head ({@link readObjectionAtHead}), which outranks every
|
|
2148
|
+
* state in the published verdict; and unresolved review threads, which the
|
|
2149
|
+
* branch ruleset blocks on directly. `unrecognised` qualifies for the same
|
|
2150
|
+
* reason — a green status whose sentence nobody classified carries no
|
|
2151
|
+
* objection the review objects would not also carry.
|
|
2152
|
+
*/
|
|
2153
|
+
const SUBSTITUTABLE_REPORTED_CONDITIONS = Object.freeze(
|
|
2154
|
+
new Set([
|
|
2155
|
+
REVIEW_GATE_CONDITIONS.waived,
|
|
2156
|
+
REVIEW_GATE_CONDITIONS.waivedWithReview,
|
|
2157
|
+
REVIEW_GATE_CONDITIONS.unrecognised,
|
|
2158
|
+
])
|
|
2159
|
+
);
|
|
2160
|
+
|
|
2161
|
+
/**
|
|
2162
|
+
* Whether a substitute may stand in for one reviewer's reading.
|
|
2163
|
+
*
|
|
2164
|
+
* A reviewer that posted NO row qualifies whatever the wait concluded. A
|
|
2165
|
+
* reviewer that posted a row qualifies only when that row is SETTLED and says
|
|
2166
|
+
* it did not review. `undetermined` with a row present is a review STILL
|
|
2167
|
+
* RUNNING once the wait expires, and a substitute must not race a review in
|
|
2168
|
+
* flight whose objection would land after the merge. `objected` and `pending`
|
|
2169
|
+
* never qualify.
|
|
2170
|
+
*
|
|
2171
|
+
* EVERY substitute — for a reviewer that spoke or one that never posted —
|
|
2172
|
+
* also requires the pull request's review surface to have been READ and to
|
|
2173
|
+
* show no objection: no CHANGES_REQUESTED decision and no unresolved thread.
|
|
2174
|
+
* The review objects at head catch only a CHANGES_REQUESTED on this commit; a
|
|
2175
|
+
* COMMENTED review with open threads, or an objection on an earlier push, is
|
|
2176
|
+
* visible only on the surface. A surface that could not be read is not a clean
|
|
2177
|
+
* one, so it substitutes nothing.
|
|
2178
|
+
*
|
|
2179
|
+
* KNOWN DEPENDENCY: GitHub fills `reviewDecision` only where the repository
|
|
2180
|
+
* requires reviews. Without that rule an earlier push's CHANGES_REQUESTED is
|
|
2181
|
+
* caught only if it left an unresolved thread, which reviewers that request
|
|
2182
|
+
* changes ordinarily do.
|
|
2183
|
+
*
|
|
2184
|
+
* @param {object|undefined} found - The reviewer's check row, if it posted one
|
|
2185
|
+
* @param {string} condition - The condition its reading produced
|
|
2186
|
+
* @param {{read: boolean, present: boolean, objected: boolean}|undefined} activity - What the review surface showed, if it was read
|
|
2187
|
+
* @returns {boolean} Whether a substitute may stand in
|
|
2188
|
+
*/
|
|
2189
|
+
function substitutable(found, condition, activity) {
|
|
2190
|
+
const surfaceClean =
|
|
2191
|
+
activity !== undefined &&
|
|
2192
|
+
activity.read === true &&
|
|
2193
|
+
activity.objected !== true;
|
|
2194
|
+
if (!surfaceClean) return false;
|
|
2195
|
+
if (found === undefined) return true;
|
|
2196
|
+
return SUBSTITUTABLE_REPORTED_CONDITIONS.has(condition);
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2140
2199
|
/**
|
|
2141
2200
|
* What the pull request's OWN review surface says, independent of any check.
|
|
2142
2201
|
*
|
|
@@ -2506,15 +2565,14 @@ export function evaluateReviewGate(declaration, checks, options = {}) {
|
|
|
2506
2565
|
},
|
|
2507
2566
|
vocabulary
|
|
2508
2567
|
);
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
// merge. One that is pending, said something unrecognised, or objected
|
|
2514
|
-
// has spoken, and a substitute does not get to overrule it.
|
|
2515
|
-
if (found === undefined && options.substitutes?.has(name) === true) {
|
|
2568
|
+
if (
|
|
2569
|
+
options.substitutes?.has(name) === true &&
|
|
2570
|
+
substitutable(found, verdict.condition, options.reviewActivity)
|
|
2571
|
+
) {
|
|
2516
2572
|
states[name] = REVIEW_GATE_STATES.satisfied;
|
|
2517
2573
|
conditions[name] = REVIEW_GATE_CONDITIONS.substituted;
|
|
2574
|
+
if (found !== undefined)
|
|
2575
|
+
descriptions[name] = String(found.description ?? "");
|
|
2518
2576
|
continue;
|
|
2519
2577
|
}
|
|
2520
2578
|
states[name] = verdict.state;
|
|
@@ -3204,7 +3262,10 @@ export function reviewGateVerdict(reading = {}) {
|
|
|
3204
3262
|
*/
|
|
3205
3263
|
const quote = name => {
|
|
3206
3264
|
if (conditions[name] === REVIEW_GATE_CONDITIONS.substituted) {
|
|
3207
|
-
|
|
3265
|
+
const said = Object.hasOwn(descriptions, name)
|
|
3266
|
+
? `reported ${JSON.stringify(descriptions[name])} without reviewing`
|
|
3267
|
+
: "posted NO review status";
|
|
3268
|
+
return `${name} ${said}; a writer's ${REVIEW_SUBSTITUTE_MARKER} local adversarial review stands in for it at this head`;
|
|
3208
3269
|
}
|
|
3209
3270
|
if (conditions[name] === REVIEW_GATE_CONDITIONS.undetermined) {
|
|
3210
3271
|
return `${name} had not settled when the gate's wait EXPIRED — not observed to be unreviewed`;
|
|
@@ -3299,7 +3360,7 @@ export function reviewGateVerdict(reading = {}) {
|
|
|
3299
3360
|
verdict: REVIEW_GATE_STATES.waived,
|
|
3300
3361
|
conclusion: REVIEW_VERDICT_CONCLUSIONS.waived,
|
|
3301
3362
|
title: fitTitle(
|
|
3302
|
-
`CARRIED UNREVIEWED — this pull request's own review ran, but the work it carries was not reviewed with it${suffix}`
|
|
3363
|
+
`CARRIED UNREVIEWED — this pull request's own ${names.some(name => conditions[name] === REVIEW_GATE_CONDITIONS.substituted) ? "head was covered by a local adversarial review standing in for the reviewer" : "review ran"}, but the work it carries was not reviewed with it${suffix}`
|
|
3303
3364
|
),
|
|
3304
3365
|
};
|
|
3305
3366
|
}
|
|
@@ -3315,7 +3376,7 @@ export function reviewGateVerdict(reading = {}) {
|
|
|
3315
3376
|
verdict: REVIEW_GATE_STATES.waived,
|
|
3316
3377
|
conclusion: REVIEW_VERDICT_CONCLUSIONS.waived,
|
|
3317
3378
|
title: fitTitle(
|
|
3318
|
-
|
|
3379
|
+
`${names.some(name => conditions[name] === REVIEW_GATE_CONDITIONS.substituted) ? "SUBSTITUTED, OBJECTION STANDING UNKNOWN — a local adversarial review stood in" : "REVIEWED, OBJECTION STANDING UNKNOWN — the review ran"}, and whether a reviewer requested changes at this head could not be read: ${names.map(quote).join("; ")}${suffix}`
|
|
3319
3380
|
),
|
|
3320
3381
|
};
|
|
3321
3382
|
}
|
|
@@ -4525,23 +4586,38 @@ export function inspectVacuity(argv, declaration, options = {}) {
|
|
|
4525
4586
|
? earlySubstitutes
|
|
4526
4587
|
: readSubstitutes(read.headSha),
|
|
4527
4588
|
};
|
|
4528
|
-
// TWO PASSES, AND THE SECOND IS PAID FOR ONLY BY A WAIVER
|
|
4529
|
-
// surface is read exactly when
|
|
4530
|
-
//
|
|
4531
|
-
// `unrecognised` and `undetermined` all reach the same
|
|
4532
|
-
//
|
|
4533
|
-
// work. Same shape, and the same
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
:
|
|
4589
|
+
// TWO PASSES, AND THE SECOND IS PAID FOR ONLY BY A WAIVER OR A SUBSTITUTE
|
|
4590
|
+
// (#3706, #4532). The review surface is read exactly when one of the two is
|
|
4591
|
+
// on the table, the only inputs whose verdict it can change: `satisfied`,
|
|
4592
|
+
// `absent`, `pending`, `unrecognised` and `undetermined` all reach the same
|
|
4593
|
+
// answer without it when nobody stood in, and making them pay a network call
|
|
4594
|
+
// would put a new failure mode on paths that work. Same shape, and the same
|
|
4595
|
+
// reason, as the waive-rate sample below.
|
|
4596
|
+
//
|
|
4597
|
+
// The trigger is decided WITHOUT substitutes. A substitute turns a waived
|
|
4598
|
+
// row satisfied, and deciding on that would skip the very read that finds an
|
|
4599
|
+
// objection hidden inside a waiver. And ANY substitute pays for the read on
|
|
4600
|
+
// its own, because standing in — for a reviewer that spoke or one that never
|
|
4601
|
+
// posted — requires the surface to show no objection: an unresolved thread,
|
|
4602
|
+
// or a CHANGES_REQUESTED from an earlier push, is visible only there.
|
|
4603
|
+
const unsubstituted = evaluateReviewGate(declaration, read.checks, {
|
|
4604
|
+
...gateOptions,
|
|
4605
|
+
substitutes: undefined,
|
|
4606
|
+
});
|
|
4607
|
+
const anyStandIn = Object.keys(unsubstituted.conditions).some(name =>
|
|
4608
|
+
gateOptions.substitutes.has(name)
|
|
4609
|
+
);
|
|
4610
|
+
const gate =
|
|
4611
|
+
Object.values(unsubstituted.states).includes(REVIEW_GATE_STATES.waived) ||
|
|
4612
|
+
anyStandIn
|
|
4613
|
+
? evaluateReviewGate(declaration, read.checks, {
|
|
4614
|
+
...gateOptions,
|
|
4615
|
+
reviewActivity: (options.reviewActivity ?? fetchReviewActivity)(
|
|
4616
|
+
pr,
|
|
4617
|
+
repo
|
|
4618
|
+
),
|
|
4619
|
+
})
|
|
4620
|
+
: evaluateReviewGate(declaration, read.checks, gateOptions);
|
|
4545
4621
|
// #3658. Everything above judged ONE commit — this pull request's head — and
|
|
4546
4622
|
// that is the one commit a batch integration pull request does not speak for.
|
|
4547
4623
|
// Armed by the same flag as the gate itself, because this IS the gate,
|
|
@@ -4578,12 +4654,16 @@ export function inspectVacuity(argv, declaration, options = {}) {
|
|
|
4578
4654
|
headSha: read.headSha,
|
|
4579
4655
|
checked: evaluated.checked,
|
|
4580
4656
|
violations: [
|
|
4581
|
-
// "Did not report… NOBODY LOOKED"
|
|
4582
|
-
//
|
|
4657
|
+
// "Did not report… NOBODY LOOKED" and "reported green having reviewed
|
|
4658
|
+
// nothing" are both answered once a writer's substitute stands in for
|
|
4659
|
+
// that exact check at this head, so neither is repeated — and the
|
|
4660
|
+
// vacuous one would otherwise still fail the job under
|
|
4661
|
+
// `--fail-on-vacuous` while the verdict reads SUBSTITUTED.
|
|
4583
4662
|
...evaluated.violations.filter(
|
|
4584
4663
|
violation =>
|
|
4585
4664
|
!(
|
|
4586
|
-
violation.kind === VIOLATIONS.unproven
|
|
4665
|
+
(violation.kind === VIOLATIONS.unproven ||
|
|
4666
|
+
violation.kind === VIOLATIONS.vacuous) &&
|
|
4587
4667
|
gate.conditions[violation.token] ===
|
|
4588
4668
|
REVIEW_GATE_CONDITIONS.substituted
|
|
4589
4669
|
)
|