@codyswann/lisa 4.38.6 → 4.38.8

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 (99) hide show
  1. package/all/copy-overwrite/scripts/lib/gate-failure-diagnosis.mjs +23 -1
  2. package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +23 -0
  3. package/all/copy-overwrite/scripts/lisa-run-gates.mjs +30 -1
  4. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  5. package/dist/core/lisa-owned-hash-ledger.js +6 -0
  6. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  7. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  8. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  9. package/dist/core/upstream-evidence-manifest.js +13 -10
  10. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  11. package/dist/opencode/plugin-templates/parity-safety-net.sh +23 -0
  12. package/package.json +4 -4
  13. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  14. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  15. package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +1 -1
  16. package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +1 -1
  17. package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +1 -1
  18. package/plugins/lisa/.codex-plugin/skills/lisa-tracker-build-intake/SKILL.md +1 -1
  19. package/plugins/lisa/hooks/parity-safety-net.sh +23 -0
  20. package/plugins/lisa/rules/eager/claim-time-guards.md +4 -2
  21. package/plugins/lisa/rules/reference/claim-time-guards.md +29 -4
  22. package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +1 -1
  23. package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +1 -1
  24. package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +1 -1
  25. package/plugins/lisa/skills/lisa-tracker-build-intake/SKILL.md +1 -1
  26. package/plugins/lisa-agy/hooks/parity-safety-net.sh +23 -0
  27. package/plugins/lisa-agy/plugin.json +1 -1
  28. package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +1 -1
  29. package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +1 -1
  30. package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +1 -1
  31. package/plugins/lisa-agy/skills/lisa-tracker-build-intake/SKILL.md +1 -1
  32. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  34. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  35. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-copilot/hooks/parity-safety-net.sh +23 -0
  39. package/plugins/lisa-copilot/rules/eager/claim-time-guards.md +4 -2
  40. package/plugins/lisa-copilot/rules/reference/claim-time-guards.md +29 -4
  41. package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +1 -1
  42. package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +1 -1
  43. package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +1 -1
  44. package/plugins/lisa-copilot/skills/lisa-tracker-build-intake/SKILL.md +1 -1
  45. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-cursor/hooks/parity-safety-net.sh +23 -0
  47. package/plugins/lisa-cursor/rules/claim-time-guards-reference.mdc +29 -4
  48. package/plugins/lisa-cursor/rules/claim-time-guards.mdc +4 -2
  49. package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +1 -1
  50. package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +1 -1
  51. package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +1 -1
  52. package/plugins/lisa-cursor/skills/lisa-tracker-build-intake/SKILL.md +1 -1
  53. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  55. package/plugins/lisa-expo-agy/plugin.json +1 -1
  56. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  60. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  61. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  65. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  66. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  70. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  71. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  75. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  76. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  80. package/plugins/lisa-rails-agy/plugin.json +1 -1
  81. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  84. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  85. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  86. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  87. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  88. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  89. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  90. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  91. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  92. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  93. package/plugins/src/base/hooks/parity-safety-net.sh +23 -0
  94. package/plugins/src/base/rules/eager/claim-time-guards.md +4 -2
  95. package/plugins/src/base/rules/reference/claim-time-guards.md +29 -4
  96. package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +1 -1
  97. package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +1 -1
  98. package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +1 -1
  99. package/plugins/src/base/skills/lisa-tracker-build-intake/SKILL.md +1 -1
