@codyswann/lisa 4.87.11 → 4.87.12

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.
Files changed (84) hide show
  1. package/all/copy-overwrite/scripts/review-evidence-event.mjs +202 -0
  2. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  3. package/dist/core/lisa-owned-hash-ledger.js +8 -0
  4. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  5. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  6. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  7. package/dist/core/upstream-evidence-manifest.js +10 -5
  8. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  9. package/package.json +4 -4
  10. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  11. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  12. package/plugins/lisa-agy/plugin.json +1 -1
  13. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  14. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  15. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  16. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-cdk-devin/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-cdk-devin/.devin-plugin/plugin.json +1 -1
  20. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-devin/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-devin/.devin-plugin/plugin.json +1 -1
  24. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  26. package/plugins/lisa-expo-agy/plugin.json +1 -1
  27. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-expo-devin/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-expo-devin/.devin-plugin/plugin.json +1 -1
  31. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  33. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  34. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-harper-fabric-devin/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-harper-fabric-devin/.devin-plugin/plugin.json +1 -1
  38. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  40. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  41. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-nestjs-devin/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-nestjs-devin/.devin-plugin/plugin.json +1 -1
  45. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  47. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  48. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-openclaw-devin/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-openclaw-devin/.devin-plugin/plugin.json +1 -1
  52. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  54. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  55. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-phaser-devin/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-phaser-devin/.devin-plugin/plugin.json +1 -1
  59. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  61. package/plugins/lisa-rails-agy/plugin.json +1 -1
  62. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-rails-devin/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-rails-devin/.devin-plugin/plugin.json +1 -1
  66. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  68. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  69. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-typescript-devin/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-typescript-devin/.devin-plugin/plugin.json +1 -1
  73. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  75. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  76. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-wiki-devin/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +1 -1
  80. package/scripts/two-channel-couplings.json +1 -1
  81. package/typescript/copy-overwrite/.prettierignore +1 -0
  82. package/typescript/copy-overwrite/scripts/check-skipped-required-checks.mjs +52 -5
  83. package/typescript/create-only/.github/required-checks.json +1 -0
  84. package/typescript/create-only/.github/workflows/review-evidence.yml +43 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.87.11",
3
+ "version": "4.87.12",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.87.11",
3
+ "version": "4.87.12",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.87.11",
3
+ "version": "4.87.12",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.87.11",
3
+ "version": "4.87.12",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.87.11",
3
+ "version": "4.87.12",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -122,7 +122,7 @@
122
122
  "workflows": 26,
123
123
  "steps": 823,
124
124
  "couplings": 40,
125
- "inventory": 207
125
+ "inventory": 208
126
126
  },
