@codyswann/lisa 4.87.0 → 4.87.1

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 (87) hide show
  1. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  2. package/dist/core/upstream-evidence-manifest.js +2 -2
  3. package/package.json +4 -4
  4. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  5. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  6. package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +79 -22
  7. package/plugins/lisa/.codex-plugin/skills/lisa-pull-request-review/SKILL.md +8 -0
  8. package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +79 -22
  9. package/plugins/lisa/skills/lisa-pull-request-review/SKILL.md +8 -0
  10. package/plugins/lisa-agy/plugin.json +1 -1
  11. package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +79 -22
  12. package/plugins/lisa-agy/skills/lisa-pull-request-review/SKILL.md +8 -0
  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-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +79 -22
  22. package/plugins/lisa-copilot/skills/lisa-pull-request-review/SKILL.md +8 -0
  23. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +79 -22
  25. package/plugins/lisa-cursor/skills/lisa-pull-request-review/SKILL.md +8 -0
  26. package/plugins/lisa-devin/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-devin/.devin-plugin/plugin.json +1 -1
  28. package/plugins/lisa-devin/skills/lisa-drive-pr-to-merge/SKILL.md +79 -22
  29. package/plugins/lisa-devin/skills/lisa-pull-request-review/SKILL.md +8 -0
  30. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  32. package/plugins/lisa-expo-agy/plugin.json +1 -1
  33. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-expo-devin/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-expo-devin/.devin-plugin/plugin.json +1 -1
  37. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  39. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  40. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-harper-fabric-devin/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-harper-fabric-devin/.devin-plugin/plugin.json +1 -1
  44. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  46. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  47. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-nestjs-devin/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-nestjs-devin/.devin-plugin/plugin.json +1 -1
  51. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  53. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  54. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-openclaw-devin/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-openclaw-devin/.devin-plugin/plugin.json +1 -1
  58. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  60. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  61. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-phaser-devin/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-phaser-devin/.devin-plugin/plugin.json +1 -1
  65. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  67. package/plugins/lisa-rails-agy/plugin.json +1 -1
  68. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-rails-devin/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-rails-devin/.devin-plugin/plugin.json +1 -1
  72. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  74. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  75. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-typescript-devin/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-typescript-devin/.devin-plugin/plugin.json +1 -1
  79. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  81. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  82. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  84. package/plugins/lisa-wiki-devin/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +1 -1
  86. package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +79 -22
  87. package/plugins/src/base/skills/lisa-pull-request-review/SKILL.md +8 -0
@@ -41,9 +41,9 @@ export const NIGHTLY_E2E_GUARD_BEHAVIOR_CERTIFICATES = Object.freeze({
41
41
  }),
42
42
  d1b26caeaf65950e3b60ff41964d234c032c50470072e7643310b1f6722e34e6: Object.freeze({
43
43
  contractVersion: "1.9.0",
44
- packageVersions: Object.freeze(["4.87.0"]),
44
+ packageVersions: Object.freeze(["4.87.1"]),
45
45
  provenances: Object.freeze([
46
- "workspace package @codyswann/lisa@4.87.0 (typescript/copy-overwrite/scripts/check-nightly-e2e-health.mjs)",
46
+ "workspace package @codyswann/lisa@4.87.1 (typescript/copy-overwrite/scripts/check-nightly-e2e-health.mjs)",
47
47
  ]),
48
48
  }),