@@ -425,7 +425,7 @@ A blocker is active if it is open and has no cleared status label. Treat `status
425
425
 
426
426
  **The two `claim-time-guards` run third and fourth — still before the relabel below.** Both semantics live in that one vendor-neutral slug; do not restate them here. GitHub wiring only:
427
427
 
428
- 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the issue from the read bundle's comments (match on the marker, never the title). With two or more, do **not** claim: relabel to the configured blocked role (`gh issue edit <number> --repo <org>/<repo> --remove-label "$READY" --add-label "$BLOCKED"`, resolved from `github.labels.build.blocked` per `config-resolution`), post the operator-readable comment naming both attempts, and **stop the cycle** at Phase 3e. Every non-success terminal outcome recorded in 3c/3d also appends a fresh `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> -->` marker so the next cycle can count it.
428
+ 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the issue from the read bundle's comments (match on the marker, never the title), applying both filters from `claim-time-guards`: count a marker only when it carries `measures=work` (a marker with no `measures=` counts as `work`), and only when its `createdAt` is **after the issue most recently gained the ready label**. The ready-lane entry comes from the read bundle's `LabeledEvent` stream, which is already fetched — no extra call. If that history is `unknown`, count every `measures=work` marker regardless of age and say so in the comment. With two or more surviving markers, do **not** claim: relabel to the configured blocked role (`gh issue edit <number> --repo <org>/<repo> --remove-label "$READY" --add-label "$BLOCKED"`, resolved from `github.labels.build.blocked` per `config-resolution`), post the operator-readable comment naming both attempts, and **stop the cycle** at Phase 3e. Every non-success terminal outcome recorded in 3c/3d also appends a fresh `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> measures=<work|machine> -->` marker so the next cycle can count it — `measures=machine` when the run was terminated by a signal or its outcome was `recovery-required`, `measures=work` when the build ran and did not satisfy the issue.
429
429
  2. **`already-implemented` check.** Probe for this issue's own key — `git log --all --grep "<org>/<repo>#<number>"` and `gh pr list --repo <org>/<repo> --state all --search "<org>/<repo>#<number>" --json number,state,mergedAt,url`. On a hit, claim as normal but route 3c to **verify-and-close** instead of `lisa-implement`: verify what shipped against the issue's acceptance criteria, post evidence via `lisa-github-evidence` naming the shipping PR/commit, then run the ordinary 3d transition and 3d.1 rollup. A partial hit implements only the remaining gap. An unreadable history degrades to "no hit" and the ordinary path proceeds — the guard never blocks the claim. This is not `DUPLICATE_ALREADY_FIXED` (a *different* canonical issue) and not `claim-archaeology` (a *different* ancestor issue); it is this issue's own work already having shipped without a transition.
430
430
 
431
431
  ```bash
@@ -306,7 +306,7 @@ This gate never blocks a legitimate flat Task/Bug: those have no open children a
306
306
 
307
307
  **The two `claim-time-guards` run third and fourth — still before the transition below.** Both semantics live in that one vendor-neutral slug; do not restate them here. JIRA wiring only:
308
308
 
309
- 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the ticket from the read bundle's comments (match on the marker, never the summary). With two or more, do **not** claim: transition to the configured blocked status (`lisa-atlassian-access operation: transition to: "$BLOCKED"`, resolved from `jira.workflow.blocked` per `config-resolution`), post the operator-readable comment naming both attempts, and **stop the cycle** at Phase 3e. Every non-success terminal outcome recorded in 3c/3d also appends a fresh `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> -->` marker so the next cycle can count it.
309
+ 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the ticket from the read bundle's comments (match on the marker, never the summary), applying both filters from `claim-time-guards`: count a marker only when it carries `measures=work` (a marker with no `measures=` counts as `work`), and only when its timestamp is **after the ticket most recently transitioned into the ready status**. Read that transition with `lisa-atlassian-access operation: changelog key:<K>` — `read-ticket` uses `fields=*all`, which does **not** include the changelog, so this is an explicit extra read. If the changelog cannot be read, count every `measures=work` marker regardless of age and say so in the comment. With two or more surviving markers, do **not** claim: transition to the configured blocked status (`lisa-atlassian-access operation: transition to: "$BLOCKED"`, resolved from `jira.workflow.blocked` per `config-resolution`), post the operator-readable comment naming both attempts, and **stop the cycle** at Phase 3e. Every non-success terminal outcome recorded in 3c/3d also appends a fresh `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> measures=<work|machine> -->` marker so the next cycle can count it — `measures=machine` when the run was terminated by a signal or its outcome was `recovery-required`, `measures=work` when the build ran and did not satisfy the ticket.
310
310
  2. **`already-implemented` check.** Probe for this ticket's own key — `git log --all --grep "<TICKET>"` and the merged/open PRs referencing `<TICKET>` (`gh pr list --state all --search "<TICKET>"` in the bound repo). On a hit, claim as normal but route 3c to **verify-and-close** instead of `lisa-implement`: verify what shipped against the ticket's acceptance criteria, post evidence via `lisa-jira-evidence` naming the shipping PR/commit, then run the ordinary 3d transition and rollup. A partial hit implements only the remaining gap. An unreadable history degrades to "no hit" and the ordinary path proceeds — the guard never blocks the claim. This is not `DUPLICATE_ALREADY_FIXED` (a *different* canonical ticket) and not `claim-archaeology` (a *different* ancestor ticket); it is this ticket's own work already having shipped without a transition.
311
311
 
