@codyswann/lisa 2.129.6 → 2.129.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 (67) hide show
  1. package/harper-fabric/copy-overwrite/knip.json +3 -0
  2. package/package.json +1 -1
  3. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  4. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  5. package/plugins/lisa/skills/github-build-intake/SKILL.md +14 -6
  6. package/plugins/lisa/skills/jira-build-intake/SKILL.md +16 -8
  7. package/plugins/lisa/skills/linear-build-intake/SKILL.md +16 -8
  8. package/plugins/lisa/skills/repair-intake/SKILL.md +147 -31
  9. package/plugins/lisa-agy/plugin.json +1 -1
  10. package/plugins/lisa-agy/skills/github-build-intake/SKILL.md +14 -6
  11. package/plugins/lisa-agy/skills/jira-build-intake/SKILL.md +16 -8
  12. package/plugins/lisa-agy/skills/linear-build-intake/SKILL.md +16 -8
  13. package/plugins/lisa-agy/skills/repair-intake/SKILL.md +147 -31
  14. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  16. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  17. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-copilot/skills/github-build-intake/SKILL.md +14 -6
  21. package/plugins/lisa-copilot/skills/jira-build-intake/SKILL.md +16 -8
  22. package/plugins/lisa-copilot/skills/linear-build-intake/SKILL.md +16 -8
  23. package/plugins/lisa-copilot/skills/repair-intake/SKILL.md +147 -31
  24. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-cursor/skills/github-build-intake/SKILL.md +14 -6
  26. package/plugins/lisa-cursor/skills/jira-build-intake/SKILL.md +16 -8
  27. package/plugins/lisa-cursor/skills/linear-build-intake/SKILL.md +16 -8
  28. package/plugins/lisa-cursor/skills/repair-intake/SKILL.md +147 -31
  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-rails/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  51. package/plugins/lisa-rails-agy/plugin.json +1 -1
  52. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  56. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  57. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  61. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  62. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  64. package/plugins/src/base/skills/github-build-intake/SKILL.md +14 -6
  65. package/plugins/src/base/skills/jira-build-intake/SKILL.md +16 -8
  66. package/plugins/src/base/skills/linear-build-intake/SKILL.md +16 -8
  67. package/plugins/src/base/skills/repair-intake/SKILL.md +147 -31
@@ -17,6 +17,9 @@
17
17
  "harper-app/resource-*.js",
18
18
  "harper-app/web/**/*.js"
19
19
  ],
20
+ "ignoreIssues": {
21
+ "src/types/harper-schema.ts": ["types"]
22
+ },
20
23
  "ignoreDependencies": ["@types/node", "@vitest/coverage-v8"],
21
24
  "ignoreBinaries": ["audit", "harperdb", "knip", "playwright", "tsx"],
22
25
  "rules": {
package/package.json CHANGED
@@ -83,7 +83,7 @@
83
83
  "lodash": ">=4.18.1"
84
84
  },
85
85
  "name": "@codyswann/lisa",
86
- "version": "2.129.6",
86
+ "version": "2.129.8",
87
87
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
88
88
  "main": "dist/index.js",
89
89
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.129.6",
3
+ "version": "2.129.8",
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": "2.129.6",
3
+ "version": "2.129.8",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -264,24 +264,30 @@ Invoke `lisa:github-agent` (the per-issue lifecycle agent) with the issue ref. `
264
264
 
265
265
  Wait for `lisa:github-agent` to return. Capture its outcome:
266
266
 
267
- - **Success** — PR is ready (open or merged); evidence posted; ready for next status.
267
+ - **Success** — the build flow completed and a PR exists; evidence posted. The PR may already be **merged** or still **open** (auto-merge enabled, awaiting checks/merge). "Success" means the build work is sound — it does **not** assert the change reached an environment. The env transition in 3d gates on the PR actually being merged; an open PR does not advance the issue to a `done` env status.
268
268
  - **Blocked by github-verify pre-flight gate** — `lisa:github-agent` itself relabels the issue to `status:blocked` (or removes `$CLAIMED` and reassigns to the original author). This is correct and expected — let it stand. Record and move on.
269
269
  - **Blocked by ticket-triage ambiguities** — `lisa:github-agent` posts findings and stops. The issue stays in `$CLAIMED`. Surface to human; do not auto-relabel. Record under "Errors".
270
270
  - **Errored** — exception, missing config, etc. Leave the issue in `$CLAIMED` for human investigation. Record under "Errors".
271
271
 
272
- #### 3d. Transition to $DONE (only on Success)
272
+ #### 3d. Transition to $DONE (only after the PR is merged)
273
+
274
+ A `done` env state (`status:on-dev`, `status:on-stg`, or the terminal value) asserts that the code has actually reached that environment. Never set it for a PR that is merely open: auto-merge can be blocked indefinitely (a required rebase / `BEHIND` branch, failing checks, an unaddressed review), and the change may never land. Relabeling an issue `status:on-stg` on an open PR makes it *claim* a deploy that never happened. Transition only after confirming the PR merged.
273
275
 
274
276
  If `lisa:github-agent` returned Success:
275
277
 
276
- 1. Resolve `$DONE` for this issue's PR base branch using the Workflow resolution algorithm above. If env can't be resolved and `done` is env-keyed, record an Error and skip this transition — never guess.
277
- 2. Determine whether `$DONE` is the true terminal done value per the `leaf-only-lifecycle` rule's Terminal native closure section:
278
+ 1. **Confirm the PR merged.** Read the live state of the issue's PR `gh pr view <pr> --json state,mergedAt,mergeStateStatus,url`:
279
+ - **Merged** (`state == MERGED`) → proceed to resolve and apply `$DONE` below. Where the env deploy is observable (a deploy workflow run / deployment status keyed to the merged-into branch via `deploy.branches`), confirm it did not fail before relabeling; a still-running deploy is treated like an open PR (leave in `$CLAIMED`), a failed deploy is recorded as an Error.
280
+ - **Open / not yet merged** → do **not** transition. The build is sound but the change has reached no environment yet. Record the issue under **"PR open — awaiting merge"** in the summary (with the PR URL and its `mergeStateStatus`), leave it in `$CLAIMED`, and stop. A later `lisa:repair-intake` cycle drives the open PR to merge — re-syncing a `BEHIND` branch so the already-enabled auto-merge can land, or surfacing a real blocker — and, once merged, applies this same env transition. Do **not** comment "Build complete" or close anything.
281
+ - **Closed without merging** → record an Error (the PR was abandoned unmerged); leave the issue in `$CLAIMED`.
282
+ 2. Resolve `$DONE` for this issue's PR base branch using the Workflow resolution algorithm above. If env can't be resolved and `done` is env-keyed, record an Error and skip this transition — never guess.
283
+ 3. Determine whether `$DONE` is the true terminal done value per the `leaf-only-lifecycle` rule's Terminal native closure section:
278
284
  - If `github.labels.build.done` is a string, that string is terminal.
279
285
  - If `github.labels.build.done` is an object, only the production/final environment value is terminal (default: `status:done`). Intermediate env values such as `status:on-dev` and `status:on-stg` are not terminal and must stay open.
280
286
  - If the project uses a different final environment name, resolve it from the configured deployment topology; if ambiguous, record an Error and do not close.
281
287
 
282
288
  ```bash