49
49
  dfd2fef680de5ef03e63075e8a61c62ca4d95cdfdff6201939b79c748d3397f6: Object.freeze({
@@ -699,7 +699,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
699
699
  "plugins/src/base/skills/lisa-detect-tooling/scripts/commands.mjs": "e28bd61fdde4a336b56ae3395423026943a5816015719d31d04f0d5a0ab50eec",
700
700
  "plugins/src/base/skills/lisa-detect-tooling/scripts/detect-tooling.mjs": "d9419814fc04c935bd7e320e85b1977c9bfc9275d9ea5fb557002ad438ee7925",
701
701
  "plugins/src/base/skills/lisa-doctor/SKILL.md": "ab7bb855fd3ebe321e41b0143815f202b70f6ba38f6678791d6d9e933e0c3fd8",
702
- "plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md": "4fcae84ea60fbab8f35d401daebfbd45ac46164c5b78f0c8460c96b7dc7fb10c",
702
+ "plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md": "46b3b6e974caf5dad42e770c1320b0bd6ae631c9dca787a3478f21485e343429",
703
703
  "plugins/src/base/skills/lisa-epic-triage/SKILL.md": "d02760411249bddbd396f283191fe3e82bb7b95bf9393a19a7025dc5a57c3ab7",
704
704
  "plugins/src/base/skills/lisa-evaluation-suite/SKILL.md": "96b5c2091ccd22a565935a7b0b917f67998881b81055ce3e4d518319472eac8b",
705
705
  "plugins/src/base/skills/lisa-exploratory-qa/SKILL.md": "254b15d65f8da6bfc6a930814004892e4a32ba8946ff1b68c27fec2a57d9e5b4",
@@ -798,7 +798,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
798
798
  "plugins/src/base/skills/lisa-project-ideation/examples/idempotency-verification-harness.md": "c6def168f32c3e6cb426d7d7d942bbe5b5776b46e315f47d2b2aeaad275c7f0f",
799
799
  "plugins/src/base/skills/lisa-project-ideation/examples/public-external-inspiration.md": "8e61344f46d46c2f6806b6bdb5bbf0086df358240661a524806d1bd659330ce9",
800
800
  "plugins/src/base/skills/lisa-project-ideation/examples/unavailable-data-rejection.md": "362835db13cb8f73179754bce427d0f7caef7738a575aa5b936a0383b7f81078",
801
- "plugins/src/base/skills/lisa-pull-request-review/SKILL.md": "10bb42cba995cdd6b945efd6ef3d48578860b9d09c94aefd17c298b53aed5053",
801
+ "plugins/src/base/skills/lisa-pull-request-review/SKILL.md": "c95c6fd7948e1daaec760b1c7ff9504f83e3fdcf9f7e9409edeef41991254b03",
802
802
  "plugins/src/base/skills/lisa-quality-review/SKILL.md": "c51afffe153f614bcef5bbd2a7b8ffb53c241ebd246900863448e3a6f4be7d47",
803
803
  "plugins/src/base/skills/lisa-queue-status/SKILL.md": "8905a65e2c0f3d6894b4c36907723fe0b7d6048ff0fd1d0e2be529eccb5de1e3",
804
804
  "plugins/src/base/skills/lisa-remote-dispatch/SKILL.md": "f3c48120a206d01db45f849ca5b61690d572abc16bc36d559a4cacc8f9422c06",
package/package.json CHANGED
@@ -189,7 +189,7 @@
189
189
  "qs": "^6.16.0"
190
190
  },
191
191
  "name": "@codyswann/lisa",
192
- "version": "4.87.0",
192
+ "version": "4.87.1",
193
193
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
194
194
  "main": "dist/index.js",
195
195
  "exports": {
@@ -347,7 +347,7 @@
347
347
  "test": "tests"
348
348
  },
349
349
  "types": "./dist/index.d.ts",
350
- "lisaReleaseCommit": "1a96a2fed56ab77f8f4cca54bd17a34b73324a1a",
351
- "gitHead": "1a96a2fed56ab77f8f4cca54bd17a34b73324a1a",
352
- "lisaReleaseTag": "v4.87.0"
350
+ "lisaReleaseCommit": "685c54f5fdefa2acbc9a412557124db84d898f79",
351
+ "gitHead": "685c54f5fdefa2acbc9a412557124db84d898f79",
352
+ "lisaReleaseTag": "v4.87.1"
353
353
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.87.0",
3
+ "version": "4.87.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.87.0",
3
+ "version": "4.87.1",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -393,15 +393,16 @@ declared, arm normally (the scope rule above). Where one IS declared, absent a
393
393
  description that positively states a review ran, treat the context as vacuous.
394
394
  Fail closed: absence of evidence is not evidence of a review.
395
395
 
396
- #### Vacuous and transient are different properties
396
+ #### Vacuous, transient or standing: the response is the same
397
397
 
398
- A vacuous context is not automatically something to wait out, and this is the
399
- distinction a naive wait-and-arm gets wrong — it waits forever on a repository
400
- where the state never clears. **Only the rate limit has both properties.**
398
+ A vacuous context is never something to wait out. Waiting looks like progress
399
+ but it is a stall, and on a repository where the state never clears it waits
400
+ forever. Some vacuities clear on their own and some do not. **That changes what
401
+ the report says, not what you do:**
401
402
 
402
403
  | description | vacuous? | clears on its own? |
403
404
  | --- | --- | --- |
404
- | `Review rate limited` | yes | **yes** — a throughput window |
405
+ | `Review rate limited` (and decorated forms such as `Review rate limited (retry in 12m)`) | yes | eventually — a throughput window of unknown length |
405
406
  | `Review skipped: manual review required for this OSS repository` | yes | **no** — a standing vendor policy for public repositories |
406
407
  | `Review skipped: N files exceed the limit of M` | yes | **no** — not without splitting the pull request |
407
408
  | `Review skipped` (bare, no stated reason) | yes | **unknown — treat as standing** |
@@ -410,17 +411,33 @@ A bare skip carries no machine-readable reason, so nothing distinguishes it from
410
411
  the standing forms. Requiring a stated reason before treating a skip as vacuous
411
412
  is how the commonest form gets missed.
412
413
 
413
- - **Transient (the rate limit, and only the rate limit)** — do not arm yet. Wait
414
- the window out and re-request the review **at most once**, then re-classify.
415
- If it now proves work, arm. If it does not, stop and treat it as standing.
416
- **Never loop**: a retry loop re-triggers the very limit it is escaping, and
417
- measured on #3220 a single explicit re-request in this repository was
418
- acknowledged, went `Review in progress`, and settled back at
419
- `Review rate limited` two seconds later having reviewed nothing — minting a
420
- second hollow green. One attempt, then report.
421
- - **Standing** — do not wait at all, and do not re-request. There is no window
422
- to wait out, so waiting produces a stall that reads as progress. Go straight
423
- to the watch loop and let step (d) adjudicate the merge in the open.
414
+ **Every row, the rate limit included: do not wait, and do not re-request.** Do
415
+ not arm. Go straight to the watch loop, run the local adversarial review over the
416
+ PR diff at the current head **now**, post it with the substitute marker (step
417
+ (d), "In case 3, substitute"), and keep driving. Fix what it finds, substitute
418
+ again on each new head, and let step (d) merge when the vacuous context is the
419
+ sole remaining gate.
420
+
421
+ The rate limit used to get a wait-the-window-out-and-re-request-once exception.
422
+ That exception is removed, for three reasons:
423
+
424
+ - **The window is not short.** Agents waiting it out stalled for an hour or more
425
+ per pull request, across a whole portfolio of repositories, and nothing about
426
+ the wait made the merge safer than a substitute review would.
427
+ - **Re-requesting does not work under a throttle.** Measured on #3220, a single
428
+ explicit re-request was acknowledged, went `Review in progress`, and settled
429
+ back at `Review rate limited` two seconds later having reviewed nothing. That
430
+ minted a second hollow green.
431
+ - **Re-requesting destroys evidence.** It overwrites the existing status (see
432
+ "Never re-request a review to 'refresh' it" in step (d)), so the exception
433
+ contradicted a rule this file states with no exceptions.
434
+
435
+ If the reviewer later reviews on its own, nothing special happens. Its threads
436
+ are review threads like any other, and step (d) handles them. A `CHANGES_REQUESTED`
437
+ it leaves is a real blocker (step (e)), and the substitute never overrides it.
438
+ If it now proves work, arm, per the table above. That is a re-classification
439
+ the watch loop makes on what it reads anyway. It is never a reason to wait or
440
+ re-request.
424
441
 
425
442
  #### A latch somebody else armed
426
443
 
@@ -1048,10 +1065,11 @@ configured reviewed-when phrase says what "did work" looks like for this
1048
1065
  project.
1049
1066
 
1050
1067
  Prove the signal from the commit status API as above; a merely pending or queued
1051
- check is not proof of anything and must keep polling. **A transient vacuity is not adjudicated here until the arm gate's
1052
- single wait-and-re-request has been spent** (section 1): a rate limit has a
1053
- window, and merging past one you never waited out is a choice you did not have
1054
- to make. A standing vacuity has no window, so it arrives here immediately.
1068
+ check is not proof of anything and must keep polling. **A settled vacuity, the
1069
+ rate limit included, arrives here immediately.** There is no wait to spend first
1070
+ and no re-request to try: a rate limit's window is of unknown length, and
1071
+ waiting it out stalls the pull request without reading a line of the diff. The
1072
+ substitute is what makes the merge safe, not the passage of time.
1055
1073
 
1056
1074
  Once the signal is explicit, merge directly with `gh pr merge <pr>
1057
1075
  --<merge_method>` (pass `--admin` only if branch protection lists the vacuous
@@ -1172,6 +1190,34 @@ Deleting the fallback outright would over-correct: it is the only remedy a lane
1172
1190
  without dismissal permission has, and that permission is not universal. This
1173
1191
  narrows it to the case that costs nothing.
1174
1192
 
1193
+ **A stale bot verdict under a rate limit: substitute, then stop and report.**
1194
+ Under a rate limit or an exhausted review allowance, a bot's old
1195
+ `CHANGES_REQUESTED` on an outdated head can end up as the only thing blocking
1196
+ the merge. The bot cannot post a fresh review to replace it, so the verdict
1197
+ will not clear by itself while the throttle lasts. This was measured on a
1198
+ caller repo in the portfolio: every check green, zero unresolved threads, and
1199
+ the bot's verdict from an earlier head as the only blocker. In that case:
1200
+
1201
+ 1. **Do not wait for the window to reset, and do not re-request.** Waiting
1202
+ leaves the pull request wedged for an hour or more. A re-request under the
1203
+ throttle settles hollow and can take away the bot's standing review (see
1204
+ above).
1205
+ 2. Post the local adversarial review substitute for the **current** head, as
1206
+ step (d) case 3 describes, if one is not already there.
1207
+ 3. **Then stop** with `blocked:stale-bot-verdict` (section 4). Report exactly
1208
+ that blocker: the bot reviewer, the review id, the outdated head it reviewed
1209
+ and the current head, the unresolved thread count, and that the substitute
1210
+ is posted for the current head. Name the decision that is needed: a human
1211
+ with dismissal rights dismisses that review, or decides it must stand.
1212
+
1213
+ Do not dismiss it on the strength of your own substitute. Here the bot's review
1214
+ is the only third-party review on the pull request. Dismissing it because of a
1215
+ review this run wrote would make the agent both author and judge of the change.
1216
+ That is the escalation the bullet above requires, reached right away instead of
1217
+ after a wait. A stranded verdict that is **not** the only substantive review, or
1218
+ one left by a reviewer that is not throttled, is still handled by the
1219
+ dismissal rule above.
1220
+
1175
1221
  **Unverified, and stated as such rather than asserted:** that a bot's re-review
1176
1222
  REPLACES its predecessor in the effective set is inferred from the observed
1177
1223
  consequence, not measured against the vendor. It has not been tested here, and
@@ -1455,7 +1501,7 @@ Loop until one of:
1455
1501
  the mode forbids acting on them: `on_blocker=report`). The latch is