312
312
  Transition the ticket from `$READY` to `$CLAIMED` by invoking `lisa-atlassian-access` `operation: transition key: <TICKET> to: "$CLAIMED"`.
@@ -302,7 +302,7 @@ This gate never blocks a legitimate flat Task/Bug: those have no open children a
302
302
 
303
303
  **The two `claim-time-guards` run third and fourth — still before the transition below.** Both semantics live in that one vendor-neutral slug; do not restate them here. Linear wiring only:
304
304
 
305
- 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the Issue from the read bundle's comments (match on the marker, never the title). With two or more, do **not** claim: invoke `lisa-linear-access operation: save-issue lifecycle_role: blocked` (the access layer resolves `linear.workflow.blocked` itself per `config-resolution`; this skill supplies the role, never a state ID), post the operator-readable comment naming both attempts via `save-comment`, and **stop the cycle** at Phase 3e. Every non-success terminal outcome recorded in 3c/3d also appends a fresh `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> -->` marker so the next cycle can count it.
305
+ 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the Issue from the read bundle's comments (match on the marker, never the title), applying both filters from `claim-time-guards`: count a marker only when it carries `measures=work` (a marker with no `measures=` counts as `work`), and only when its timestamp is **after the Issue most recently entered the ready state**. Read that transition with `lisa-linear-access operation: history id:<ID>`. If the history cannot be read, count every `measures=work` marker regardless of age and say so in the comment. With two or more surviving markers, do **not** claim: invoke `lisa-linear-access operation: save-issue lifecycle_role: blocked` (the access layer resolves `linear.workflow.blocked` itself per `config-resolution`; this skill supplies the role, never a state ID), post the operator-readable comment naming both attempts via `save-comment`, and **stop the cycle** at Phase 3e. Every non-success terminal outcome recorded in 3c/3d also appends a fresh `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> measures=<work|machine> -->` marker so the next cycle can count it — `measures=machine` when the run was terminated by a signal or its outcome was `recovery-required`, `measures=work` when the build ran and did not satisfy the Issue.
306
306
  2. **`already-implemented` check.** Probe for this Issue's own key — `git log --all --grep "<IDENTIFIER>"` and the merged/open PRs referencing `<IDENTIFIER>` (`gh pr list --state all --search "<IDENTIFIER>"` in the bound repo; Linear's own GitHub attachments in the read bundle are the cheaper first look). On a hit, claim as normal but route 3c to **verify-and-close** instead of `lisa-implement`: verify what shipped against the Issue's acceptance criteria, post evidence via `lisa-linear-evidence` naming the shipping PR/commit, then run the ordinary 3d transition and rollup. A partial hit implements only the remaining gap. An unreadable history degrades to "no hit" and the ordinary path proceeds — the guard never blocks the claim. This is not `DUPLICATE_ALREADY_FIXED` (a *different* canonical Issue) and not `claim-archaeology` (a *different* ancestor Issue); it is this Issue's own work already having shipped without a transition.
307
307
 
308
308
  Transition the Issue via `lisa-linear-access operation: save-issue lifecycle_role: claimed`. The access layer resolves the `claimed` role's exact configured state against the team catalog and dispatches that ID; a missing or ambiguous `$CLAIMED` state is a setup defect it refuses on (see the pre-flight check) — never create one here.
@@ -107,5 +107,5 @@ If the canonical fix is merged but not yet on the production branch, the close c
107
107
  - **Leaf-only dispatch, every vendor.** Per the `leaf-only-lifecycle` rule, each vendor scanner dispatches leaf work units only and moves or safe-blocks a container (open child work, or a childless Epic) carrying a stale build-ready role according to its lifecycle semantics. This shim does not re-implement the gate — it relies on the vendor scanner's Phase 3a — but the contract is uniform across `jira`, `github`, and `linear` so behavior never drifts by tracker.
108
108
  - **Terminal native closure, every capable vendor.** Per the same rule, each vendor scanner finalizes native open/closed state only at the true terminal `done` value. This shim never performs native closure itself, but callers can rely on the dispatched vendor scanner to apply the contract.
109
109
  - **Duplicate already fixed, every vendor.** Auto-close without a PR is allowed only for `DUPLICATE_ALREADY_FIXED` with canonical reference and empirical base-branch evidence. Do not conflate this with `BLOCKED`.