283
289
  gh issue edit <number> --repo <org>/<repo> --remove-label "$CLAIMED" --add-label "$DONE"
284
- gh issue comment <number> --repo <org>/<repo> --body "[claude-build-intake] Build complete. PR <URL>. Transitioned to $DONE."
290
+ gh issue comment <number> --repo <org>/<repo> --body "[claude-build-intake] Build complete. PR <URL> merged. Transitioned to $DONE."
285
291
  ```
286
292
 
287
293
  If `$DONE` is terminal, immediately close the native GitHub issue:
@@ -308,8 +314,10 @@ Cycle started: <ISO timestamp>
308
314
  Cycle completed: <ISO timestamp>
309
315
 
310
316
  Issues processed: <n>
311
- - $DONE (build complete, PR ready): <n>
317
+ - $DONE (build complete, PR merged): <n>
312
318
  - <org>/<repo>#<number> <title> → PR <URL>
319
+ - PR open — awaiting merge (left in $CLAIMED for repair-intake): <n>
320
+ - <org>/<repo>#<number> <title> → PR <URL> (mergeStateStatus: <state>)
313
321
  - Repaired (container — leaf-only-lifecycle): <n>
314
322
  - <org>/<repo>#<number> <title> — build-ready on a parent/container; moved $READY → $CLAIMED without invoking lisa:github-agent; lifecycle-repair comment posted
315
323
  - Skipped (active blockers): <n>
@@ -193,22 +193,28 @@ Invoke the `lisa:jira-agent` (existing per-ticket lifecycle agent) with the tick
193
193
  - Posting evidence via `lisa:jira-evidence`
194
194
 
195
195
  Wait for `lisa:jira-agent` to return. Capture its outcome:
196
- - **Success** — PR is ready (open or merged); evidence posted; ready for next status.
196
+ - **Success** — the build flow completed and a PR exists; evidence posted. The PR may already be **merged** or still **open** (auto-merge enabled, awaiting checks/merge). "Success" means the build work is sound — it does **not** assert the change reached an environment. The env transition in 3d gates on the PR actually being merged; an open PR does not advance the ticket to a `done` env status.
197
197
  - **Blocked by jira-verify pre-flight gate** — `lisa:jira-agent` itself transitions the ticket to `Blocked` and reassigns to Reporter. This is correct and expected — let it stand. Record the outcome and move on.
198
198
  - **Blocked by ticket-triage ambiguities** — `lisa:jira-agent` posts findings and stops. The ticket stays in `$CLAIMED`. Surface to human; do not auto-transition. Record under "Errors" with reason `"Triage found ambiguities — see comments on <ticket-key>"`.
199
199
  - **Errored** — exception, missing config, etc. Leave the ticket in `$CLAIMED` for human investigation. Record under "Errors" with the exception summary.
200
200
 
201
- #### 3d. Transition to $DONE (only on Success)
201
+ #### 3d. Transition to $DONE (only after the PR is merged)
202
+
203
+ A `done` env status (`On Dev`, `On Stg`, or the terminal value) asserts that the code has actually reached that environment. Never set it for a PR that is merely open: auto-merge can be blocked indefinitely (a required rebase / `BEHIND` branch, failing checks, an unaddressed review), and the change may never land. Setting `On Stg` on an open PR makes a ticket *claim* a deploy that never happened. Transition only after confirming the PR merged.
202
204
 
203
205
  If `lisa:jira-agent` returned Success:
204
- 1. Resolve `$DONE` for this ticket's PR base branch using the Workflow resolution algorithm above. If env can't be resolved and `done` is env-keyed, record an Error and skip this transition — never guess.
205
- 2. Determine whether `$DONE` is the true terminal done value per the `leaf-only-lifecycle` rule's Terminal native closure section:
206
+ 1. **Confirm the PR merged.** Read the live state of the ticket's PR `gh pr view <pr> --json state,mergedAt,mergeStateStatus,url`:
207
+ - **Merged** (`state == MERGED`) → proceed to resolve and apply `$DONE` below. Where the env deploy is observable (a deploy workflow run / deployment status keyed to the merged-into branch via `deploy.branches`), confirm it did not fail before transitioning; a still-running deploy is treated like an open PR (leave in `$CLAIMED` for a later cycle), a failed deploy is recorded as an Error.
208
+ - **Open / not yet merged** → do **not** transition. The build is sound but the change has reached no environment yet. Record the ticket under **"PR open — awaiting merge"** in the summary (with the PR URL and its `mergeStateStatus`), leave it in `$CLAIMED`, and stop. A later `lisa:repair-intake` cycle drives the open PR to merge — re-syncing a `BEHIND` branch so the already-enabled auto-merge can land, or surfacing a real blocker — and, once it is merged, applies this same env transition. Do **not** comment "Build complete" or file anything: the work is in-flight, not done.
209
+ - **Closed without merging** → record an Error (the PR was abandoned unmerged); leave the ticket in `$CLAIMED` for human investigation.
210
+ 2. Resolve `$DONE` for this ticket's PR base branch using the Workflow resolution algorithm above. If env can't be resolved and `done` is env-keyed, record an Error and skip this transition — never guess.
211
+ 3. Determine whether `$DONE` is the true terminal done value per the `leaf-only-lifecycle` rule's Terminal native closure section:
206
212
  - If `jira.workflow.done` is a string, that status is terminal.
207
213
  - If `jira.workflow.done` is an object, only the production/final environment value is terminal (default: `Done`). Intermediate env statuses such as `On Dev` and `On Stg` are not terminal and must remain unresolved / open.
208
214
  - If the project uses a different final environment name, resolve it from the configured deployment topology; if ambiguous, record an Error and do not finalize native resolution.
209
- 3. Invoke `lisa:atlassian-access` `operation: transition key: <TICKET> to: "$DONE"`.
210
- 4. If `$DONE` is terminal, verify the resulting JIRA issue is natively closed/resolved: status category is `Done`, and resolution is set when the project's workflow requires one. If the transition screen requires an explicit resolution, use the configured default resolution if present; otherwise record an Error naming the missing workflow setup rather than silently landing in an unresolved Done-named status.
211
- 5. Post a `[claude-build-intake]` comment via `lisa:atlassian-access` `operation: comment key: <TICKET> body: "Build complete. PR <URL>. Transitioned to $DONE."` Include whether terminal native resolution was verified, already satisfied, skipped for an intermediate env, or blocked by workflow setup.
215
+ 4. Invoke `lisa:atlassian-access` `operation: transition key: <TICKET> to: "$DONE"`.
216
+ 5. If `$DONE` is terminal, verify the resulting JIRA issue is natively closed/resolved: status category is `Done`, and resolution is set when the project's workflow requires one. If the transition screen requires an explicit resolution, use the configured default resolution if present; otherwise record an Error naming the missing workflow setup rather than silently landing in an unresolved Done-named status.
217
+ 6. Post a `[claude-build-intake]` comment via `lisa:atlassian-access` `operation: comment key: <TICKET> body: "Build complete. PR <URL> merged. Transitioned to $DONE."` Include whether terminal native resolution was verified, already satisfied, skipped for an intermediate env, or blocked by workflow setup.
212
218
 
213
219
  For any non-Success outcome, do NOT transition. The ticket sits in `$CLAIMED` (or wherever `lisa:jira-agent` left it for the Blocked case) — the cycle's job is done; humans take it from there.
214
220
 
@@ -226,8 +232,10 @@ Cycle started: <ISO timestamp>
226
232
  Cycle completed: <ISO timestamp>
227
233
 
228
234
  Tickets processed: <n>
229
- - $DONE (build complete, PR ready): <n>
235
+ - $DONE (build complete, PR merged): <n>
230
236
  - <ticket-key> <summary> → PR <URL>
237
+ - PR open — awaiting merge (left in $CLAIMED for repair-intake): <n>
238
+ - <ticket-key> <summary> → PR <URL> (mergeStateStatus: <state>)
231
239
  - Skipped (container — leaf-only-lifecycle): <n>
232
240
  - <ticket-key> <summary> — build-ready on a parent with open child work; lifecycle-repair comment posted
233
241
  - Blocked (pre-flight verify failed): <n>
@@ -203,22 +203,28 @@ Invoke `lisa:linear-agent` (per-Issue lifecycle agent) with the Issue identifier
203
203
  - Posting evidence via `lisa:linear-evidence`
204
204
 
205
205
  Wait for the agent to return. Capture its outcome:
206
- - **Success** — PR is ready (open or merged); evidence posted; ready for next status.
206
+ - **Success** — the build flow completed and a PR exists; evidence posted. The PR may already be **merged** or still **open** (auto-merge enabled, awaiting checks/merge). "Success" means the build work is sound — it does **not** assert the change reached an environment. The env transition in 3d gates on the PR actually being merged; an open PR does not advance the Issue to a `done` env status.
207
207
  - **Blocked by linear-verify pre-flight gate** — `lisa:linear-agent` itself relabels to `status:blocked` and assigns to creator. Let it stand. Record and move on.
208
208
  - **Blocked by ticket-triage ambiguities** — agent posts findings and stops. The Issue stays at `$CLAIMED`. Surface to human; do not auto-transition. Record under "Errors".
209
209
  - **Errored** — exception, missing config, etc. Leave at `$CLAIMED`. Record with exception summary.
210
210
 
211
- #### 3d. Relabel to $DONE (only on Success)
211
+ #### 3d. Relabel to $DONE (only after the PR is merged)
212
+
213
+ A `done` env state (`status:on-dev`, `status:on-stg`, or the terminal value) asserts that the code has actually reached that environment. Never set it for a PR that is merely open: auto-merge can be blocked indefinitely (a required rebase / `BEHIND` branch, failing checks, an unaddressed review), and the change may never land. Relabeling an Issue `status:on-stg` on an open PR makes it *claim* a deploy that never happened. Transition only after confirming the PR merged.
212
214
 
213
215
  If `lisa:linear-agent` returned Success:
214
- 1. Resolve `$DONE` for this issue's PR base branch using the Workflow resolution algorithm above. If env can't be resolved and `done` is env-keyed, record an Error and skip this transition — never guess.
215
- 2. Determine whether `$DONE` is the true terminal done value per the `leaf-only-lifecycle` rule's Terminal native closure section:
216
+ 1. **Confirm the PR merged.** Read the live state of the Issue's PR `gh pr view <pr> --json state,mergedAt,mergeStateStatus,url`:
217
+ - **Merged** (`state == MERGED`) → proceed to resolve and apply `$DONE` below. Where the env deploy is observable (a deploy workflow run / deployment status keyed to the merged-into branch via `deploy.branches`), confirm it did not fail before relabeling; a still-running deploy is treated like an open PR (leave at `$CLAIMED`), a failed deploy is recorded as an Error.
218
+ - **Open / not yet merged** → do **not** transition. The build is sound but the change has reached no environment yet. Record the Issue under **"PR open — awaiting merge"** in the summary (with the PR URL and its `mergeStateStatus`), leave it at `$CLAIMED`, and stop. A later `lisa:repair-intake` cycle drives the open PR to merge — re-syncing a `BEHIND` branch so the already-enabled auto-merge can land, or surfacing a real blocker — and, once merged, applies this same env transition. Do **not** comment "Build complete" or change the native state.
219
+ - **Closed without merging** → record an Error (the PR was abandoned unmerged); leave the Issue at `$CLAIMED`.
220
+ 2. Resolve `$DONE` for this issue's PR base branch using the Workflow resolution algorithm above. If env can't be resolved and `done` is env-keyed, record an Error and skip this transition — never guess.
221
+ 3. Determine whether `$DONE` is the true terminal done value per the `leaf-only-lifecycle` rule's Terminal native closure section:
216
222
  - If `linear.labels.build.done` is a string, that string is terminal.
217
223
  - If `linear.labels.build.done` is an object, only the production/final environment value is terminal (default: `status:done`). Intermediate env values such as `status:on-dev` and `status:on-stg` are not terminal and must keep the native Issue open.
218
224
  - If the project uses a different final environment name, resolve it from the configured deployment topology; if ambiguous, record an Error and do not change the native state.
219
- 3. Update labels via `mcp__linear-server__save_issue`: remove `$CLAIMED` (or `$REVIEW` if `lisa:linear-evidence` already moved it forward), add `$DONE`.
220
- 4. If `$DONE` is terminal, move the native Linear Issue state to the configured Done / Completed state. Resolve that state from project configuration if present; otherwise inspect the team workflow for a terminal state with `state.type = "completed"` and a name such as `Done` or `Completed`. If no terminal state can be resolved, record an Error and leave the labels as the source of truth — do not invent a state name.
221
- 5. Post a `[claude-build-intake]` comment: `"Build complete. PR <URL>. Transitioned to $DONE."` Include whether native closure was applied, already satisfied, skipped for an intermediate env, or unavailable for setup reasons.
225
+ 4. Update labels via `mcp__linear-server__save_issue`: remove `$CLAIMED` (or `$REVIEW` if `lisa:linear-evidence` already moved it forward), add `$DONE`.
226
+ 5. If `$DONE` is terminal, move the native Linear Issue state to the configured Done / Completed state. Resolve that state from project configuration if present; otherwise inspect the team workflow for a terminal state with `state.type = "completed"` and a name such as `Done` or `Completed`. If no terminal state can be resolved, record an Error and leave the labels as the source of truth — do not invent a state name.
227
+ 6. Post a `[claude-build-intake]` comment: `"Build complete. PR <URL> merged. Transitioned to $DONE."` Include whether native closure was applied, already satisfied, skipped for an intermediate env, or unavailable for setup reasons.
222
228
 
223
229
  For any non-Success outcome, do NOT transition. The Issue sits where the agent left it — humans take it from there.
224
230
 
@@ -236,8 +242,10 @@ Cycle started: <ISO timestamp>
236
242
  Cycle completed: <ISO timestamp>
237
243
 
238
244
  Issues processed: <n>
239
- - $DONE (build complete, PR ready): <n>
245
+ - $DONE (build complete, PR merged): <n>
240
246
  - <ID> <title> → PR <URL>
247
+ - PR open — awaiting merge (left at $CLAIMED for repair-intake): <n>
248
+ - <ID> <title> → PR <URL> (mergeStateStatus: <state>)
241
249
  - Skipped (container — leaf-only-lifecycle): <n>
242
250
  - <ID> <title> — build-ready on a parent with open child work; lifecycle-repair comment posted
243
251
  - status:blocked (pre-flight verify failed): <n>
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: repair-intake
3
- description: "Vendor-agnostic repair scanner — the recovery counterpart to lisa:intake. Where intake claims `ready` work, repair-intake finds work that got stuck or was left half-closed: items left in `blocked`, stalled in an in-progress role (build `claimed`, PRD `in_review`), terminal-labeled items that are still natively open, and rollup/container items whose children are all terminal but whose parent is not closed out. Scans the same queues lisa:intake serves (Notion / Confluence / Linear / GitHub PRD databases; JIRA / GitHub / Linear build queues), enumerates candidates up to `max_candidates`, and repairs every materially actionable one in that bounded set: resumes stalled in-progress work IN PLACE (build → the vendor agent + the scanner's post-agent transition; PRD → the source `*-to-tracker` dry-run validate→route pipeline) — but for a stalled build it first diagnoses the PR/deploy state and, if the PR cannot merge (conflict, rebase-required, failing checks, unaddressed CodeRabbit/changes-requested) or a deploy failed, files a build-ready leaf fix ticket and moves the item to `blocked` (blocked by that ticket) rather than re-dispatching, re-validates blocked PRDs when new clarifying answers exist, re-dispatches blocked build items whose `is blocked by` dependencies have since closed, performs terminal native closure for terminal-labeled items, reconciles parent rollups to their derived state per leaf-only-lifecycle — including the intermediate-env case (e.g. all children at `On Stg` → parent `On Stg`) and a container wrongly stuck in `ready` — and closes out rollups whose associated child work is fully terminal. Idempotent, loop-protected via a [lisa-repair-intake] marker + state fingerprint + backoff. Never mutates product-owned states (`draft`, `verified`) and never touches `ready` leaves (a container wrongly carrying `ready` is the one exception — it is rolled up from its children, since `ready` on a parent is an invariant violation, not intake's claim signal). Designed as a /schedule cron target running alongside lisa:intake."
3
+ description: "Vendor-agnostic repair scanner — the recovery counterpart to lisa:intake. Where intake claims `ready` work, repair-intake finds work that got stuck or was left half-closed: items left in `blocked`, stalled in an in-progress role (build `claimed`, PRD `in_review`), terminal-labeled items that are still natively open, and rollup/container items whose children are all terminal but whose parent is not closed out. Scans the same queues lisa:intake serves (Notion / Confluence / Linear / GitHub PRD databases; JIRA / GitHub / Linear build queues), enumerates candidates up to `max_candidates`, and repairs every materially actionable one in that bounded set: resumes stalled in-progress work IN PLACE (build → the vendor agent + the scanner's post-agent transition; PRD → the source `*-to-tracker` dry-run validate→route pipeline) — but for a stalled build it first diagnoses the PR/deploy state: a PR that already merged is recovered by applying the env transition build-intake never got to (no re-dispatch); a PR that is merely behind its base is re-synced in place via `gh pr update-branch` so the already-enabled auto-merge can land (a clean rebase needs no human); and only a PR that cannot merge for a non-mechanical reason (true conflict, failing checks, unaddressed CodeRabbit/changes-requested) or a failed deploy gets a build-ready leaf fix ticket with the item moved to `blocked` (blocked by that ticket) rather than re-dispatching, re-validates blocked PRDs when new clarifying answers exist, re-dispatches blocked build items whose `is blocked by` dependencies have since closed OR whose validation/quality-gate self-block now re-validates PASS (re-running `lisa:tracker-validate` against current content — the build mirror of PRD re-validation), performs terminal native closure for terminal-labeled items, reconciles parent rollups to their derived state per leaf-only-lifecycle — including the intermediate-env case (e.g. all children at `On Stg` → parent `On Stg`) and a container wrongly stuck in `ready` — and closes out rollups whose associated child work is fully terminal. Idempotent, loop-protected via a [lisa-repair-intake] marker + state fingerprint + backoff. Never mutates product-owned states (`draft`, `verified`) and never touches `ready` leaves (a container wrongly carrying `ready` is the one exception — it is rolled up from its children, since `ready` on a parent is an invariant violation, not intake's claim signal). Designed as a /schedule cron target running alongside lisa:intake."
4
4
  allowed-tools: ["Skill", "Bash", "Read", "Write", "Edit", "mcp__linear-server__list_teams", "mcp__linear-server__list_projects", "mcp__linear-server__get_project", "mcp__linear-server__save_project", "mcp__linear-server__list_project_labels", "mcp__linear-server__list_issues", "mcp__linear-server__get_issue", "mcp__linear-server__save_issue", "mcp__linear-server__list_comments", "mcp__linear-server__save_comment", "mcp__linear-server__list_issue_labels", "mcp__linear-server__create_issue_label"]
5
5
  ---
6
6
 
@@ -15,13 +15,24 @@ close-out** roles and moves work *unstuck* or *fully closed*:
15
15
  happening, so it sits ignored forever. (The vendor PRD intakes explicitly leave an errored PRD
16
16
  in `in_review` "for the human to investigate from there" — that orphan is exactly what this
17
17
  skill recovers.) For a stalled **build**, repair-intake first diagnoses *why* it stalled by
18
- inspecting its PRs and deploys: if the PR cannot merge (conflict / rebase-required / failing
19
- checks / unaddressed CodeRabbit or `CHANGES_REQUESTED` review) or a deploy failed, it files a
20
- build-ready leaf fix ticket and moves the item to `blocked` (blocked by that ticket) instead of
21
- blindly re-dispatching the agent which would just churn against an unmergeable PR.
22
- - **Recoverable blocked** an item in `blocked` whose blocker may now be gone: an
23
- `is blocked by` dependency has since closed, clarifying questions have been answered, or
24
- research/waiting resolves the ambiguity that stopped it.
18
+ inspecting its PRs and deploys. A PR that **already merged** is recovered by applying the env
19
+ transition build-intake never got to (its merge gate left the item `claimed` when the merge landed
20
+ after its agent returned) no re-dispatch. A PR that is merely **behind its base** (`BEHIND`, no
21
+ conflict) is **re-synced in place** with `gh pr update-branch` so the already-enabled auto-merge can
22
+ finally landa clean rebase needs no human, and leaving it stranded is the exact gap that lets an
23
+ auto-merge PR sit unmerged forever. Only a PR that cannot merge for a non-mechanical reason (true
24
+ conflict / failing checks / unaddressed CodeRabbit or `CHANGES_REQUESTED` review) or a failed deploy
25
+ gets a build-ready leaf fix ticket with the item moved to `blocked` (blocked by that ticket) instead
26
+ of blindly re-dispatching the agent — which would just churn against an unmergeable PR.
27
+ - **Recoverable blocked** — an item in `blocked` whose blocker may now be gone. The blocker is
28
+ one of three classes, and repair re-checks **all** of them, not just dependencies: (a) an
29
+ `is blocked by` **dependency** has since closed; (b) a **validation / quality-gate self-block** —
30
+ the item was bounced to `blocked` by its own pre-flight `verify`/`validate` gate (missing
31
+ Validation Journey, Sign-in Required, Acceptance Criteria, etc.) with **no dependency at all**,
32
+ and a human has since edited the item to add what the gate demanded; or (c) **clarifying
33
+ questions answered** / an **ambiguity** research can now settle. A self-block (b) is the common
34
+ one missed by dependency-only re-checks: nothing else is blocking it, so re-running the same gate
35
+ against its current content is the only way to know it is now passable.
25
36
  - **Terminal-open drift** — an item already carrying its true terminal lifecycle role (for
26
37
  example GitHub `status:done`) but still open/active in the provider's native state.
27
38
  - **Rollup drift** — a parent/container item (Epic, Story, PRD, Linear Project, or equivalent)
@@ -251,14 +262,24 @@ deploys (see "Stuck-cause diagnosis" below). A stalled build usually stalled for
251
262
  reason, and re-dispatching the agent at it will not fix a PR that cannot merge or a deploy that
252
263
  failed — it just churns.
253
264
 
254
- 0. **Diagnose PR & deploy blockers.** If a real external blocker is found (PR cannot merge — merge
255
- conflict / rebase-required / failing checks / `CHANGES_REQUESTED` / unaddressed CodeRabbit; or a
256
- failed deploy), **do not dispatch the agent**. Instead file a build-ready leaf fix ticket for the
257
- blocker, move this item `claimed blocked` with an `is blocked by` link to that ticket, and
258
- record it. The existing "Build `blocked` unblock if cleared" path resumes this item on a later
259
- cycle once the fix ticket is terminal — a self-healing loop. Skip the resume steps below.
260
-
261
- If no external blocker is found, the work simply died mid-flight run the **same per-item sequence
265
+ 0. **Diagnose PR & deploy state.** Run "Stuck-cause diagnosis" below. It resolves, in order:
266
+ - **PR already merged** the build effectively completed; the vendor build-intake's merge gate
267
+ left the item `claimed` because the merge landed after its agent returned. Do **not** re-dispatch
268
+ or file anything apply the scanner's post-agent env-resolved `claimed done` transition
269
+ directly (step 2 below, env-resolved), and record it. This is the recovery arm for build-intake
270
+ leaving merged-but-unadvanced items in `claimed`.
271
+ - **PR only behind its base (a needed rebase)** → mechanically resolvable, **not** a human blocker.
272
+ Re-sync the branch in place so the already-enabled auto-merge can land (see diagnosis step 3).
273
+ Keep the item `claimed`; a later cycle confirms the merge and transitions. Do **not** file a fix
274
+ ticket for a clean rebase.
275
+ - **A real external blocker** (PR cannot merge for a non-mechanical reason — true merge conflict /
276
+ failing checks / `CHANGES_REQUESTED` / unaddressed CodeRabbit; or a failed deploy) → **do not
277
+ dispatch the agent**. File a build-ready leaf fix ticket for the blocker, move this item
278
+ `claimed → blocked` with an `is blocked by` link to that ticket, and record it. The existing
279
+ "Build `blocked` → unblock if cleared" path resumes this item on a later cycle once the fix
280
+ ticket is terminal — a self-healing loop. Skip the resume steps below.
281
+
282
+ If the PR is healthy in-flight and no blocker is found, the work simply died mid-flight — run the **same per-item sequence
262
283
  the vendor build-intake runs**, skipping the claim transition (the item is already `claimed`):
263
284
 
264
285
  1. Dispatch the item to the vendor agent — `lisa:jira-agent` / `lisa:github-agent` /
@@ -287,12 +308,38 @@ external state that resuming the agent cannot fix."
287
308
  links and `gh pr list --search <issue-ref>`; JIRA: dev-status / remote links; Linear: attachments
288
309
  and git-branch links) and the deploy(s) for the resulting merge (the env-keyed `deploy.branches`
289
310
  mapping from `config-resolution`). Read each PR with the vendor's native state, e.g. GitHub
290
- `gh pr view <n> --json mergeable,mergeStateStatus,reviewDecision,statusCheckRollup,comments,reviews`.
311
+ `gh pr view <n> --json state,mergedAt,mergeable,mergeStateStatus,reviewDecision,statusCheckRollup,comments,reviews`.
312
+
313
+ **2. PR already merged → recover, don't re-dispatch.** If `state == MERGED`, the build is effectively
314
+ complete and the only thing missing is the env transition the build-intake never applied (its merge
315
+ gate left the item `claimed` because the merge landed after its agent returned). Do **not** re-dispatch
316
+ or file anything: apply the scanner's post-agent env-resolved `claimed → done` transition (the
317
+ resume-sequence step 2, env-resolved from the merged PR's base branch) and record it as a repair
318
+ write. Where the env deploy is observable, confirm it did not fail first; a failed post-merge deploy
319
+ falls through to the blocker path (step 4).
320
+
321
+ **3. PR only behind its base → re-sync in place (mechanical, not a blocker).** If the PR is clean but
322
+ behind its base — `mergeStateStatus == BEHIND` while `mergeable != CONFLICTING` and no required check
323
+ is failing — it does **not** need a human. This is exactly the case that strands a PR forever: GitHub
324
+ auto-merge will not advance a `BEHIND` branch on its own, so a PR opened with `--auto` sits unmerged
325
+ until something rebases it. Re-sync it in place and let the existing auto-merge land it:
326
+
327
+ ```bash
328
+ gh pr update-branch <n> # rebase/merge the base into the PR head; reruns required checks
329
+ ```
291
330
 
292
- **2. Classify as a blocker.** Treat any of these as a real external blocker:
331
+ Record this as a repair write (`resynced`), keep the item `claimed`, and move on — a later cycle sees
332
+ the now-`CLEAN` (or merged) PR and either lets auto-merge finish or applies the merged-PR recovery in
333
+ step 2. Only if `gh pr update-branch` itself reports a conflict it cannot apply does the PR become a
334
+ true conflict (step 4). Honor the backoff window so repeated cycles don't re-issue `update-branch` on
335
+ an unchanged head (Loop prevention). For JIRA/Linear items the PR is still the GitHub PR backing the
336
+ branch — operate on it the same way.
293
337
 
294
- - **Merge conflict / rebase required** `mergeable = CONFLICTING`, or `mergeStateStatus` in
295
- `DIRTY` / `BEHIND`.
338
+ **4. Classify as a blocker.** Treat any of these as a real external blocker:
339
+
340
+ - **True merge conflict** — `mergeable = CONFLICTING` or `mergeStateStatus = DIRTY` (overlapping
341
+ changes a plain rebase cannot resolve), or `gh pr update-branch` (step 3) reported a conflict. A
342
+ merely `BEHIND` branch is **not** here — it was re-synced in step 3.
296
343
  - **Failing required checks** — `statusCheckRollup` has a `FAILURE`/`ERROR`/`TIMED_OUT` conclusion,
297
344
  or `mergeStateStatus = UNSTABLE`/`BLOCKED` due to checks.
298
345
  - **Change requests outstanding** — `reviewDecision = CHANGES_REQUESTED`, or unresolved CodeRabbit
@@ -306,7 +353,7 @@ A check that is still **queued/in progress**, or a `CLEAN`/`HAS_HOOKS` mergeable
306
353
  outstanding change request, is **not** a blocker — that is normal in-flight state. (Such a PR with
307
354
  recent check/commit activity would already have been caught as `active` by the staleness gate.)
308
355
 
309
- **3. On a blocker found → file a leaf fix ticket + block the item.**
356
+ **5. On a blocker found → file a leaf fix ticket + block the item.**
310
357
 
311
358
  1. **File one build-ready leaf fix ticket** per distinct blocker via `lisa:tracker-write` (the
312
359
  vendor-neutral leaf writer + validation gate; never a vendor `*-write-*` skill directly),
@@ -332,14 +379,31 @@ window and state fingerprint (Loop prevention) so re-runs over the same unchange
332
379
 
333
380
  ### Build `blocked` → re-evaluate, unblock if cleared
334
381
 
335
- 1. Read the block reason and dependencies (see Dependency clearing).
336
- 2. If every parsed blocker is **cleared** move `blocked claimed`, then run the same
337
- agent-dispatch + post-agent `claimed done` sequence as the stalled-`claimed` path above
338
- (one-cycle recovery). If the agent re-blocks, move back to `blocked` a valid outcome.
339
- 3. If the block was an **ambiguity** research can settle and no dependency remains → run the
382
+ 1. Read the block reason and classify the blocker (see Blocker classification & clearing). An item
383
+ may be held by a **dependency**, by a **validation / quality-gate self-block**, by an
384
+ **ambiguity**, or by more than one at once. Re-check **every** class present do not stop at
385
+ "no `is blocked by` links, therefore nothing to do." A self-block has zero dependencies by
386
+ definition, yet is fully re-checkable.
387
+ 2. **Dependency cleared** — if every parsed `is blocked by` dependency is **cleared** → move
388
+ `blocked → claimed`, then run the same agent-dispatch + post-agent `claimed → done` sequence as
389
+ the stalled-`claimed` path above (one-cycle recovery). If the agent re-blocks, move back to
390
+ `blocked` — a valid outcome.
391
+ 3. **Validation / quality-gate self-block re-check** — if the block reason is a pre-flight
392
+ `verify`/`validate` gate failure (its `[lisa-*]` block note carries a gate marker + a "Missing
393
+ requirements" list and there is **no** open `is blocked by` dependency), re-run the **same gate**
394
+ against the item's **current** content via `lisa:tracker-validate` (read-only; the vendor-neutral
395
+ gate `lisa:<tracker>-build-intake` and `lisa:<tracker>-write-*` already use). This is the build
396
+ mirror of the PRD `blocked → re-validate` path below.
397
+ - **PASS now** (the human added what was missing) → move `blocked → claimed` and resume exactly
398
+ as in (2): agent-dispatch + post-agent `claimed → done`.
399
+ - **Still FAIL** → stay `blocked`, but refresh the note with the **current** (usually smaller)
400
+ missing-requirement set so the human sees what remains. Because the fingerprint includes the
401
+ gate verdict + missing-requirement set (Loop prevention), a partial human fix changes the
402
+ fingerprint and re-checks next cycle, while a truly-unchanged gate result stays in backoff.
403
+ 4. If the block was an **ambiguity** research can settle and no dependency remains → run the
340
404
  research needed (`lisa:codebase-research` / `lisa:product-walkthrough`); if resolved, proceed
341
405
  as in (2).
342
- 4. Else → still blocked. Refresh the note with the current reason (Loop prevention) and leave it
406
+ 5. Else → still blocked. Refresh the note with the current reason (Loop prevention) and leave it
343
407
  `blocked`.
344
408
 
345
409
  ### Build terminal-open → native close / complete / resolve
@@ -460,7 +524,13 @@ work is fully terminal:
460
524
  5. If generated work is missing, ambiguous, or partially incomplete, leave the PRD open and report
461
525
  the incomplete child set. Never close a PRD on partial completion.
462
526
 
463
- ## Dependency clearing (conservative, vendor-specific extraction)
527
+ ## Blocker classification & clearing (conservative, vendor-specific extraction)
528
+
529
+ A `blocked` build item is held by one or more of three blocker classes. Identify which are present
530
+ from the item's block note(s) and links, then clear-check **each present class** — an item with no
531
+ dependency is not automatically un-actionable; it may be a self-block that now passes.
532
+
533
+ ### Class A — dependency blockers
464
534
 
465
535
  `lisa:tracker-read` is a thin dispatcher that returns each vendor's bundle **verbatim** — there
466
536
  is no normalized `is blocked by` field. Read the bundle, then extract blockers per vendor:
@@ -485,6 +555,38 @@ Only re-dispatch when **every** parsed blocker is cleared. When in doubt, stay b
485
555
  false-negative (left blocked) is cheap; a false-positive (re-dispatched into a real blocker)
486
556
  wastes a build cycle.
487
557
 
558
+ ### Class B — validation / quality-gate self-block
559
+
560
+ A self-block has **no** `is blocked by` dependency: the build-intake/agent flow claimed the item,
561
+ its pre-flight `verify`/`validate` gate failed (missing Validation Journey, Sign-in Required,
562
+ Target Backend Environment, Repository, Out of Scope, Evidence manifest, weak Acceptance Criteria,
563
+ etc.), and the item was bounced to `blocked` carrying that gate's `[lisa-*]` note + "Missing
564
+ requirements" list. Detect it by: (1) the block note bears a known gate marker (e.g.
565
+ `Pre-flight verify gate: BLOCKED`, `jira-verify` / `*-validate-*`), **and** (2) there is no open
566
+ `is blocked by` dependency. (If both a dependency and a self-block are present, clear the
567
+ dependency via Class A first; the self-block re-check still gates the eventual re-dispatch.)
568
+
569
+ Clear-check by **re-running the same gate against current content** — `lisa:tracker-validate`
570
+ (read-only; never writes), which dispatches to `lisa:<tracker>-validate-*` exactly as the write
571
+ path and build-intake do, so the bar cannot drift:
572
+
573
+ - **PASS** → cleared. Proceed to re-dispatch (decision tree step 2).
574
+ - **FAIL** → still self-blocked. Refresh the note with the current missing set (Loop prevention).
575
+
576
+ Conservative, same as Class A: a still-failing gate is a real blocker — never re-dispatch a build
577
+ whose own gate has not yet passed. This is intentionally symmetric with the PRD `blocked →
578
+ re-validate` path: PRDs re-run their dry-run `validate→route` when source content changes; builds
579
+ re-run `tracker-validate` when item content changes. The asymmetry where build `blocked` checked
580
+ only dependencies — leaving verify-gate self-blocks stranded forever after a human filled in the
581
+ missing sections — is the gap this class closes.
582
+
583
+ ### Class C — ambiguity / clarifying answers
584
+
585
+ A block that research or a human answer can settle (no dependency, no failing gate). Re-check by
586
+ running the needed research (`lisa:codebase-research` / `lisa:product-walkthrough`) or detecting a
587
+ human comment/edit newer than the last `[lisa-repair-intake]` note. Resolved → proceed to
588
+ re-dispatch; else stay blocked.
589
+
488
590
  ## Loop prevention
489
591
 
490
592
  A `blocked` item with a permanently unresolved problem must not be "repaired" and re-noted every
@@ -492,7 +594,10 @@ cron tick.
492
594
 
493
595
  - Every note this skill writes is prefixed `[lisa-repair-intake]` and carries a compact **state
494
596
  fingerprint**: the lifecycle role, the set of blocker refs + their observed states, the
495
- validation verdict (PASS/FAIL), terminal/open state, rollup child tally, and a timestamp.
597
+ validation verdict (PASS/FAIL) **plus the current missing-requirement set for a Class-B
598
+ self-block** (so a human filling in one of several missing sections changes the fingerprint and
599
+ triggers a re-check next cycle, rather than being suppressed as a no-op), terminal/open state,
600
+ rollup child tally, and a timestamp.
496
601
  - Before writing a note or re-attempting a `blocked` item, compute the current fingerprint. If
497
602
  an identical fingerprint was already posted within the **backoff window**, skip the item
498
603
  silently (record as `still_blocked` / `active`, no write).
@@ -548,8 +653,10 @@ It MUST NOT:
548
653
  containers, that need their derived state applied (status-only reconciliation, no native
549
654
  close),
550
655
  4. `blocked` items whose dependencies are now **cleared** (safe, high-value, one-cycle wins),
551
- 5. `blocked` items with **new clarifying answers**,
552
- 6. **stalled** in-progress items, oldest activity first.
656
+ 5. `blocked` items whose **validation / quality-gate self-block now re-validates PASS** —
657
+ a human filled in the missing sections (Class B; equally safe and high-value),
658
+ 6. `blocked` items with **new clarifying answers**,
659
+ 7. **stalled** in-progress items, oldest activity first.
553
660
  4. **Walk the ordered list**, evaluating each candidate (terminal close-out, rollup child tally,
554
661
  staleness, dependency, answer checks), and repair **every** candidate that is actionable inside
555
662
  the `max_candidates` cap. Continue after successful writes and after per-item errors.
@@ -568,6 +675,11 @@ often consists of cheap close-out reconciliation that should drain in one cron p
568
675
  Report outcomes in these buckets:
569
676
 
570
677
  - `resumed` — stalled in-progress work re-dispatched in place.
678
+ - `resynced` — a stalled build whose PR was merely behind its base, re-synced via
679
+ `gh pr update-branch` so the already-enabled auto-merge can land; the item stays `claimed` for a
680
+ later cycle to confirm the merge and transition.
681
+ - `recovered` — a stalled build whose PR had already merged, advanced by applying the env-resolved
682
+ `claimed → done` transition build-intake never got to (no re-dispatch).
571
683
  - `unblocked` — blocker cleared (or answers resolved); re-dispatched or transitioned to
572
684
  `ticketed`.
573
685
  - `closed_out` — terminal-labeled items whose native open/active state was closed, completed,
@@ -606,6 +718,10 @@ stuck work accumulates), or interleaved on a longer cadence.
606
718
  child work is terminal.
607
719
  - Apply build `done` ONLY via the env-resolution rules, and trigger native closure only at the
608
720
  true terminal `done` value (`leaf-only-lifecycle`).
721
+ - A `blocked` build item's blocker may be a dependency, a validation/quality-gate self-block (no
722
+ dependency — re-check by re-running `lisa:tracker-validate` against current content), or an
723
+ ambiguity. Re-check every class present; do not treat "no `is blocked by` links" as "nothing to
724
+ do."
609
725
  - Never re-dispatch a `blocked` build item unless every parsed blocker is cleared (conservative
610
726
  dependency clearing).
611
727
  - Repair every materially actionable candidate inside the `max_candidates` cap; default cap is 100.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.129.6",
3
+ "version": "2.129.8",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -264,24 +264,30 @@ Invoke `lisa:github-agent` (the per-issue lifecycle agent) with the issue ref. `
264
264
 