1456
1502
  deliberately not armed, so the PR sits OPEN rather than merging on a review
1457
1503
  nothing performed. Report the PR URL, the review context's settled
1458
- description, whether it is transient or standing, and which sole-gate
1504
+ description, whether it clears on its own (a rate limit) or is standing, and which sole-gate
1459
1505
  condition failed. This is an outcome that needs an operator, stated in one
1460
1506
  line a non-technical reader can act on — for example: *"PR #123 is ready to
1461
1507
  merge but nobody reviewed it: the review tool says it skips public
@@ -1485,6 +1531,16 @@ Loop until one of:
1485
1531
  — but a review asked for changes and that is still on record, so it will sit
1486
1532
  there forever. Someone needs to clear that review or resolve the open
1487
1533
  comments."* Never report this PR as merging.
1534
+ - **`blocked:stale-bot-verdict`** — the only thing blocking the merge is a
1535
+ bot's `CHANGES_REQUESTED` on an outdated head, the bot is rate limited or out
1536
+ of review allowance so it cannot replace that verdict, and the local
1537
+ adversarial review substitute is posted for the current head (step (e)).
1538
+ Report the reviewer, the review id, both heads, the unresolved thread count,
1539
+ and the dismissal decision a human needs to make. For example: *"PR #123 is
1540
+ ready except for an old review from the review bot on an earlier version. The
1541
+ bot is rate limited and cannot re-review, and I posted my own review of the
1542
+ current version. Someone with dismissal rights needs to dismiss review 456,
1543
+ or decide it should stand."* Do not wait for the bot's window to reset.
1488
1544
  - **`CLOSED`** → report (PR was closed without merge).