110
- - **Claim-time guards, every vendor.** Per the `claim-time-guards` rule, each vendor scanner runs both guards inside its Phase 3b before the claim transition: an item whose own key already appears in git history or an open/merged PR routes to **verify-and-close** rather than being built twice, and the **`two-failed-attempts`** valve moves an item with two `[lisa-build-attempt]` markers to the configured blocked role and stops the cycle. This shim does not re-implement either guard; it forwards the contract so behavior never drifts by tracker.
110
+ - **Claim-time guards, every vendor.** Per the `claim-time-guards` rule, each vendor scanner runs both guards inside its Phase 3b before the claim transition: an item whose own key already appears in git history or an open/merged PR routes to **verify-and-close** rather than being built twice, and the **`two-failed-attempts`** valve moves an item with two counting `[lisa-build-attempt]` markers to the configured blocked role and stops the cycle. A marker counts only when it is `measures=work` and was recorded after the item most recently entered the ready lane — every vendor applies both filters, reading lane history from the substrate that already exposes it (GitHub label events, JIRA `changelog`, Linear `history`). This shim does not re-implement either guard; it forwards the contract so behavior never drifts by tracker.
111
111
  - Never run two intake cycles concurrently against overlapping queues — the scheduling layer is responsible for serialization.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -901,6 +901,7 @@ follow_scan() {
901
901
  redirected=""
902
902
  heredoc=0
903
903
  stdin_mode=0
904
+ noexec=0
904
905
  j=$((i + 1))
905
906
  while [ "$j" -lt "$n" ]; do
906
907
  follow_unwrap "${toks[j]}"
@@ -931,13 +932,35 @@ follow_scan() {
931
932
  *) j=$((j + 1)) ;;
932
933
  esac
933
934
  ;;
935
+ # `-n` is NOEXEC: the shell reads and parses its operand, then exits
936
+ # without running a line of it. So a syntax check is the one shape
937
+ # that puts a path at a command position while provably executing
938
+ # nothing, and following it reads a file the command never runs.
939
+ #
940
+ # This guard hit that on ITSELF: its pattern list is destructive
941
+ # command literals living inside the guard, so `bash -n` on its own
942
+ # source was refused by its own patterns — and the same held for any
943
+ # file documenting destructive commands. See CodySwannGT/lisa#3803.
944
+ #
945
+ # `bash <file>` still executes and is still followed. Noexec is the
946
+ # distinction, not the program: this is not a read-only exemption.
947
+ --noexec) noexec=1; break ;;
934
948
  --*) j=$((j + 1)) ;;
935
949
  -*c*) inline=1; j=$((j + 1)) ;;
950
+ -*n*) noexec=1; break ;;
936
951
  -s | -[a-zA-Z]*s[a-zA-Z]*) stdin_mode=1; j=$((j + 1)) ;;
937
952
  -*) j=$((j + 1)) ;;
938
953
  *) break ;;
939
954
  esac
940
955
  done
956
+ if [ "$noexec" -eq 1 ]; then
957
+ # Nothing runs, so there is no script to follow and nothing to fail
958
+ # closed about. Checked before the heredoc and dispatcher arms: those
959
+ # decide WHICH text to read, and here there is no execution at all.
960
+ cmd_pos=0
961
+ i=$((j + 1))
962
+ continue
963
+ fi
941
964
  if [ "$heredoc" -eq 1 ] && [ "$inline" -eq 0 ]; then
942
965
  cmd_pos=0
943
966
  i=$((j + 1))
@@ -60,15 +60,40 @@ A hit counts only when it names **this** key. Branch-name coincidence, a similar
60
60
 
61
61
  ```text
62
62
  Build attempt <N> did not complete: <one-line operator-readable reason>.
63
- <!-- [lisa-build-attempt] n=<N> outcome=<outcome> -->
63
+ <!-- [lisa-build-attempt] n=<N> outcome=<outcome> measures=<work|machine> -->
64
64
  ```
65
65
 
66
- The marker line is verbatim; the count is the number of `[lisa-build-attempt]` markers on the item. Match on the **marker, never the title**. A successful build records no marker, so an item that shipped after one bad attempt starts clean if it is ever re-filed.
66
+ The marker line is verbatim. Match on the **marker, never the title**. A successful build records no marker, so an item that shipped after one bad attempt starts clean if it is ever re-filed.
67
67
 