265
265
  Wait for `lisa:github-agent` to return. Capture its outcome:
266
266
 
267
- - **Success** — PR is ready (open or merged); evidence posted; ready for next status.
267
+ - **Success** — the build flow completed and a PR exists; evidence posted. The PR may already be **merged** or still **open** (auto-merge enabled, awaiting checks/merge). "Success" means the build work is sound — it does **not** assert the change reached an environment. The env transition in 3d gates on the PR actually being merged; an open PR does not advance the issue to a `done` env status.
268
268
  - **Blocked by github-verify pre-flight gate** — `lisa:github-agent` itself relabels the issue to `status:blocked` (or removes `$CLAIMED` and reassigns to the original author). This is correct and expected — let it stand. Record and move on.
269
269
  - **Blocked by ticket-triage ambiguities** — `lisa:github-agent` posts findings and stops. The issue stays in `$CLAIMED`. Surface to human; do not auto-relabel. Record under "Errors".
270
270
  - **Errored** — exception, missing config, etc. Leave the issue in `$CLAIMED` for human investigation. Record under "Errors".
271
271
 
272
- #### 3d. Transition to $DONE (only on Success)
272
+ #### 3d. Transition to $DONE (only after the PR is merged)
273
+
274
+ A `done` env state (`status:on-dev`, `status:on-stg`, or the terminal value) asserts that the code has actually reached that environment. Never set it for a PR that is merely open: auto-merge can be blocked indefinitely (a required rebase / `BEHIND` branch, failing checks, an unaddressed review), and the change may never land. Relabeling an issue `status:on-stg` on an open PR makes it *claim* a deploy that never happened. Transition only after confirming the PR merged.
273
275
 