1489
1545
  - **Hard block needing a human**: an unresolvable conflict, a failing check that
1490
1546
  needs design input, or genuine unresolved human objection (not a bot gate). Stop
@@ -1593,7 +1649,8 @@ declare none, one, or several, and each shows its own evidence.
1593
1649
 
1594
1650
  Quote the description that was actually read. A report that says "rate limited"
1595
1651
  on a policy skip is a wrong record, and the two call for different operator
1596
- actions: one clears itself, the other never will.
1652
+ actions: one clears itself, the other never will. Neither changes what this
1653
+ skill does in the meantime: it substitutes and keeps driving in both cases.
1597
1654
 
1598
1655
  `NOT REVIEWED` is reporting, and on a merged PR it is never a terminal state of
1599
1656
  its own: it does not turn a merged PR into a blocked one. What it does gate is
@@ -75,6 +75,14 @@ node scripts/check-skipped-required-checks.mjs --pr=<pr> --json
75
75
  It reports and never fails — a hollow check is often a vendor spending cap, not
76
76
  a repository defect, and it is not this skill's call to block on one.
77
77
 
78
+ **Do not wait for a rate limit to reset, and do not re-request the review.** A
79
+ `Review rate limited` status, including decorated forms such as
80
+ `Review rate limited (retry in 12m)`, is handled like every other vacuous
81
+ review. Report it here. `lisa-drive-pr-to-merge` then posts a local adversarial
82
+ review substitute for the current head right away and keeps driving. Waiting
83
+ out the window stalls the pull request for an hour or more and reads no code.
84
+ Re-requesting overwrites the status and can destroy a real review.
85
+
78
86
  Carry the finding into your Step 4 report. **Do not write "no unresolved review
79
87
  threads" on its own** — it is true of an unreviewed PR too. Say which you
80
88
  observed:
@@ -391,15 +391,16 @@ declared, arm normally (the scope rule above). Where one IS declared, absent a
391
391
  description that positively states a review ran, treat the context as vacuous.
392
392
  Fail closed: absence of evidence is not evidence of a review.
393
393
 
394
- #### Vacuous and transient are different properties
394
+ #### Vacuous, transient or standing: the response is the same
395
395
 
396
- A vacuous context is not automatically something to wait out, and this is the
397
- distinction a naive wait-and-arm gets wrong — it waits forever on a repository
398
- where the state never clears. **Only the rate limit has both properties.**
396
+ A vacuous context is never something to wait out. Waiting looks like progress
397
+ but it is a stall, and on a repository where the state never clears it waits
398
+ forever. Some vacuities clear on their own and some do not. **That changes what
399
+ the report says, not what you do:**
399
400
 
400
401
  | description | vacuous? | clears on its own? |
401
402
  | --- | --- | --- |
402
- | `Review rate limited` | yes | **yes** — a throughput window |
403
+ | `Review rate limited` (and decorated forms such as `Review rate limited (retry in 12m)`) | yes | eventually — a throughput window of unknown length |
403
404
  | `Review skipped: manual review required for this OSS repository` | yes | **no** — a standing vendor policy for public repositories |
404
405
  | `Review skipped: N files exceed the limit of M` | yes | **no** — not without splitting the pull request |
405
406
  | `Review skipped` (bare, no stated reason) | yes | **unknown — treat as standing** |
@@ -408,17 +409,33 @@ A bare skip carries no machine-readable reason, so nothing distinguishes it from
408
409
  the standing forms. Requiring a stated reason before treating a skip as vacuous
409
410
  is how the commonest form gets missed.
410
411
 