127
127
  "counts": {
128
128
  "package-backed": 11,
@@ -75,6 +75,7 @@ scripts/check-skipped-required-checks.mjs
75
75
  scripts/check-state-classification.mjs
76
76
  scripts/check-third-party-action-pins.mjs
77
77
  scripts/check-third-party-review-evidence.mjs
78
+ scripts/review-evidence-event.mjs
78
79
  scripts/check-threshold-ratchet.mjs
79
80
  scripts/check-verification-coverage.mjs
80
81
  scripts/check-workflow-load-failures.mjs
@@ -1033,9 +1033,48 @@ export function loadDeclaration(rootDir) {
1033
1033
  assertEnforcementMode(declaration);
1034
1034
  assertSkipJobDeclarations(declaration.skip_job_declarations);
1035
1035
  assertEvidenceBearingChecks(declaration.evidence_bearing_checks ?? {});
1036
+ registrationContexts(declaration, {
1037
+ contexts: declaration.required_contexts,
1038
+ });
1036
1039
  return declaration;
1037
1040
  }
1038
1041
 
1042
+ /**
1043
+ * Validate reasoned registration deferrals against the set actually judged.
1044
+ * This only removes absence/registration observations. GitHub still requires
1045
+ * each deferred check to pass; evidence-bearing checks can never be deferred.
1046
+ * @param {object} declaration - Reviewed repository declaration.
1047
+ * @param {{contexts: string[]}} requiredSet - Selected base branch or union.
1048
+ * @returns {string[]} Contexts whose registration must still be observed.
1049
+ */
1050
+ export function registrationContexts(declaration, requiredSet) {
1051
+ const deferred = declaration.registration_deferred;
1052
+ if (deferred === undefined) return requiredSet.contexts;
1053
+ if (
1054
+ deferred === null ||
1055
+ typeof deferred !== "object" ||
1056
+ Array.isArray(deferred)
1057
+ )
1058
+ throw new Error(
1059
+ "check-skipped-required-checks: `registration_deferred` must be an object mapping required check names to non-empty reasons."
1060
+ );
1061
+ for (const [name, reason] of Object.entries(deferred)) {
1062
+ if (typeof reason !== "string" || reason.trim() === "")
1063
+ throw new Error(
1064
+ `check-skipped-required-checks: registration_deferred entry ${JSON.stringify(name)} needs a non-empty reason.`
1065
+ );
1066
+ if (!requiredSet.contexts.includes(name))
1067
+ throw new Error(
1068
+ `check-skipped-required-checks: registration_deferred entry ${JSON.stringify(name)} is not in the selected required set. Refusing to judge this declaration.`
1069
+ );
1070
+ if (Object.hasOwn(declaration.evidence_bearing_checks ?? {}, name))
1071
+ throw new Error(
1072
+ `check-skipped-required-checks: registration_deferred entry ${JSON.stringify(name)} is evidence-bearing. Review evidence must still be waited for and judged.`
1073
+ );
1074
+ }
1075
+ return requiredSet.contexts.filter(name => !Object.hasOwn(deferred, name));
1076
+ }
1077
+
1039
1078
  /**
1040
1079
  * Refuses a declaration that omits one of the guard's load-bearing snapshots.
1041
1080
  *
@@ -1781,7 +1820,7 @@ export function evaluateAbsentRequiredChecks(
1781
1820
  declaration,
1782
1821
  options.base ?? { base: null, source: null }
1783
1822
  );
1784
- const required = requiredSet.contexts;
1823
+ const required = registrationContexts(declaration, requiredSet);
1785
1824
  const judgedFor =
1786
1825
  requiredSet.source === "branch"
1787
1826
  ? ` Judged against the contexts required on base \`${requiredSet.base}\`.`
@@ -4498,7 +4537,7 @@ export function fetchSettledChecks(declaration, pr, repo, options = {}) {
4498
4537
  selectRequiredContexts(declaration, { base: null, source: null });
4499
4538
  const selectSet = options.requiredSetFor ?? (() => defaultRequiredSet);
4500
4539
  const missing = observed =>
4501
- observed.requiredSet.contexts.filter(
4540
+ registrationContexts(declaration, observed.requiredSet).filter(
4502
4541
  name => !observed.checks.some(check => check.name === name)
4503
4542
  );
4504
4543
  // A substitute is useful only at the head it was actually read for. Pending
@@ -4522,6 +4561,7 @@ export function fetchSettledChecks(declaration, pr, repo, options = {}) {
4522
4561
  const before = initial?.headSha === undefined ? observe(pr, repo) : initial;
4523
4562
  initial = undefined;
4524
4563
  const beforeSet = selectSet(before);
4564
+ registrationContexts(declaration, beforeSet);
4525
4565
  if (before.headSha === undefined) {
4526
4566
  return {
4527
4567
  checks: [],
@@ -4536,6 +4576,7 @@ export function fetchSettledChecks(declaration, pr, repo, options = {}) {
4536
4576
  const checks = read(pr, repo, before.headSha);
4537
4577
  const after = observe(pr, repo);
4538
4578
  const afterSet = selectSet(after);
4579
+ registrationContexts(declaration, afterSet);
4539
4580
  return {
4540
4581
  checks,
4541
4582
  headSha: before.headSha,
@@ -4571,7 +4612,12 @@ export function fetchSettledChecks(declaration, pr, repo, options = {}) {
4571
4612
  }
4572
4613
  const elapsedSeconds = Math.max(0, clock() - started) / 1000;
4573
4614
  const unregistered = missing(observed);
4574
- const total = observed.requiredSet.contexts.length;
4615
+ const total = registrationContexts(declaration, observed.requiredSet).length;
4616
+ const deferred = Object.keys(declaration.registration_deferred ?? {});
4617
+ const deferralNote =
4618
+ deferred.length === 0
4619
+ ? ""
4620
+ : ` (${deferred.length} deferred by declaration: ${deferred.join(", ")})`;
4575
4621
  const present = total - unregistered.length;
4576
4622
  const expired = unregistered.length > 0;
4577
4623
  const settled = checksSettled(declaration, observed.checks);
@@ -4589,9 +4635,10 @@ export function fetchSettledChecks(declaration, pr, repo, options = {}) {
4589
4635
  total,
4590
4636
  missing: unregistered,
4591
4637
  expired,
4638
+ ...(deferred.length === 0 ? {} : { deferred }),
4592
4639
  line: expired
4593
- ? `Required registration wait EXPIRED: the gate stopped waiting after ${elapsedSeconds}s; ${present} of ${total} required contexts observed; missing: ${unregistered.join(", ")}. RE-RUN this job before treating this as a finding about the change.`
4594
- : `Required registration settled after ${elapsedSeconds}s; ${present} of ${total} required contexts observed.`,
4640
+ ? `Required registration wait EXPIRED: the gate stopped waiting after ${elapsedSeconds}s; ${present} of ${total} required contexts observed${deferralNote}; missing: ${unregistered.join(", ")}. RE-RUN this job before treating this as a finding about the change.`
4641
+ : `Required registration settled after ${elapsedSeconds}s; ${present} of ${total} required contexts observed${deferralNote}.`,
4595
4642
  };
4596
4643
  return {
4597
4644
  checks: observed.checks,
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "_readme": [
3
+ "Optional `registration_deferred` (#4622) maps exact required context names to non-empty reasons when those jobs register after the bounded five-minute wait introduced by #4527. The registration/absence probe excludes only these names; GitHub still requires them to pass before merge. Entries outside the selected base branch's required set, malformed reasons, and evidence-bearing checks are refused. Omit the key for unchanged behavior. A slow reviewer is never deferred: the review-evidence workflow re-evaluates on its terminal check_run or status event, using default-branch code and a fresh current-head read. This workflow is create-only; existing hosts must adopt the event job explicitly to receive the wake-up behavior.",
3
4
  "Two REVIEWED SNAPSHOTS that scripts/check-skipped-required-checks.mjs makes police each other.",
4
5
  "Neither is derivable from this repository: `required_contexts` lives in a GitHub ruleset that humans edit in an admin console, and the skip_jobs token -> job name map lives in Lisa's quality.yml, which is not vendored here.",
5
6
  "Why it matters: GitHub counts a SKIPPED required status check as SATISFIED. A job named in `skip_jobs` still reports green against its required context having run zero steps, so the merge gate can never be red and therefore can never block anything.",
@@ -122,6 +122,9 @@ name: 🕵️ Review Evidence
122
122
  on:
123
123
  pull_request:
124
124
  types: [opened, synchronize, reopened, ready_for_review]
125
+ check_run:
126
+ types: [completed]
127
+ status:
125
128
  workflow_dispatch:
126
129
  inputs:
127
130
  pr:
@@ -147,11 +150,50 @@ permissions:
147
150
  pull-requests: read
148
151
 
149
152
  concurrency:
150
- group: review-evidence-${{ github.event.pull_request.number || inputs.pr || github.ref }}
153
+ group: review-evidence-${{ github.event_name }}-${{ github.event.pull_request.number || inputs.pr || github.event.check_run.head_sha || github.event.sha || github.ref }}-${{ github.event.check_run.name || github.event.context }}-${{ github.event.check_run.app.id || github.event.creator.id }}
151
154
  cancel-in-progress: true
152
155
 
153
156
  jobs:
157
+ # Reviewer completion can outlast the bounded pull_request run. Dispatch the
158
+ # normal gate; the event is a wake-up and never proof that a review occurred.
159
+ # check_run requires this file on the default branch and GitHub suppresses
160
+ # Actions-created suites/heads; status supports legacy reviewer statuses.
161
+ recheck:
162
+ name: 🕵️ Re-evaluate a completed reviewer
163
+ if: github.event_name == 'check_run' || (github.event_name == 'status' && github.event.state != 'pending')
164
+ runs-on: ubuntu-latest
165
+ timeout-minutes: 5
166
+ permissions:
167
+ contents: read
168
+ checks: read
169
+ statuses: read
170
+ pull-requests: read
171
+ actions: write
172
+ steps:
173
+ # No head ref: never execute PR files with the dispatch token.
174
+ - name: 📥 Checkout default branch
175
+ uses: actions/checkout@v6
176
+ with:
177
+ persist-credentials: false
178
+ - name: 🔧 Setup Node.js
179
+ uses: actions/setup-node@v6
180
+ with:
181
+ package-manager-cache: false
182
+ node-version: ${{ vars.NODE_VERSION || '24.21.0' }}
183
+ - name: 🕵️ Dispatch the gate for current declared reviewer heads
184
+ env:
185
+ GH_TOKEN: ${{ github.token }}
186
+ run: |
187
+ set -eu
188
+ script=scripts/review-evidence-event.mjs
189
+ if [ ! -f "$script" ]; then
190
+ echo "::error::Reviewer event resolver missing; no gate was dispatched."
191
+ exit 1
192
+ fi
193
+ node "$script" --dispatch
194
+
154
195
  vacuity:
196
+ if: github.event_name != 'check_run' && github.event_name != 'status'
155
197
  # DECLARATIVE, NOT A QUESTION (#3917). This was `🕵️ Did the required review
156
198
  # checks do any work?`, and an unsatisfied verdict exits non-zero, so the
157
199
  # row rendered `Did the required review checks do any work? fail`. A yes/no