274
276
  If `lisa:github-agent` returned Success:
275
277
 
276
- 1. Resolve `$DONE` for this issue's PR base branch using the Workflow resolution algorithm above. If env can't be resolved and `done` is env-keyed, record an Error and skip this transition — never guess.
277
- 2. Determine whether `$DONE` is the true terminal done value per the `leaf-only-lifecycle` rule's Terminal native closure section:
278
+ 1. **Confirm the PR merged.** Read the live state of the issue's PR `gh pr view <pr> --json state,mergedAt,mergeStateStatus,url`:
279
+ - **Merged** (`state == MERGED`) → proceed to resolve and apply `$DONE` below. Where the env deploy is observable (a deploy workflow run / deployment status keyed to the merged-into branch via `deploy.branches`), confirm it did not fail before relabeling; a still-running deploy is treated like an open PR (leave in `$CLAIMED`), a failed deploy is recorded as an Error.
280
+ - **Open / not yet merged** → do **not** transition. The build is sound but the change has reached no environment yet. Record the issue under **"PR open — awaiting merge"** in the summary (with the PR URL and its `mergeStateStatus`), leave it in `$CLAIMED`, and stop. A later `lisa:repair-intake` cycle drives the open PR to merge — re-syncing a `BEHIND` branch so the already-enabled auto-merge can land, or surfacing a real blocker — and, once merged, applies this same env transition. Do **not** comment "Build complete" or close anything.
281
+ - **Closed without merging** → record an Error (the PR was abandoned unmerged); leave the issue in `$CLAIMED`.
282
+ 2. Resolve `$DONE` for this issue's PR base branch using the Workflow resolution algorithm above. If env can't be resolved and `done` is env-keyed, record an Error and skip this transition — never guess.
283
+ 3. Determine whether `$DONE` is the true terminal done value per the `leaf-only-lifecycle` rule's Terminal native closure section:
278
284
  - If `github.labels.build.done` is a string, that string is terminal.