411
- - **Transient (the rate limit, and only the rate limit)** — do not arm yet. Wait
412
- the window out and re-request the review **at most once**, then re-classify.
413
- If it now proves work, arm. If it does not, stop and treat it as standing.
414
- **Never loop**: a retry loop re-triggers the very limit it is escaping, and
415
- measured on #3220 a single explicit re-request in this repository was
416
- acknowledged, went `Review in progress`, and settled back at
417
- `Review rate limited` two seconds later having reviewed nothing — minting a
418
- second hollow green. One attempt, then report.
419
- - **Standing** — do not wait at all, and do not re-request. There is no window
420
- to wait out, so waiting produces a stall that reads as progress. Go straight
421
- to the watch loop and let step (d) adjudicate the merge in the open.
412
+ **Every row, the rate limit included: do not wait, and do not re-request.** Do
413
+ not arm. Go straight to the watch loop, run the local adversarial review over the
414
+ PR diff at the current head **now**, post it with the substitute marker (step
415
+ (d), "In case 3, substitute"), and keep driving. Fix what it finds, substitute
416
+ again on each new head, and let step (d) merge when the vacuous context is the
417
+ sole remaining gate.
418
+
419
+ The rate limit used to get a wait-the-window-out-and-re-request-once exception.
420
+ That exception is removed, for three reasons:
421
+
422
+ - **The window is not short.** Agents waiting it out stalled for an hour or more
423
+ per pull request, across a whole portfolio of repositories, and nothing about
424
+ the wait made the merge safer than a substitute review would.
425
+ - **Re-requesting does not work under a throttle.** Measured on #3220, a single
426
+ explicit re-request was acknowledged, went `Review in progress`, and settled
427
+ back at `Review rate limited` two seconds later having reviewed nothing. That
428
+ minted a second hollow green.
429
+ - **Re-requesting destroys evidence.** It overwrites the existing status (see
430
+ "Never re-request a review to 'refresh' it" in step (d)), so the exception
431
+ contradicted a rule this file states with no exceptions.
432
+
433
+ If the reviewer later reviews on its own, nothing special happens. Its threads
434
+ are review threads like any other, and step (d) handles them. A `CHANGES_REQUESTED`
435
+ it leaves is a real blocker (step (e)), and the substitute never overrides it.
436
+ If it now proves work, arm, per the table above. That is a re-classification
437
+ the watch loop makes on what it reads anyway. It is never a reason to wait or
438
+ re-request.
422
439
 
423
440
  #### A latch somebody else armed
424
441
 
@@ -1046,10 +1063,11 @@ configured reviewed-when phrase says what "did work" looks like for this
1046
1063
  project.
1047
1064
 
1048
1065
  Prove the signal from the commit status API as above; a merely pending or queued
1049
- check is not proof of anything and must keep polling. **A transient vacuity is not adjudicated here until the arm gate's
1050
- single wait-and-re-request has been spent** (section 1): a rate limit has a
1051
- window, and merging past one you never waited out is a choice you did not have
1052
- to make. A standing vacuity has no window, so it arrives here immediately.
1066
+ check is not proof of anything and must keep polling. **A settled vacuity, the
1067
+ rate limit included, arrives here immediately.** There is no wait to spend first
1068
+ and no re-request to try: a rate limit's window is of unknown length, and
1069
+ waiting it out stalls the pull request without reading a line of the diff. The
1070
+ substitute is what makes the merge safe, not the passage of time.
1053
1071
 
1054
1072
  Once the signal is explicit, merge directly with `gh pr merge <pr>
1055
1073
  --<merge_method>` (pass `--admin` only if branch protection lists the vacuous
@@ -1170,6 +1188,34 @@ Deleting the fallback outright would over-correct: it is the only remedy a lane
1170
1188
  without dismissal permission has, and that permission is not universal. This
1171
1189
  narrows it to the case that costs nothing.
1172
1190
 
1191
+ **A stale bot verdict under a rate limit: substitute, then stop and report.**
1192
+ Under a rate limit or an exhausted review allowance, a bot's old
1193
+ `CHANGES_REQUESTED` on an outdated head can end up as the only thing blocking
1194
+ the merge. The bot cannot post a fresh review to replace it, so the verdict
1195
+ will not clear by itself while the throttle lasts. This was measured on a
1196
+ caller repo in the portfolio: every check green, zero unresolved threads, and
1197
+ the bot's verdict from an earlier head as the only blocker. In that case:
1198
+
1199
+ 1. **Do not wait for the window to reset, and do not re-request.** Waiting
1200
+ leaves the pull request wedged for an hour or more. A re-request under the
1201
+ throttle settles hollow and can take away the bot's standing review (see
1202
+ above).
1203
+ 2. Post the local adversarial review substitute for the **current** head, as
1204
+ step (d) case 3 describes, if one is not already there.
1205
+ 3. **Then stop** with `blocked:stale-bot-verdict` (section 4). Report exactly
1206
+ that blocker: the bot reviewer, the review id, the outdated head it reviewed
1207
+ and the current head, the unresolved thread count, and that the substitute
1208
+ is posted for the current head. Name the decision that is needed: a human
1209
+ with dismissal rights dismisses that review, or decides it must stand.
1210
+
1211
+ Do not dismiss it on the strength of your own substitute. Here the bot's review
1212
+ is the only third-party review on the pull request. Dismissing it because of a
1213
+ review this run wrote would make the agent both author and judge of the change.
1214
+ That is the escalation the bullet above requires, reached right away instead of
1215
+ after a wait. A stranded verdict that is **not** the only substantive review, or
1216
+ one left by a reviewer that is not throttled, is still handled by the
1217
+ dismissal rule above.
1218
+
1173
1219
  **Unverified, and stated as such rather than asserted:** that a bot's re-review
