@codyswann/lisa 3.14.4 → 3.14.6

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 (71) hide show
  1. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  2. package/dist/core/upstream-evidence-manifest.js +14 -2
  3. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  4. package/package.json +1 -1
  5. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  6. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  7. package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +54 -0
  8. package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +95 -0
  9. package/plugins/lisa/scripts/lifecycle-label-trust.mjs +494 -0
  10. package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +54 -0
  11. package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +95 -0
  12. package/plugins/lisa-agy/plugin.json +1 -1
  13. package/plugins/lisa-agy/scripts/lifecycle-label-trust.mjs +494 -0
  14. package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +54 -0
  15. package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +95 -0
  16. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  18. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  19. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-copilot/scripts/lifecycle-label-trust.mjs +494 -0
  23. package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +54 -0
  24. package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +95 -0
  25. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-cursor/scripts/lifecycle-label-trust.mjs +494 -0
  27. package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +54 -0
  28. package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +95 -0
  29. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  31. package/plugins/lisa-expo-agy/plugin.json +1 -1
  32. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  36. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  37. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  41. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  42. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  46. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  47. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  51. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  52. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  56. package/plugins/lisa-rails-agy/plugin.json +1 -1
  57. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  61. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  62. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  66. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  67. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  69. package/plugins/src/base/scripts/lifecycle-label-trust.mjs +494 -0
  70. package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +54 -0
  71. package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +95 -0
@@ -168,6 +168,60 @@ gh label list --repo <org>/<repo> --json name \
168
168
 
169
169
  If none of the configured role labels exist on the repo → label convention not adopted, surface a setup error and exit. If the role labels exist but none are `$READY` on any open issue matching the resolved assignee filter (or any open issue when the filter is empty) → genuinely empty queue, exit cleanly with `"No GitHub issues labeled $READY. Nothing to do."`
170
170
 