279
285
  - If `github.labels.build.done` is an object, only the production/final environment value is terminal (default: `status:done`). Intermediate env values such as `status:on-dev` and `status:on-stg` are not terminal and must stay open.
280
286
  - If the project uses a different final environment name, resolve it from the configured deployment topology; if ambiguous, record an Error and do not close.
281
287
 
282
288
  ```bash
283
289
  gh issue edit <number> --repo <org>/<repo> --remove-label "$CLAIMED" --add-label "$DONE"
284
- gh issue comment <number> --repo <org>/<repo> --body "[claude-build-intake] Build complete. PR <URL>. Transitioned to $DONE."
290
+ gh issue comment <number> --repo <org>/<repo> --body "[claude-build-intake] Build complete. PR <URL> merged. Transitioned to $DONE."
285
291
  ```
286
292
 
287
293
  If `$DONE` is terminal, immediately close the native GitHub issue:
@@ -308,8 +314,10 @@ Cycle started: <ISO timestamp>
308
314
  Cycle completed: <ISO timestamp>
309
315
 
310
316
  Issues processed: <n>
311
- - $DONE (build complete, PR ready): <n>
317
+ - $DONE (build complete, PR merged): <n>
312
318
  - <org>/<repo>#<number> <title> → PR <URL>
319
+ - PR open — awaiting merge (left in $CLAIMED for repair-intake): <n>
320
+ - <org>/<repo>#<number> <title> → PR <URL> (mergeStateStatus: <state>)
313
321
  - Repaired (container — leaf-only-lifecycle): <n>
314
322
  - <org>/<repo>#<number> <title> — build-ready on a parent/container; moved $READY → $CLAIMED without invoking lisa:github-agent; lifecycle-repair comment posted
315
323
  - Skipped (active blockers): <n>