1174
1220
  REPLACES its predecessor in the effective set is inferred from the observed
1175
1221
  consequence, not measured against the vendor. It has not been tested here, and
@@ -1453,7 +1499,7 @@ Loop until one of:
1453
1499
  the mode forbids acting on them: `on_blocker=report`). The latch is
1454
1500
  deliberately not armed, so the PR sits OPEN rather than merging on a review
1455
1501
  nothing performed. Report the PR URL, the review context's settled
1456
- description, whether it is transient or standing, and which sole-gate
1502
+ description, whether it clears on its own (a rate limit) or is standing, and which sole-gate
1457
1503
  condition failed. This is an outcome that needs an operator, stated in one
1458
1504
  line a non-technical reader can act on — for example: *"PR #123 is ready to
1459
1505
  merge but nobody reviewed it: the review tool says it skips public
@@ -1483,6 +1529,16 @@ Loop until one of:
1483
1529
  — but a review asked for changes and that is still on record, so it will sit
1484
1530
  there forever. Someone needs to clear that review or resolve the open
1485
1531
  comments."* Never report this PR as merging.
1532
+ - **`blocked:stale-bot-verdict`** — the only thing blocking the merge is a
1533
+ bot's `CHANGES_REQUESTED` on an outdated head, the bot is rate limited or out
1534
+ of review allowance so it cannot replace that verdict, and the local
1535
+ adversarial review substitute is posted for the current head (step (e)).
1536
+ Report the reviewer, the review id, both heads, the unresolved thread count,
1537
+ and the dismissal decision a human needs to make. For example: *"PR #123 is
1538
+ ready except for an old review from the review bot on an earlier version. The
1539
+ bot is rate limited and cannot re-review, and I posted my own review of the
1540
+ current version. Someone with dismissal rights needs to dismiss review 456,
1541
+ or decide it should stand."* Do not wait for the bot's window to reset.
1486
1542
  - **`CLOSED`** → report (PR was closed without merge).
1487
1543
  - **Hard block needing a human**: an unresolvable conflict, a failing check that
1488
1544
  needs design input, or genuine unresolved human objection (not a bot gate). Stop
@@ -1591,7 +1647,8 @@ declare none, one, or several, and each shows its own evidence.
1591
1647
 
1592
1648
  Quote the description that was actually read. A report that says "rate limited"
1593
1649
  on a policy skip is a wrong record, and the two call for different operator
1594
- actions: one clears itself, the other never will.
1650
+ actions: one clears itself, the other never will. Neither changes what this
1651
+ skill does in the meantime: it substitutes and keeps driving in both cases.
1595
1652
 
1596
1653
  `NOT REVIEWED` is reporting, and on a merged PR it is never a terminal state of
1597
1654
  its own: it does not turn a merged PR into a blocked one. What it does gate is
@@ -73,6 +73,14 @@ node scripts/check-skipped-required-checks.mjs --pr=<pr> --json
73
73
  It reports and never fails — a hollow check is often a vendor spending cap, not
74
74
  a repository defect, and it is not this skill's call to block on one.
75
75
 
76
+ **Do not wait for a rate limit to reset, and do not re-request the review.** A
77
+ `Review rate limited` status, including decorated forms such as
78
+ `Review rate limited (retry in 12m)`, is handled like every other vacuous
79
+ review. Report it here. `lisa-drive-pr-to-merge` then posts a local adversarial
80
+ review substitute for the current head right away and keeps driving. Waiting
81
+ out the window stalls the pull request for an hour or more and reads no code.
82
+ Re-requesting overwrites the status and can destroy a real review.
83
+
76
84
  Carry the finding into your Step 4 report. **Do not write "no unresolved review
77
85
  threads" on its own** — it is true of an unreviewed PR too. Say which you
78
86
  observed:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.87.0",
3
+ "version": "4.87.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -391,15 +391,16 @@ declared, arm normally (the scope rule above). Where one IS declared, absent a
391
391
  description that positively states a review ran, treat the context as vacuous.
392
392
  Fail closed: absence of evidence is not evidence of a review.
393
393
 
394
- #### Vacuous and transient are different properties
394
+ #### Vacuous, transient or standing: the response is the same
395
395
 
396
- A vacuous context is not automatically something to wait out, and this is the
397
- distinction a naive wait-and-arm gets wrong — it waits forever on a repository
398
- where the state never clears. **Only the rate limit has both properties.**
396
+ A vacuous context is never something to wait out. Waiting looks like progress
397
+ but it is a stall, and on a repository where the state never clears it waits
398
+ forever. Some vacuities clear on their own and some do not. **That changes what
399
+ the report says, not what you do:**
399
400
 
400
401
  | description | vacuous? | clears on its own? |
401
402
  | --- | --- | --- |