68
- **The threshold is two.** At the top of the claim, count existing markers. With **two or more**, do not claim:
68
+ **`measures=` says what the attempt is evidence about, and only `work` is counted.**
69
+
70
+ - `measures=work` — the build ran and did not satisfy the item. That is evidence about *this item*: the code, the criteria, the spec.
71
+ - `measures=machine` — the run was terminated rather than answered, or the loop could not complete for a reason outside the item: a gate killed under load, a substrate or access failure, an out-of-memory reap. That is evidence about *the box*, and the item is a bystander.
72
+
73
+ A run whose exit code is one of the terminating signals — the set `gate-failure-diagnosis` already names as *"the ones that actually terminate a gate on this fleet: an operator's Ctrl-C, an out-of-memory reap, a CPU-time limit, and the SIGTERM a saturated box hands out"* — is `measures=machine`. So is any run whose own outcome is `recovery-required`, which the automation runbook contract already defines as *"the loop itself could not complete (access, tooling, or substrate broken)"*. Both discriminators are shipped and already correct; this field is what carries their answer to the counter.
74
+
75
+ **Why this is not optional.** A pre-push gate killed by machine contention is errored, gate-blocked, and unmerged all at once — three non-success outcomes from one event that proved nothing about the work. Counting it retires items during exactly the busy periods when nobody is watching, and the item's own history then testifies that it failed twice, which is true and completely misleading.
76
+
77
+ **Both fields must be written even when the answer is obvious.** A marker with no `measures=` is counted as `work` — the conservative reading, because an unlabelled attempt is more likely an old marker than a machine failure, and a valve that fails open is the infinite re-claim loop this guard exists to prevent.
78
+
79
+ **The count is scoped to the current ready-lane period.** Count only markers recorded **after the item most recently entered the ready lane**. Markers older than that describe a period a human has already responded to; they stay on the item as history and stop being evidence about the attempt in front of you.
80
+
81
+ The lane history is already available on every tracker, and for a near-identical purpose — rejection detection reads it to spot an item that reached review and came back:
82
+
83
+ - **GitHub** — the `LabeledEvent` / `UnlabeledEvent` stream is already in the read bundle. No extra call.
84
+ - **JIRA** — `lisa-atlassian-access operation: changelog key:<K>`. `read-ticket` uses `fields=*all`, which does **not** include it; the expansion must be requested explicitly.
85
+ - **Linear** — `lisa-linear-access operation: history id:<ID>`.
86
+
87
+ **If the lane history cannot be read, count every `measures=work` marker regardless of age** and say so in the comment. Degrading to the unscoped count keeps the valve intact; degrading to "count nothing" would reopen the infinite re-claim loop. A history read failure must never *strand* an item either — it narrows recovery, it does not block the claim outright.
88
+
89
+ **The threshold is two.** At the top of the claim, count the markers that survive both filters. With **two or more**, do not claim:
69
90
 
70
91
  1. Move the item to the configured `blocked` role (`build.blocked` / `workflow.blocked`, resolved per `config-resolution` — never a hardcoded lane).
71
92
  2. Post an operator-readable comment naming both prior attempts, what each one hit, and what a human would need to decide or supply. Written for a non-technical operator, per `report-actionability`.
72
93
  3. **Stop the loop** — end the cycle without claiming anything else. Stopping is the point: the next scheduled invocation should not immediately pick up the next item as though nothing happened.
73
94
 