171
+ #### 2b. Lifecycle-label trust resolution (bot-authored labels are not signals)
172
+
173
+ **A `status:*` label is only a lifecycle signal if a trustworthy actor applied it.** Third-party GitHub Apps write labels through the same API humans do, and at least one — `coderabbitai[bot]` — stamps `status:*` on issues seconds after filing. Measured on CodySwannGT/lisa#2460–#2540: seven of eight bot-applied lifecycle labels landed 26–118s after creation. Those labels are guesses wearing the costume of the intake contract, and they break the queue in **both** directions:
174
+
175
+ - a bot-applied **`$CLAIMED`** makes an unworked issue look like somebody's active work, so no cycle picks it up and no human re-examines it (#2470 sat unworked for a day this way);
176
+ - a bot-applied **`$READY`** puts an issue into the build queue that no human ever flipped ready (#2538), inverting the gate the ready role exists to be.
177
+
178
+ Before treating any candidate's lifecycle labels as meaningful, resolve which ones are trustworthy:
179
+
180
+ ```bash
181
+ TRUST_DIR=$(mktemp -d)
182
+ trap 'rm -rf "$TRUST_DIR"' EXIT
183
+
184
+ gh api "repos/<org>/<repo>/issues/<n>" > "$TRUST_DIR/issue.json"
185
+
186
+ # --paginate emits ONE ARRAY PER PAGE. Reading `$t[0]` would pass only page one,
187
+ # silently dropping later label events — the newest of which is exactly the
188
+ # application this classifier keys on. --slurp + `add` flattens all pages.
189
+ gh api "repos/<org>/<repo>/issues/<n>/timeline?per_page=100" --paginate --slurp \
190
+ > "$TRUST_DIR/pages.json"
191
+ jq 'add // []' "$TRUST_DIR/pages.json" > "$TRUST_DIR/timeline.json"
192
+
193
+ # Resolve config the SAME way `read_role` does: the local file overrides the
194
+ # global one key by key. Reading only `.lisa.config.json` would resolve a stale
195
+ # terminal `done` label for any project that overrides it locally, and
196
+ # `lisa-repair-intake` WRITES on the drift direction that mistake produces.
197
+ # Both files are optional — a missing one must not abort the cycle.
198
+ jq -s '(.[0] // {}) * (.[1] // {})' \
199
+ <(cat .lisa.config.json 2>/dev/null || echo '{}') \
200
+ <(cat .lisa.config.local.json 2>/dev/null || echo '{}') \
201
+ > "$TRUST_DIR/config.json"
202
+
203
+ jq -n --slurpfile i "$TRUST_DIR/issue.json" \
204
+ --slurpfile t "$TRUST_DIR/timeline.json" \
205
+ --slurpfile c "$TRUST_DIR/config.json" \
206
+ '{issue: $i[0], timeline: $t[0], config: $c[0]}' \
207
+ > "$TRUST_DIR/input.json"
208
+
209
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/lifecycle-label-trust.mjs" < "$TRUST_DIR/input.json"
210
+ ```
211
+
212
+ The temp directory is **per invocation**. Fixed `/tmp/lisa-*.json` paths let two concurrent intake cycles interleave one issue's metadata with another's timeline, which yields a confident verdict about an item that was never examined.
213
+
214
+ The classifier returns `trusted`, `untrusted`, `unknownProvenance`, and a per-label `evaluated` list carrying the actor and the latency behind each decision. **Use `trusted` wherever this skill would otherwise read the raw label set**, and specifically:
215
+
216
+ - a candidate whose `$READY` is **untrusted** is **not claimable** — skip it and leave it for a human to flip genuinely ready; report it in the summary rather than dispatching it;
217
+ - a candidate whose `$CLAIMED` is **untrusted** is **not claimed** — if its `$READY` is trusted it stays a normal candidate, exactly as if the bot label were absent.
218
+
219
+ **Never unlabel to correct this.** The bot re-applies its label on each subsequent review event, so reverting produces a label-flap loop that is worse than the defect. The guard is that intake stops *believing* the label; it writes nothing. Distrust is idempotent and cannot race.
220
+
221
+ A label whose provenance cannot be established (applied at creation, which GitHub records no `labeled` event for) is trusted but listed in `unknownProvenance` — failing closed there would ignore the human `status:ready` that opens the queue. Report that list; do not silently drop it.
222
+
223
+ Lifecycle membership is decided by the **`status:` prefix**, never by a pinned member list. The live family has drifted 7 → 6 members, and a literal set breaks silently: an unrecognised member simply fails to match, so the guard would report clean on exactly the case it stopped covering.
224
+
171
225
  ### Phase 3 — Process the first eligible ready issue
172
226
 
173
227
  #### 3a.0 Repo-scope gate (claim only current-repo issues)
@@ -560,6 +560,101 @@ native-open / active / unresolved:
560
560
  4. Post a compact `[lisa-repair-intake]` note only when the native close-out changed state or when
561
561
  an actionable setup error must be surfaced. Do not spam already-closed terminal items.
562
562
 
563
+ ### Lifecycle label contradicts native state — walk BOTH directions
564
+
565
+ A lifecycle label can lie in two ways, and historically only one of them had an owner:
566
+
567
+ | label | native state | owned by |
568
+ |---|---|---|
569
+ | terminal `done` role | still open / active | the `Build terminal-open` section above |
570
+ | non-terminal role (`ready`, `claimed`, `blocked`, or any other `status:` member) | closed / completed | **nothing, until now** |
571
+
572
+ A pass that walks one direction leaves the other accumulating silently. Measured on the Linear TUN
573
+ board: **TUN-556 and TUN-503 both carry a terminal `status:done` while still natively open in
574
+ `On Dev`** — invisible to intake and indistinguishable from handled, exactly like a bot-applied
575
+ `status:in-progress` on GitHub.
576
+
577
+ Resolve both directions in one pass with the shipped detector, which always reports
578
+ `directionsWalked` covering both, so a "clean" verdict is an assertion that both were examined.
579
+
580
+ **Build the classifier input inside this cycle. Never consume a temp file another skill wrote.**
581
+ repair-intake runs as its own cycle, so borrowing `lisa-github-build-intake`'s scratch file fails
582
+ two ways: absent, the redirect fails and `set -e` aborts the whole cycle; stale from an earlier run
583
+ on a *different* item, the resolver classifies that other item and this section reports `drifts: []`
584
+ while `directionsWalked` still claims both directions were walked. That is precisely the
585
+ silent-clean verdict this section promises cannot happen.
586
+
587
+ ```bash
588
+ TRUST_DIR=$(mktemp -d)
589
+ trap 'rm -rf "$TRUST_DIR"' EXIT
590
+
591
+ gh api "repos/<org>/<repo>/issues/<n>" > "$TRUST_DIR/issue.json"
592
+
593
+ # --paginate emits ONE ARRAY PER PAGE; --slurp + `add` flattens all of them so a
594
+ # label event on page two is not silently dropped.
595
+ gh api "repos/<org>/<repo>/issues/<n>/timeline?per_page=100" --paginate --slurp \
596
+ > "$TRUST_DIR/pages.json"
597
+ jq 'add // []' "$TRUST_DIR/pages.json" > "$TRUST_DIR/timeline.json"
598
+
599
+ # Same resolution `read_role` uses: local overrides global, both optional.
600
+ # Resolving a stale terminal `done` here would make the true terminal label look
601
+ # like `open-label-closed-state` — and that direction WRITES.
602
+ jq -s '(.[0] // {}) * (.[1] // {})' \
603
+ <(cat .lisa.config.json 2>/dev/null || echo '{}') \
604
+ <(cat .lisa.config.local.json 2>/dev/null || echo '{}') \
605
+ > "$TRUST_DIR/config.json"
606
+
607
+ jq -n --slurpfile i "$TRUST_DIR/issue.json" \
608
+ --slurpfile t "$TRUST_DIR/timeline.json" \
609
+ --slurpfile c "$TRUST_DIR/config.json" \
610
+ '{issue: $i[0], timeline: $t[0], config: $c[0]}' \
611
+ > "$TRUST_DIR/input.json"
612
+
613
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/lifecycle-label-trust.mjs" < "$TRUST_DIR/input.json"
614
+ ```
615
+
616
+ **Untrusted labels are excluded from `drifts` before any repair runs** — the classifier does this
617
+ itself, so repair must **never act on a label the classifier refused to believe**. Without it, a
618
+ bot-applied label on a natively closed item would be advanced to the terminal `done` role by the
619
+ `open-label-closed-state` repair, laundering the exact input the guard rejected into a real write.
620
+ The `excluded` array reports what was held back; surface it, do not repair it.
621
+
622
+ 1. **`terminal-label-open-state`** → hand to the `Build terminal-open → native close` section above.
623
+ Do not restate its rules; the terminality test lives there (intermediate env rungs like
624
+ `status:on-dev` / `status:on-stg` are **not** terminal).
625
+ 2. **`open-label-closed-state`** → the previously unowned direction. The item is natively closed or
626
+ completed while still wearing a non-terminal lifecycle role. Advance the label to the env-resolved
627
+ terminal `done` role and post one idempotent `[lisa-repair-intake]` note. This is a write on
628
+ **Lisa's own** lifecycle surface, not a contest with another writer.
629
+ Apply the leaf/container check from the **Lifecycle ownership guard** section *before* this
630
+ branch: repair-intake owns container repair, so a natively-closed `ready` **leaf** is skipped
631
+ here and left to the build lane rather than claimed by this pass.
632
+ 3. **Vendor caveat — Linear.** On Linear the lifecycle surface is the native workflow **state**, not a
633
+ `status:*` label (see `config-resolution`). A `status:*` label there is leftover cruft that no
634
+ repair direction reads, which is precisely why TUN-556 and TUN-503 rotted. Treat Linear's native
635
+ state as authoritative and remove the contradicting stale label; never move the state to match a
636
+ label.
637
+
638
+ Membership in the lifecycle namespace is decided by the **`status:` prefix**, never a pinned member
639
+ list — the live family has drifted 7 → 6 members, and a literal set fails silently by simply not
640
+ matching the member it stopped covering.
641
+
642
+ ### Bot-authored lifecycle label → distrust, never revert (read-only)
643
+
644
+ `status:*` labels written by a **bot** actor within the plausibility window of the item's creation are
645
+ not lifecycle signals — see `lisa-github-build-intake` Phase 2b for the measurement and the
646
+ classifier. Report them here so an operator can see how much of the board is wearing a label nobody
647
+ chose:
648
+
649
+ - list each item alongside the untrusted label, the bot login, and the latency, from the classifier's
650
+ `untrusted` array;
651
+ - list `unknownProvenance` labels separately — trusted, but unattributable;
652
+ - **do not unlabel and do not relabel.** The bot re-applies on each subsequent review event, so a
653
+ reverting reconciler produces a label-flap loop that is worse than the defect. Repair happens by
654
+ intake declining to *believe* the label, which is idempotent and writes nothing.
655
+
656
+ This class is deliberately **read-only** and never counts toward the repair cap's actionable work.
657
+
563
658
  ### Build parent rollup reconciliation (intermediate-env or terminal close-out)
564
659
 
565
660
  For each parent/container item (an Epic, a Linear Project, or any item — of any type — with open child work),
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "3.14.4",
3
+ "version": "3.14.6",
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": "3.14.4",
3
+ "version": "3.14.6",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "3.14.4",
3
+ "version": "3.14.6",
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": "3.14.4",
3
+ "version": "3.14.6",
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": "3.14.4",
3
+ "version": "3.14.6",
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",
3
- "version": "3.14.4",
3
+ "version": "3.14.6",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"