402
- | `Review rate limited` | yes | **yes** — a throughput window |
403
+ | `Review rate limited` (and decorated forms such as `Review rate limited (retry in 12m)`) | yes | eventually — a throughput window of unknown length |
403
404
  | `Review skipped: manual review required for this OSS repository` | yes | **no** — a standing vendor policy for public repositories |
404
405
  | `Review skipped: N files exceed the limit of M` | yes | **no** — not without splitting the pull request |
405
406
  | `Review skipped` (bare, no stated reason) | yes | **unknown — treat as standing** |
@@ -408,17 +409,33 @@ A bare skip carries no machine-readable reason, so nothing distinguishes it from
408
409
  the standing forms. Requiring a stated reason before treating a skip as vacuous
409
410
  is how the commonest form gets missed.
410
411
 
411
- - **Transient (the rate limit, and only the rate limit)** — do not arm yet. Wait
412
- the window out and re-request the review **at most once**, then re-classify.
413
- If it now proves work, arm. If it does not, stop and treat it as standing.
414
- **Never loop**: a retry loop re-triggers the very limit it is escaping, and
415
- measured on #3220 a single explicit re-request in this repository was
416
- acknowledged, went `Review in progress`, and settled back at
417
- `Review rate limited` two seconds later having reviewed nothing — minting a
418
- second hollow green. One attempt, then report.
419
- - **Standing** — do not wait at all, and do not re-request. There is no window
420
- to wait out, so waiting produces a stall that reads as progress. Go straight
421
- to the watch loop and let step (d) adjudicate the merge in the open.
412
+ **Every row, the rate limit included: do not wait, and do not re-request.** Do
413
+ not arm. Go straight to the watch loop, run the local adversarial review over the
414
+ PR diff at the current head **now**, post it with the substitute marker (step
415
+ (d), "In case 3, substitute"), and keep driving. Fix what it finds, substitute
416
+ again on each new head, and let step (d) merge when the vacuous context is the
417
+ sole remaining gate.
418
+
419
+ The rate limit used to get a wait-the-window-out-and-re-request-once exception.
420
+ That exception is removed, for three reasons:
421
+
422
+ - **The window is not short.** Agents waiting it out stalled for an hour or more
423
+ per pull request, across a whole portfolio of repositories, and nothing about
424
+ the wait made the merge safer than a substitute review would.
425
+ - **Re-requesting does not work under a throttle.** Measured on #3220, a single
426
+ explicit re-request was acknowledged, went `Review in progress`, and settled
427
+ back at `Review rate limited` two seconds later having reviewed nothing. That
428
+ minted a second hollow green.
429
+ - **Re-requesting destroys evidence.** It overwrites the existing status (see
430
+ "Never re-request a review to 'refresh' it" in step (d)), so the exception
431
+ contradicted a rule this file states with no exceptions.
432
+
433
+ If the reviewer later reviews on its own, nothing special happens. Its threads
434
+ are review threads like any other, and step (d) handles them. A `CHANGES_REQUESTED`
435
+ it leaves is a real blocker (step (e)), and the substitute never overrides it.
436
+ If it now proves work, arm, per the table above. That is a re-classification
437
+ the watch loop makes on what it reads anyway. It is never a reason to wait or
438
+ re-request.
422
439
 
423
440
  #### A latch somebody else armed
424
441
 
@@ -1046,10 +1063,11 @@ configured reviewed-when phrase says what "did work" looks like for this
1046
1063
  project.
1047
1064
 
1048
1065
  Prove the signal from the commit status API as above; a merely pending or queued
1049
- check is not proof of anything and must keep polling. **A transient vacuity is not adjudicated here until the arm gate's
1050
- single wait-and-re-request has been spent** (section 1): a rate limit has a
1051
- window, and merging past one you never waited out is a choice you did not have
1052
- to make. A standing vacuity has no window, so it arrives here immediately.
1066
+ check is not proof of anything and must keep polling. **A settled vacuity, the
1067
+ rate limit included, arrives here immediately.** There is no wait to spend first
1068
+ and no re-request to try: a rate limit's window is of unknown length, and
1069
+ waiting it out stalls the pull request without reading a line of the diff. The
1070
+ substitute is what makes the merge safe, not the passage of time.
1053
1071
 