74
- **Recovery is deliberate.** A blocked item returns to the queue only when a human (or `lisa-repair-intake`, once the named blocker is provably cleared) moves it back. The attempt markers stay on the item as history; re-entering the ready lane after a real fix is a fresh claim whose markers describe why it was hard, not a silent reset of the counter.
95
+ **Recovery is deliberate, and it works.** A blocked item returns to the queue only when a human (or `lisa-repair-intake`, once the named blocker is provably cleared) moves it back. The attempt markers stay on the item as permanent history — nothing deletes them, and comments could not be deleted even if something wanted to. What the return *does* is end the period those markers describe: the next claim counts from the new ready-lane entry, so an item that was fixed and requeued is claimable, while an item that keeps failing accumulates fresh markers inside the new period and is stopped again by the same valve.
96
+
97
+ Re-entering the ready lane is therefore the discharge, and it is deliberate by construction — a person or a repair cycle has to do it. That is not a silent reset: nothing resets, the window moves.
98
+
99
+ **This paragraph used to describe behaviour the code did not have** (CodySwannGT/lisa#3854). The count was unscoped and taken fresh at every claim, so an item with two markers was refused on re-entry — the recovery this section documents could not run, and a human fixing the real cause and requeueing would watch the loop re-block it every cycle, forever. **The prose was doing the opposite of its job**: an auditor reading a section headed "Recovery is deliberate" sees a control that is covered and stops checking, so the documentation is what prevented anyone from noticing. Keep this note. A recovery path that is described but inert is worse than one that is absent, because an absent path invites the question "so how does this ever end?" and a documented one answers it wrongly.
@@ -28,8 +28,10 @@ Distinct from `claim-archaeology` (finds a **different** ancestor issue) and fro
28
28
 
29
29
  ## `two-failed-attempts` → blocked
30
30
 
31
- Every non-success terminal outcome records a durable marker on the item — a visible line plus `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> -->` (match on the marker, never the title). A cron holds no memory between cycles, so the item carries the count.
31
+ Every non-success terminal outcome records a durable marker on the item — a visible line plus `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> measures=<work|machine> -->` (match on the marker, never the title). A cron holds no memory between cycles, so the item carries the count.
32
32
 
33
- With **two or more** markers at claim time: do not claim. Move the item to the configured `blocked` role (resolved per `config-resolution`, never hardcoded), post an operator-readable comment naming both attempts and what a human must decide or supply, and **stop the loop** for this cycle. Recovery is deliberate — a human or a `lisa-repair-intake` cycle with the blocker provably cleared returns it to the queue.
33
+ **Two filters before counting.** Count a marker only when it is `measures=work` — a run terminated by a signal, or whose outcome was `recovery-required`, measures the box and not the item — and only when it was recorded **after the item most recently entered the ready lane**. An unlabelled marker counts as `work`; an unreadable lane history falls back to counting every `work` marker. Both defaults keep the valve shut rather than open (CodySwannGT/lisa#3854).
34
+
35
+ With **two or more** surviving markers at claim time: do not claim. Move the item to the configured `blocked` role (resolved per `config-resolution`, never hardcoded), post an operator-readable comment naming both attempts and what a human must decide or supply, and **stop the loop** for this cycle. Recovery is deliberate and it works — a human or a `lisa-repair-intake` cycle with the blocker provably cleared returns it to the queue, which ends the period the old markers describe without deleting them.
34
36
 
35
37
  Full contract (probe bounds, verify-and-close steps, partial-hit handling, marker mechanics): [reference/claim-time-guards.md](claim-time-guards-reference.mdc).
@@ -425,7 +425,7 @@ A blocker is active if it is open and has no cleared status label. Treat `status
425
425
 
426
426
  **The two `claim-time-guards` run third and fourth — still before the relabel below.** Both semantics live in that one vendor-neutral slug; do not restate them here. GitHub wiring only:
427
427
 
428
- 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the issue from the read bundle's comments (match on the marker, never the title). With two or more, do **not** claim: relabel to the configured blocked role (`gh issue edit <number> --repo <org>/<repo> --remove-label "$READY" --add-label "$BLOCKED"`, resolved from `github.labels.build.blocked` per `config-resolution`), post the operator-readable comment naming both attempts, and **stop the cycle** at Phase 3e. Every non-success terminal outcome recorded in 3c/3d also appends a fresh `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> -->` marker so the next cycle can count it.
428
+ 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the issue from the read bundle's comments (match on the marker, never the title), applying both filters from `claim-time-guards`: count a marker only when it carries `measures=work` (a marker with no `measures=` counts as `work`), and only when its `createdAt` is **after the issue most recently gained the ready label**. The ready-lane entry comes from the read bundle's `LabeledEvent` stream, which is already fetched — no extra call. If that history is `unknown`, count every `measures=work` marker regardless of age and say so in the comment. With two or more surviving markers, do **not** claim: relabel to the configured blocked role (`gh issue edit <number> --repo <org>/<repo> --remove-label "$READY" --add-label "$BLOCKED"`, resolved from `github.labels.build.blocked` per `config-resolution`), post the operator-readable comment naming both attempts, and **stop the cycle** at Phase 3e. Every non-success terminal outcome recorded in 3c/3d also appends a fresh `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> measures=<work|machine> -->` marker so the next cycle can count it — `measures=machine` when the run was terminated by a signal or its outcome was `recovery-required`, `measures=work` when the build ran and did not satisfy the issue.
429
429
  2. **`already-implemented` check.** Probe for this issue's own key — `git log --all --grep "<org>/<repo>#<number>"` and `gh pr list --repo <org>/<repo> --state all --search "<org>/<repo>#<number>" --json number,state,mergedAt,url`. On a hit, claim as normal but route 3c to **verify-and-close** instead of `lisa-implement`: verify what shipped against the issue's acceptance criteria, post evidence via `lisa-github-evidence` naming the shipping PR/commit, then run the ordinary 3d transition and 3d.1 rollup. A partial hit implements only the remaining gap. An unreadable history degrades to "no hit" and the ordinary path proceeds — the guard never blocks the claim. This is not `DUPLICATE_ALREADY_FIXED` (a *different* canonical issue) and not `claim-archaeology` (a *different* ancestor issue); it is this issue's own work already having shipped without a transition.
430
430
 
431
431
  ```bash
@@ -306,7 +306,7 @@ This gate never blocks a legitimate flat Task/Bug: those have no open children a
306
306
 
307
307
  **The two `claim-time-guards` run third and fourth — still before the transition below.** Both semantics live in that one vendor-neutral slug; do not restate them here. JIRA wiring only:
308
308
 
309
- 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the ticket from the read bundle's comments (match on the marker, never the summary). With two or more, do **not** claim: transition to the configured blocked status (`lisa-atlassian-access operation: transition to: "$BLOCKED"`, resolved from `jira.workflow.blocked` per `config-resolution`), post the operator-readable comment naming both attempts, and **stop the cycle** at Phase 3e. Every non-success terminal outcome recorded in 3c/3d also appends a fresh `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> -->` marker so the next cycle can count it.
309
+ 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the ticket from the read bundle's comments (match on the marker, never the summary), applying both filters from `claim-time-guards`: count a marker only when it carries `measures=work` (a marker with no `measures=` counts as `work`), and only when its timestamp is **after the ticket most recently transitioned into the ready status**. Read that transition with `lisa-atlassian-access operation: changelog key:<K>` — `read-ticket` uses `fields=*all`, which does **not** include the changelog, so this is an explicit extra read. If the changelog cannot be read, count every `measures=work` marker regardless of age and say so in the comment. With two or more surviving markers, do **not** claim: transition to the configured blocked status (`lisa-atlassian-access operation: transition to: "$BLOCKED"`, resolved from `jira.workflow.blocked` per `config-resolution`), post the operator-readable comment naming both attempts, and **stop the cycle** at Phase 3e. Every non-success terminal outcome recorded in 3c/3d also appends a fresh `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> measures=<work|machine> -->` marker so the next cycle can count it — `measures=machine` when the run was terminated by a signal or its outcome was `recovery-required`, `measures=work` when the build ran and did not satisfy the ticket.
310
310
  2. **`already-implemented` check.** Probe for this ticket's own key — `git log --all --grep "<TICKET>"` and the merged/open PRs referencing `<TICKET>` (`gh pr list --state all --search "<TICKET>"` in the bound repo). On a hit, claim as normal but route 3c to **verify-and-close** instead of `lisa-implement`: verify what shipped against the ticket's acceptance criteria, post evidence via `lisa-jira-evidence` naming the shipping PR/commit, then run the ordinary 3d transition and rollup. A partial hit implements only the remaining gap. An unreadable history degrades to "no hit" and the ordinary path proceeds — the guard never blocks the claim. This is not `DUPLICATE_ALREADY_FIXED` (a *different* canonical ticket) and not `claim-archaeology` (a *different* ancestor ticket); it is this ticket's own work already having shipped without a transition.
311
311
 
312
312
  Transition the ticket from `$READY` to `$CLAIMED` by invoking `lisa-atlassian-access` `operation: transition key: <TICKET> to: "$CLAIMED"`.
@@ -302,7 +302,7 @@ This gate never blocks a legitimate flat Task/Bug: those have no open children a
302
302
 
303
303
  **The two `claim-time-guards` run third and fourth — still before the transition below.** Both semantics live in that one vendor-neutral slug; do not restate them here. Linear wiring only:
304
304
 
305
- 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the Issue from the read bundle's comments (match on the marker, never the title). With two or more, do **not** claim: invoke `lisa-linear-access operation: save-issue lifecycle_role: blocked` (the access layer resolves `linear.workflow.blocked` itself per `config-resolution`; this skill supplies the role, never a state ID), post the operator-readable comment naming both attempts via `save-comment`, and **stop the cycle** at Phase 3e. Every non-success terminal outcome recorded in 3c/3d also appends a fresh `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> -->` marker so the next cycle can count it.
305
+ 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the Issue from the read bundle's comments (match on the marker, never the title), applying both filters from `claim-time-guards`: count a marker only when it carries `measures=work` (a marker with no `measures=` counts as `work`), and only when its timestamp is **after the Issue most recently entered the ready state**. Read that transition with `lisa-linear-access operation: history id:<ID>`. If the history cannot be read, count every `measures=work` marker regardless of age and say so in the comment. With two or more surviving markers, do **not** claim: invoke `lisa-linear-access operation: save-issue lifecycle_role: blocked` (the access layer resolves `linear.workflow.blocked` itself per `config-resolution`; this skill supplies the role, never a state ID), post the operator-readable comment naming both attempts via `save-comment`, and **stop the cycle** at Phase 3e. Every non-success terminal outcome recorded in 3c/3d also appends a fresh `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> measures=<work|machine> -->` marker so the next cycle can count it — `measures=machine` when the run was terminated by a signal or its outcome was `recovery-required`, `measures=work` when the build ran and did not satisfy the Issue.
306
306
  2. **`already-implemented` check.** Probe for this Issue's own key — `git log --all --grep "<IDENTIFIER>"` and the merged/open PRs referencing `<IDENTIFIER>` (`gh pr list --state all --search "<IDENTIFIER>"` in the bound repo; Linear's own GitHub attachments in the read bundle are the cheaper first look). On a hit, claim as normal but route 3c to **verify-and-close** instead of `lisa-implement`: verify what shipped against the Issue's acceptance criteria, post evidence via `lisa-linear-evidence` naming the shipping PR/commit, then run the ordinary 3d transition and rollup. A partial hit implements only the remaining gap. An unreadable history degrades to "no hit" and the ordinary path proceeds — the guard never blocks the claim. This is not `DUPLICATE_ALREADY_FIXED` (a *different* canonical Issue) and not `claim-archaeology` (a *different* ancestor Issue); it is this Issue's own work already having shipped without a transition.
307
307
 
308
308
  Transition the Issue via `lisa-linear-access operation: save-issue lifecycle_role: claimed`. The access layer resolves the `claimed` role's exact configured state against the team catalog and dispatches that ID; a missing or ambiguous `$CLAIMED` state is a setup defect it refuses on (see the pre-flight check) — never create one here.
@@ -107,5 +107,5 @@ If the canonical fix is merged but not yet on the production branch, the close c
107
107
  - **Leaf-only dispatch, every vendor.** Per the `leaf-only-lifecycle` rule, each vendor scanner dispatches leaf work units only and moves or safe-blocks a container (open child work, or a childless Epic) carrying a stale build-ready role according to its lifecycle semantics. This shim does not re-implement the gate — it relies on the vendor scanner's Phase 3a — but the contract is uniform across `jira`, `github`, and `linear` so behavior never drifts by tracker.
108
108
  - **Terminal native closure, every capable vendor.** Per the same rule, each vendor scanner finalizes native open/closed state only at the true terminal `done` value. This shim never performs native closure itself, but callers can rely on the dispatched vendor scanner to apply the contract.
109
109
  - **Duplicate already fixed, every vendor.** Auto-close without a PR is allowed only for `DUPLICATE_ALREADY_FIXED` with canonical reference and empirical base-branch evidence. Do not conflate this with `BLOCKED`.
110
- - **Claim-time guards, every vendor.** Per the `claim-time-guards` rule, each vendor scanner runs both guards inside its Phase 3b before the claim transition: an item whose own key already appears in git history or an open/merged PR routes to **verify-and-close** rather than being built twice, and the **`two-failed-attempts`** valve moves an item with two `[lisa-build-attempt]` markers to the configured blocked role and stops the cycle. This shim does not re-implement either guard; it forwards the contract so behavior never drifts by tracker.
110
+ - **Claim-time guards, every vendor.** Per the `claim-time-guards` rule, each vendor scanner runs both guards inside its Phase 3b before the claim transition: an item whose own key already appears in git history or an open/merged PR routes to **verify-and-close** rather than being built twice, and the **`two-failed-attempts`** valve moves an item with two counting `[lisa-build-attempt]` markers to the configured blocked role and stops the cycle. A marker counts only when it is `measures=work` and was recorded after the item most recently entered the ready lane — every vendor applies both filters, reading lane history from the substrate that already exposes it (GitHub label events, JIRA `changelog`, Linear `history`). This shim does not re-implement either guard; it forwards the contract so behavior never drifts by tracker.
111
111
  - Never run two intake cycles concurrently against overlapping queues — the scheduling layer is responsible for serialization.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
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.38.6",
3
+ "version": "4.38.8",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.38.6",
3
+ "version": "4.38.8",
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"