1054
1072
  Once the signal is explicit, merge directly with `gh pr merge <pr>
1055
1073
  --<merge_method>` (pass `--admin` only if branch protection lists the vacuous
@@ -1170,6 +1188,34 @@ Deleting the fallback outright would over-correct: it is the only remedy a lane
1170
1188
  without dismissal permission has, and that permission is not universal. This
1171
1189
  narrows it to the case that costs nothing.
1172
1190
 
1191
+ **A stale bot verdict under a rate limit: substitute, then stop and report.**
1192
+ Under a rate limit or an exhausted review allowance, a bot's old
1193
+ `CHANGES_REQUESTED` on an outdated head can end up as the only thing blocking
1194
+ the merge. The bot cannot post a fresh review to replace it, so the verdict
1195
+ will not clear by itself while the throttle lasts. This was measured on a
1196
+ caller repo in the portfolio: every check green, zero unresolved threads, and
1197
+ the bot's verdict from an earlier head as the only blocker. In that case:
1198
+
1199
+ 1. **Do not wait for the window to reset, and do not re-request.** Waiting
1200
+ leaves the pull request wedged for an hour or more. A re-request under the
1201
+ throttle settles hollow and can take away the bot's standing review (see
1202
+ above).
1203
+ 2. Post the local adversarial review substitute for the **current** head, as
1204
+ step (d) case 3 describes, if one is not already there.
1205
+ 3. **Then stop** with `blocked:stale-bot-verdict` (section 4). Report exactly
1206
+ that blocker: the bot reviewer, the review id, the outdated head it reviewed
1207
+ and the current head, the unresolved thread count, and that the substitute
1208
+ is posted for the current head. Name the decision that is needed: a human
1209
+ with dismissal rights dismisses that review, or decides it must stand.
1210
+
1211
+ Do not dismiss it on the strength of your own substitute. Here the bot's review
1212
+ is the only third-party review on the pull request. Dismissing it because of a
1213
+ review this run wrote would make the agent both author and judge of the change.
1214
+ That is the escalation the bullet above requires, reached right away instead of
1215
+ after a wait. A stranded verdict that is **not** the only substantive review, or
1216
+ one left by a reviewer that is not throttled, is still handled by the
1217
+ dismissal rule above.
1218
+
1173
1219
  **Unverified, and stated as such rather than asserted:** that a bot's re-review
1174
1220
  REPLACES its predecessor in the effective set is inferred from the observed
1175
1221
  consequence, not measured against the vendor. It has not been tested here, and
@@ -1453,7 +1499,7 @@ Loop until one of:
1453
1499
  the mode forbids acting on them: `on_blocker=report`). The latch is
1454
1500
  deliberately not armed, so the PR sits OPEN rather than merging on a review
1455
1501
  nothing performed. Report the PR URL, the review context's settled
1456
- description, whether it is transient or standing, and which sole-gate
1502
+ description, whether it clears on its own (a rate limit) or is standing, and which sole-gate
1457
1503
  condition failed. This is an outcome that needs an operator, stated in one
1458
1504
  line a non-technical reader can act on — for example: *"PR #123 is ready to
1459
1505
  merge but nobody reviewed it: the review tool says it skips public
@@ -1483,6 +1529,16 @@ Loop until one of:
1483
1529
  — but a review asked for changes and that is still on record, so it will sit
1484
1530
  there forever. Someone needs to clear that review or resolve the open
1485
1531
  comments."* Never report this PR as merging.
1532
+ - **`blocked:stale-bot-verdict`** — the only thing blocking the merge is a
1533
+ bot's `CHANGES_REQUESTED` on an outdated head, the bot is rate limited or out
1534
+ of review allowance so it cannot replace that verdict, and the local
1535
+ adversarial review substitute is posted for the current head (step (e)).
1536
+ Report the reviewer, the review id, both heads, the unresolved thread count,
1537
+ and the dismissal decision a human needs to make. For example: *"PR #123 is
1538
+ ready except for an old review from the review bot on an earlier version. The
1539
+ bot is rate limited and cannot re-review, and I posted my own review of the
1540
+ current version. Someone with dismissal rights needs to dismiss review 456,
1541
+ or decide it should stand."* Do not wait for the bot's window to reset.
1486
1542
  - **`CLOSED`** → report (PR was closed without merge).
1487
1543
  - **Hard block needing a human**: an unresolvable conflict, a failing check that
1488
1544
  needs design input, or genuine unresolved human objection (not a bot gate). Stop
@@ -1591,7 +1647,8 @@ declare none, one, or several, and each shows its own evidence.
1591
1647
 
1592
1648
  Quote the description that was actually read. A report that says "rate limited"
1593
1649
  on a policy skip is a wrong record, and the two call for different operator
1594
- actions: one clears itself, the other never will.
1650
+ actions: one clears itself, the other never will. Neither changes what this
1651
+ skill does in the meantime: it substitutes and keeps driving in both cases.
1595
1652
 
1596
1653
  `NOT REVIEWED` is reporting, and on a merged PR it is never a terminal state of
1597
1654
  its own: it does not turn a merged PR into a blocked one. What it does gate is
@@ -73,6 +73,14 @@ node scripts/check-skipped-required-checks.mjs --pr=<pr> --json
73
73
  It reports and never fails — a hollow check is often a vendor spending cap, not
74
74
  a repository defect, and it is not this skill's call to block on one.
75
75
 
76
+ **Do not wait for a rate limit to reset, and do not re-request the review.** A
77
+ `Review rate limited` status, including decorated forms such as
78
+ `Review rate limited (retry in 12m)`, is handled like every other vacuous
79
+ review. Report it here. `lisa-drive-pr-to-merge` then posts a local adversarial
80
+ review substitute for the current head right away and keeps driving. Waiting
81
+ out the window stalls the pull request for an hour or more and reads no code.
82
+ Re-requesting overwrites the status and can destroy a real review.
83
+
76
84
  Carry the finding into your Step 4 report. **Do not write "no unresolved review
77
85
  threads" on its own** — it is true of an unreviewed PR too. Say which you
78
86
  observed:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.87.0",
3
+ "version": "4.87.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.87.0",
3
+ "version": "4.87.1",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"