@codyswann/lisa 2.259.1 → 2.259.3
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.
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +76 -4
- package/plugins/lisa/.codex-plugin/skills/lisa-git-submit-pr/SKILL.md +3 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-sync/SKILL.md +9 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +5 -1
- package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +77 -5
- package/plugins/lisa/skills/lisa-git-submit-pr/SKILL.md +3 -1
- package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-linear-sync/SKILL.md +9 -0
- package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +5 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +77 -5
- package/plugins/lisa-agy/skills/lisa-git-submit-pr/SKILL.md +3 -1
- package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-linear-sync/SKILL.md +9 -0
- package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +5 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +77 -5
- package/plugins/lisa-copilot/skills/lisa-git-submit-pr/SKILL.md +3 -1
- package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-linear-sync/SKILL.md +9 -0
- package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +5 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +77 -5
- package/plugins/lisa-cursor/skills/lisa-git-submit-pr/SKILL.md +3 -1
- package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-linear-sync/SKILL.md +9 -0
- package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +5 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +77 -5
- package/plugins/src/base/skills/lisa-git-submit-pr/SKILL.md +3 -1
- package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-linear-sync/SKILL.md +9 -0
- package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +5 -1
package/package.json
CHANGED
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"form-data": ">=4.0.6"
|
|
103
103
|
},
|
|
104
104
|
"name": "@codyswann/lisa",
|
|
105
|
-
"version": "2.259.
|
|
105
|
+
"version": "2.259.3",
|
|
106
106
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
107
107
|
"main": "dist/index.js",
|
|
108
108
|
"exports": {
|
|
@@ -246,11 +246,16 @@ head's checks to start, then re-enable auto-merge (section 1). In
|
|
|
246
246
|
`on_blocker=report` mode this whole step is off-limits (diagnose-only): do not
|
|
247
247
|
merge, close, or delete anything — return `blocked:pending-auto-fix`.
|
|
248
248
|
|
|
249
|
-
## 3. Merge and verify it actually shipped (ancestry
|
|
249
|
+
## 3. Merge and verify it actually shipped (ancestry + deploy run)
|
|
250
250
|
|
|
251
251
|
Enabling auto-merge + green checks + resolved threads is **not** proof the merge
|
|
252
|
-
included your fix
|
|
253
|
-
|
|
252
|
+
included your fix, and a passing merge **not** proof anything deployed. Both must
|
|
253
|
+
be verified after the PR reports `MERGED`.
|
|
254
|
+
|
|
255
|
+
### a. Ancestry check — is my code in the merged branch
|
|
256
|
+
|
|
257
|
+
Auto-merge can land the PRIOR head the instant gates go green, before a late fix
|
|
258
|
+
commit becomes the head:
|
|
254
259
|
|
|
255
260
|
```bash
|
|
256
261
|
git fetch origin
|
|
@@ -263,11 +268,78 @@ ship — fix forward with a new commit/PR and re-drive. Re-confirm after any com
|
|
|
263
268
|
that lands while auto-merge is enabled; a successful merge of an older head is a
|
|
264
269
|
failed drive-to-merge outcome, not a successful closeout.
|
|
265
270
|
|
|
271
|
+
### b. Deploy-run check — did a deploy/release workflow run actually fire
|
|
272
|
+
|
|
273
|
+
Ancestry proves your code is *in* the merged branch; it does **not** prove
|
|
274
|
+
anything deployed. GitHub can **suppress the `on: push` event for a merge commit
|
|
275
|
+
created by auto-merge or a bot token** (`GITHUB_TOKEN`), so the deploy workflow
|
|
276
|
+
fires **zero** runs — no run, not even a `startup_failure` — while the ancestry
|
|
277
|
+
check above stays green. Incident of record: TunnlAI/frontend **TUN-186** (PR #67)
|
|
278
|
+
merged to `dev` via auto-merge; the merge commit `1b3f836` produced **no**
|
|
279
|
+
`deploy.yml` run, and only the next human push `d1fe18c` (which carries `1b3f836`
|
|
280
|
+
as an ancestor) actually shipped it. **Never report shipped on ancestry alone.**
|
|
281
|
+
|
|
282
|
+
After ancestry passes, capture the merge SHA and poll for a **deploy/release
|
|
283
|
+
workflow run** whose head SHA **is the merge SHA or an including descendant** (a
|
|
284
|
+
run whose head has the merge SHA as an ancestor also shipped the merge, mirroring
|
|
285
|
+
`d1fe18c` shipping `1b3f836`), keyed to the merged-into branch. The observing
|
|
286
|
+
workflow name is **not fixed** — do **not** hardcode `deploy.yml`:
|
|
287
|
+
|
|
288
|
+
- **Downstream projects:** the deploy/release workflow run keyed to the base
|
|
289
|
+
branch resolved via `.lisa.config.json` `deploy.branches` (the merged-into env
|
|
290
|
+
branch) — the same "deploy run keyed to the merged-into branch via
|
|
291
|
+
`deploy.branches`" observation `lisa-linear-build-intake` performs before
|
|
292
|
+
relabeling.
|
|
293
|
+
- **lisa / other repos:** the repo's release or publish workflow for
|
|
294
|
+
`<baseRefName>`.
|
|
295
|
+
|
|
296
|
+
Discover the run with the same `gh run list --json …headSha…` pattern
|
|
297
|
+
`lisa-verify-workflow-change` uses:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
merge_sha=$(gh pr view <pr> --json mergeCommit -q .mergeCommit.oid)
|
|
301
|
+
gh run list --branch <baseRefName> --commit "$merge_sha" \
|
|
302
|
+
--json databaseId,workflowName,status,conclusion,headSha,headBranch,createdAt --limit 20
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Bounded wait:** a just-created run can take a few seconds to register — poll
|
|
306
|
+
briefly (a small number of short intervals / a short ceiling, mirroring the "wait
|
|
307
|
+
for that head's checks to start" bound used above) before concluding the run is
|
|
308
|
+
absent, so a not-yet-registered run is not mis-read as zero. When no run matches
|
|
309
|
+
the merge SHA directly, also accept a descendant run whose head has `$merge_sha`
|
|
310
|
+
as an ancestor (`git merge-base --is-ancestor "$merge_sha" <run_head_sha>`).
|
|
311
|
+
|
|
312
|
+
**Zero runs after the bounded wait — do NOT report shipped.** Recover in order:
|
|
313
|
+
|
|
314
|
+
1. **Dispatch the deploy, then re-verify.** Trigger the env's `workflow_dispatch`
|
|
315
|
+
for the merged-into branch and re-poll for a run that now covers the merge SHA
|
|
316
|
+
(or an including descendant):
|
|
317
|
+
```bash
|
|
318
|
+
gh workflow run <deploy-or-release-workflow> --ref <baseRefName>
|
|
319
|
+
```
|
|
320
|
+
Once such a run appears, the merge is confirmed shipped.
|
|
321
|
+
2. **Still zero, or dispatch not permitted → surface a blocker.** Emit a hard
|
|
322
|
+
block (`blocked:deploy`) reporting exactly what was observed — the merge SHA,
|
|
323
|
+
the base branch, and zero deploy runs. A failed/blocked path, **never** a
|
|
324
|
+
silent "done".
|
|
325
|
+
|
|
326
|
+
In **`on_blocker=report`** mode this deploy-run step is diagnose-only: dispatching
|
|
327
|
+
a workflow is an action, so do **not** run `gh workflow run` / `workflow_dispatch`
|
|
328
|
+
— classify the absence as `blocked:deploy` (or `blocked:no-deploy-run`) and return
|
|
329
|
+
it for the caller to act on, consistent with the report-mode contract (steps b–f
|
|
330
|
+
of section 2 are diagnose-only).
|
|
331
|
+
|
|
266
332
|
## 4. Terminal states
|
|
267
333
|
|
|
268
334
|
Loop until one of:
|
|
269
335
|
|
|
270
|
-
- **`MERGED`** and the ancestry check passes
|
|
336
|
+
- **`MERGED`** and the ancestry check passes **and** a deploy/release run for the
|
|
337
|
+
merge SHA (or an including descendant) is confirmed — observed directly or after
|
|
338
|
+
a `workflow_dispatch` recovery → success. Ancestry alone is **not** success.
|
|
339
|
+
- **`blocked:deploy`** — merged with ancestry green, but after the bounded wait no
|
|
340
|
+
deploy/release run fired for the merge SHA and dispatch recovery could not
|
|
341
|
+
confirm one (or was not permitted, e.g. `on_blocker=report`). Stop and report
|
|
342
|
+
the merge SHA, base branch, and zero observed runs — never a silent "done".
|
|
271
343
|
- **`awaiting-human`** (`auto_merge=false` only) → success. The PR is `OPEN`,
|
|
272
344
|
required checks are green, the review gate is clear, and
|
|
273
345
|
`mergeable == MERGEABLE`, with auto-merge deliberately not enabled
|
|
@@ -51,7 +51,9 @@ Add provider-appropriate linkage to the PR title and/or body without changing th
|
|
|
51
51
|
- For cross-repo issue refs, use the fully qualified form, for example `Closes CodySwannGT/lisa#614` or `Refs CodySwannGT/lisa#614`.
|
|
52
52
|
- **Linear**:
|
|
53
53
|
- Ensure the Linear issue identifier appears in the branch name when the branch is created upstream by `lisa-implement`.
|
|
54
|
-
- Include the identifier in the PR title or body, for example `Linear: ENG-123`, so Linear's GitHub integration can attach the PR.
|
|
54
|
+
- Include the identifier as a **non-closing** attach token in the PR title or body, for example `Linear: ENG-123` or `Refs ENG-123`, so Linear's GitHub integration can attach the PR without completing the Issue.
|
|
55
|
+
- **Do not** emit a Linear magic word (`Closes`/`Fixes`/`Resolves ENG-123`) in the PR title, body, or commit message unless the target branch is the terminal/production branch — the repository default branch or the configured production branch from `.lisa.config.json` `deploy.branches.production` (resolved via `config-resolution`). Unlike GitHub, whose `Closes` auto-close is scoped to the default branch, Linear's integration completes a linked Issue on merge to **any branch**, so a magic word on a non-terminal env merge (for example into `dev` or `staging`) auto-closes the Issue prematurely and front-runs the env-keyed `status:*` label ladder. This is the `leaf-only-lifecycle` "Terminal native closure" invariant (native closure only at the production terminal `done`) — cite it, do not restate.
|
|
56
|
+
- On a non-terminal env branch, use only the non-closing attach form and strip/neutralize any magic word copied from a ticket title or commit message. Branch-name linkage alone can still auto-complete the Issue where a Linear team enables "complete on any linked-PR merge" — behavior we cannot suppress from our side — so the post-merge reconciliation in `lisa-linear-sync` is the mandatory backstop, not an optional cleanup.
|
|
55
57
|
- **JIRA**:
|
|
56
58
|
- Ensure the JIRA issue key appears in the branch name when the branch is created upstream by `lisa-implement`.
|
|
57
59
|
- Include the key in the PR title or body, for example `JIRA: PROJ-456`, so the GitHub-JIRA integration can attach the PR.
|
|
@@ -283,7 +283,7 @@ If the lifecycle run returned Success:
|
|
|
283
283
|
- 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.
|
|
284
284
|
- 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.
|
|
285
285
|
4. Update labels via `lisa-linear-access operation: save-issue`: remove `$CLAIMED` (or `$REVIEW` if `lisa-linear-evidence` already moved it forward), add `$DONE`.
|
|
286
|
-
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.
|
|
286
|
+
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. Conversely, if `$DONE` is an intermediate env yet Linear already natively completed the Issue (a magic-word / branch-linkage front-run — Linear auto-completes on merge to **any branch**, per the asymmetry documented in `git-submit-pr`), reconcile it back to active via `lisa-linear-sync` Phase 4b so the native state mirrors the non-terminal env instead of a premature closure.
|
|
287
287
|
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.
|
|
288
288
|
|
|
289
289
|
For any non-Success outcome, do NOT transition. The Issue sits where the lifecycle left it — humans take it from there.
|
|
@@ -92,6 +92,15 @@ Verify exactly one `status:*` label remains after the update — having two simu
|
|
|
92
92
|
|
|
93
93
|
Without `--update-label`, this skill posts the comment only and does NOT touch labels.
|
|
94
94
|
|
|
95
|
+
## Phase 4b — Reconcile Native Auto-Close (Linear-specific)
|
|
96
|
+
|
|
97
|
+
Linear's GitHub integration completes a linked Issue on merge to **any branch** — unlike GitHub's default-branch-scoped `Closes` auto-close — so a magic word (`Closes`/`Fixes`/`Resolves ENG-123`) or branch-name linkage can natively move the Issue to a Done/Completed workflow `state` at a **non-terminal** env merge, front-running the env-keyed `status:*` label ladder. `git-submit-pr` prevents the magic-word case; this phase is the required post-merge repair for the residual (branch-linkage) case we cannot suppress server-side. Run it on a `pr-merged` sync whose resolved env is **intermediate** (below the production terminal `done`):
|
|
98
|
+
|
|
99
|
+
1. Resolve the merged PR's base branch to its env via `.lisa.config.json` `deploy.branches` (`config-resolution`). If it maps to the production/terminal `done`, this phase is a **no-op** — native completion is correct there.
|
|
100
|
+
2. **Uniform / single-environment no-op.** When the project's env-keyed `done` map is uniform — every environment resolves to the same `status:done`, as in this repo (`production: main` only) and TunnlAI/frontend — dev-merge == terminal, so native completion is correct. Do nothing. Only a **non-uniform** env→`done` map (distinct `status:on-dev`/`status:on-stg`/`status:done` rungs) can desync.
|
|
101
|
+
3. Otherwise (non-uniform map, resolved env intermediate): re-read the Issue's native workflow `state`. If Linear natively moved it into a Done/Completed category while the derived `status:*` label is a lower env, **re-open** the native `state` back to the active/in-progress category (via `lisa-linear-access operation: save-issue`) so it mirrors the true env stage, and post a short `[lisa-linear-sync]` reconciliation comment. This applies the `leaf-only-lifecycle` "Terminal native closure" rule — native closure fires **only** at the production terminal `done` — as a *repair* of Linear front-running it. Cite the rule by slug; do not restate it.
|
|
102
|
+
4. **Safe default.** If the true terminal cannot be resolved (ambiguous env or unresolvable `done` map), do not change the native `state` — post a `[lisa-linear-sync]` reconciliation-suggestion comment and leave it untouched, mirroring the Phase 5 safe default.
|
|
103
|
+
|
|
95
104
|
## Phase 5 — Parent Status Rollup (`--rollup`)
|
|
96
105
|
|
|
97
106
|
When the caller passes `--rollup`, this skill **derives a parent/container's `status:*` label from the roll-up of its children** instead of acting on a leaf. A **Project** (the Epic equivalent) rolls up from its Issues; an **Issue** rolls up from its sub-Issues. This implements the Linear child-issue-status arm of the **Parent status rollup (the state machine)** section of the `leaf-only-lifecycle` rule — cite that rule, do not restate the policy.
|
|
@@ -38,7 +38,11 @@ close-out** roles and moves work *unstuck* or *fully closed*:
|
|
|
38
38
|
one missed by dependency-only re-checks: nothing else is blocking it, so re-running the same gate
|
|
39
39
|
against its current content is the only way to know it is now passable.
|
|
40
40
|
- **Terminal-open drift** — an item already carrying its true terminal lifecycle role (for
|
|
41
|
-
example GitHub `status:done`) but still open/active in the provider's native state.
|
|
41
|
+
example GitHub `status:done`) but still open/active in the provider's native state. The inverse
|
|
42
|
+
also drifts on Linear: a leaf whose native `state` was auto-completed by a magic-word / branch-linkage
|
|
43
|
+
merge into a **non-terminal** env (Linear completes on merge to any branch, unlike GitHub's
|
|
44
|
+
default-branch-scoped close) while its derived `status:*` label is still intermediate — reconcile
|
|
45
|
+
it back to active via `lisa-linear-sync` Phase 4b per `leaf-only-lifecycle`.
|
|
42
46
|
- **Rollup drift** — a parent/container item (Epic, Story, PRD, Linear Project, or equivalent)
|
|
43
47
|
whose own lifecycle state does not match the roll-up of its children's states per
|
|
44
48
|
`leaf-only-lifecycle`. This covers the *completed* case (all children terminal → close the parent
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: lisa-drive-pr-to-merge
|
|
3
|
-
description: This skill should be used to drive a pull request all the way to MERGED, handling ANYTHING that blocks the merge. It enables auto-merge when the repo supports it (direct-merge fallback otherwise), keeps the branch rebased/synced and resolves merge conflicts, fixes failing CI/deploy checks, addresses and resolves every human and bot review comment (CodeRabbit, etc.) — implementing valid feedback and replying-then-resolving invalid feedback — dismisses stale CHANGES_REQUESTED gates, and verifies the fix actually shipped (auto-merge race
|
|
3
|
+
description: This skill should be used to drive a pull request all the way to MERGED, handling ANYTHING that blocks the merge. It enables auto-merge when the repo supports it (direct-merge fallback otherwise), keeps the branch rebased/synced and resolves merge conflicts, fixes failing CI/deploy checks, addresses and resolves every human and bot review comment (CodeRabbit, etc.) — implementing valid feedback and replying-then-resolving invalid feedback — dismisses stale CHANGES_REQUESTED gates, and verifies the fix actually shipped — both merge ancestry and that a deploy/release run fired for the merge SHA (auto-merge race + zero-deploy-run check). Composable and inline — invoked by other skills (e.g. git-submit-pr, implement, sync-down) via the Skill tool, never as a standalone user command.
|
|
4
4
|
allowed-tools: ["Bash", "Read", "Edit", "Write", "Grep", "Glob", "Skill"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -246,11 +246,16 @@ head's checks to start, then re-enable auto-merge (section 1). In
|
|
|
246
246
|
`on_blocker=report` mode this whole step is off-limits (diagnose-only): do not
|
|
247
247
|
merge, close, or delete anything — return `blocked:pending-auto-fix`.
|
|
248
248
|
|
|
249
|
-
## 3. Merge and verify it actually shipped (ancestry
|
|
249
|
+
## 3. Merge and verify it actually shipped (ancestry + deploy run)
|
|
250
250
|
|
|
251
251
|
Enabling auto-merge + green checks + resolved threads is **not** proof the merge
|
|
252
|
-
included your fix
|
|
253
|
-
|
|
252
|
+
included your fix, and a passing merge **not** proof anything deployed. Both must
|
|
253
|
+
be verified after the PR reports `MERGED`.
|
|
254
|
+
|
|
255
|
+
### a. Ancestry check — is my code in the merged branch
|
|
256
|
+
|
|
257
|
+
Auto-merge can land the PRIOR head the instant gates go green, before a late fix
|
|
258
|
+
commit becomes the head:
|
|
254
259
|
|
|
255
260
|
```bash
|
|
256
261
|
git fetch origin
|
|
@@ -263,11 +268,78 @@ ship — fix forward with a new commit/PR and re-drive. Re-confirm after any com
|
|
|
263
268
|
that lands while auto-merge is enabled; a successful merge of an older head is a
|
|
264
269
|
failed drive-to-merge outcome, not a successful closeout.
|
|
265
270
|
|
|
271
|
+
### b. Deploy-run check — did a deploy/release workflow run actually fire
|
|
272
|
+
|
|
273
|
+
Ancestry proves your code is *in* the merged branch; it does **not** prove
|
|
274
|
+
anything deployed. GitHub can **suppress the `on: push` event for a merge commit
|
|
275
|
+
created by auto-merge or a bot token** (`GITHUB_TOKEN`), so the deploy workflow
|
|
276
|
+
fires **zero** runs — no run, not even a `startup_failure` — while the ancestry
|
|
277
|
+
check above stays green. Incident of record: TunnlAI/frontend **TUN-186** (PR #67)
|
|
278
|
+
merged to `dev` via auto-merge; the merge commit `1b3f836` produced **no**
|
|
279
|
+
`deploy.yml` run, and only the next human push `d1fe18c` (which carries `1b3f836`
|
|
280
|
+
as an ancestor) actually shipped it. **Never report shipped on ancestry alone.**
|
|
281
|
+
|
|
282
|
+
After ancestry passes, capture the merge SHA and poll for a **deploy/release
|
|
283
|
+
workflow run** whose head SHA **is the merge SHA or an including descendant** (a
|
|
284
|
+
run whose head has the merge SHA as an ancestor also shipped the merge, mirroring
|
|
285
|
+
`d1fe18c` shipping `1b3f836`), keyed to the merged-into branch. The observing
|
|
286
|
+
workflow name is **not fixed** — do **not** hardcode `deploy.yml`:
|
|
287
|
+
|
|
288
|
+
- **Downstream projects:** the deploy/release workflow run keyed to the base
|
|
289
|
+
branch resolved via `.lisa.config.json` `deploy.branches` (the merged-into env
|
|
290
|
+
branch) — the same "deploy run keyed to the merged-into branch via
|
|
291
|
+
`deploy.branches`" observation `lisa-linear-build-intake` performs before
|
|
292
|
+
relabeling.
|
|
293
|
+
- **lisa / other repos:** the repo's release or publish workflow for
|
|
294
|
+
`<baseRefName>`.
|
|
295
|
+
|
|
296
|
+
Discover the run with the same `gh run list --json …headSha…` pattern
|
|
297
|
+
`lisa-verify-workflow-change` uses:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
merge_sha=$(gh pr view <pr> --json mergeCommit -q .mergeCommit.oid)
|
|
301
|
+
gh run list --branch <baseRefName> --commit "$merge_sha" \
|
|
302
|
+
--json databaseId,workflowName,status,conclusion,headSha,headBranch,createdAt --limit 20
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Bounded wait:** a just-created run can take a few seconds to register — poll
|
|
306
|
+
briefly (a small number of short intervals / a short ceiling, mirroring the "wait
|
|
307
|
+
for that head's checks to start" bound used above) before concluding the run is
|
|
308
|
+
absent, so a not-yet-registered run is not mis-read as zero. When no run matches
|
|
309
|
+
the merge SHA directly, also accept a descendant run whose head has `$merge_sha`
|
|
310
|
+
as an ancestor (`git merge-base --is-ancestor "$merge_sha" <run_head_sha>`).
|
|
311
|
+
|
|
312
|
+
**Zero runs after the bounded wait — do NOT report shipped.** Recover in order:
|
|
313
|
+
|
|
314
|
+
1. **Dispatch the deploy, then re-verify.** Trigger the env's `workflow_dispatch`
|
|
315
|
+
for the merged-into branch and re-poll for a run that now covers the merge SHA
|
|
316
|
+
(or an including descendant):
|
|
317
|
+
```bash
|
|
318
|
+
gh workflow run <deploy-or-release-workflow> --ref <baseRefName>
|
|
319
|
+
```
|
|
320
|
+
Once such a run appears, the merge is confirmed shipped.
|
|
321
|
+
2. **Still zero, or dispatch not permitted → surface a blocker.** Emit a hard
|
|
322
|
+
block (`blocked:deploy`) reporting exactly what was observed — the merge SHA,
|
|
323
|
+
the base branch, and zero deploy runs. A failed/blocked path, **never** a
|
|
324
|
+
silent "done".
|
|
325
|
+
|
|
326
|
+
In **`on_blocker=report`** mode this deploy-run step is diagnose-only: dispatching
|
|
327
|
+
a workflow is an action, so do **not** run `gh workflow run` / `workflow_dispatch`
|
|
328
|
+
— classify the absence as `blocked:deploy` (or `blocked:no-deploy-run`) and return
|
|
329
|
+
it for the caller to act on, consistent with the report-mode contract (steps b–f
|
|
330
|
+
of section 2 are diagnose-only).
|
|
331
|
+
|
|
266
332
|
## 4. Terminal states
|
|
267
333
|
|
|
268
334
|
Loop until one of:
|
|
269
335
|
|
|
270
|
-
- **`MERGED`** and the ancestry check passes
|
|
336
|
+
- **`MERGED`** and the ancestry check passes **and** a deploy/release run for the
|
|
337
|
+
merge SHA (or an including descendant) is confirmed — observed directly or after
|
|
338
|
+
a `workflow_dispatch` recovery → success. Ancestry alone is **not** success.
|
|
339
|
+
- **`blocked:deploy`** — merged with ancestry green, but after the bounded wait no
|
|
340
|
+
deploy/release run fired for the merge SHA and dispatch recovery could not
|
|
341
|
+
confirm one (or was not permitted, e.g. `on_blocker=report`). Stop and report
|
|
342
|
+
the merge SHA, base branch, and zero observed runs — never a silent "done".
|
|
271
343
|
- **`awaiting-human`** (`auto_merge=false` only) → success. The PR is `OPEN`,
|
|
272
344
|
required checks are green, the review gate is clear, and
|
|
273
345
|
`mergeable == MERGEABLE`, with auto-merge deliberately not enabled
|
|
@@ -51,7 +51,9 @@ Add provider-appropriate linkage to the PR title and/or body without changing th
|
|
|
51
51
|
- For cross-repo issue refs, use the fully qualified form, for example `Closes CodySwannGT/lisa#614` or `Refs CodySwannGT/lisa#614`.
|
|
52
52
|
- **Linear**:
|
|
53
53
|
- Ensure the Linear issue identifier appears in the branch name when the branch is created upstream by `lisa-implement`.
|
|
54
|
-
- Include the identifier in the PR title or body, for example `Linear: ENG-123`, so Linear's GitHub integration can attach the PR.
|
|
54
|
+
- Include the identifier as a **non-closing** attach token in the PR title or body, for example `Linear: ENG-123` or `Refs ENG-123`, so Linear's GitHub integration can attach the PR without completing the Issue.
|
|
55
|
+
- **Do not** emit a Linear magic word (`Closes`/`Fixes`/`Resolves ENG-123`) in the PR title, body, or commit message unless the target branch is the terminal/production branch — the repository default branch or the configured production branch from `.lisa.config.json` `deploy.branches.production` (resolved via `config-resolution`). Unlike GitHub, whose `Closes` auto-close is scoped to the default branch, Linear's integration completes a linked Issue on merge to **any branch**, so a magic word on a non-terminal env merge (for example into `dev` or `staging`) auto-closes the Issue prematurely and front-runs the env-keyed `status:*` label ladder. This is the `leaf-only-lifecycle` "Terminal native closure" invariant (native closure only at the production terminal `done`) — cite it, do not restate.
|
|
56
|
+
- On a non-terminal env branch, use only the non-closing attach form and strip/neutralize any magic word copied from a ticket title or commit message. Branch-name linkage alone can still auto-complete the Issue where a Linear team enables "complete on any linked-PR merge" — behavior we cannot suppress from our side — so the post-merge reconciliation in `lisa-linear-sync` is the mandatory backstop, not an optional cleanup.
|
|
55
57
|
- **JIRA**:
|
|
56
58
|
- Ensure the JIRA issue key appears in the branch name when the branch is created upstream by `lisa-implement`.
|
|
57
59
|
- Include the key in the PR title or body, for example `JIRA: PROJ-456`, so the GitHub-JIRA integration can attach the PR.
|
|
@@ -283,7 +283,7 @@ If the lifecycle run returned Success:
|
|
|
283
283
|
- 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.
|
|
284
284
|
- 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.
|
|
285
285
|
4. Update labels via `lisa-linear-access operation: save-issue`: remove `$CLAIMED` (or `$REVIEW` if `lisa-linear-evidence` already moved it forward), add `$DONE`.
|
|
286
|
-
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.
|
|
286
|
+
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. Conversely, if `$DONE` is an intermediate env yet Linear already natively completed the Issue (a magic-word / branch-linkage front-run — Linear auto-completes on merge to **any branch**, per the asymmetry documented in `git-submit-pr`), reconcile it back to active via `lisa-linear-sync` Phase 4b so the native state mirrors the non-terminal env instead of a premature closure.
|
|
287
287
|
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.
|
|
288
288
|
|
|
289
289
|
For any non-Success outcome, do NOT transition. The Issue sits where the lifecycle left it — humans take it from there.
|
|
@@ -92,6 +92,15 @@ Verify exactly one `status:*` label remains after the update — having two simu
|
|
|
92
92
|
|
|
93
93
|
Without `--update-label`, this skill posts the comment only and does NOT touch labels.
|
|
94
94
|
|
|
95
|
+
## Phase 4b — Reconcile Native Auto-Close (Linear-specific)
|
|
96
|
+
|
|
97
|
+
Linear's GitHub integration completes a linked Issue on merge to **any branch** — unlike GitHub's default-branch-scoped `Closes` auto-close — so a magic word (`Closes`/`Fixes`/`Resolves ENG-123`) or branch-name linkage can natively move the Issue to a Done/Completed workflow `state` at a **non-terminal** env merge, front-running the env-keyed `status:*` label ladder. `git-submit-pr` prevents the magic-word case; this phase is the required post-merge repair for the residual (branch-linkage) case we cannot suppress server-side. Run it on a `pr-merged` sync whose resolved env is **intermediate** (below the production terminal `done`):
|
|
98
|
+
|
|
99
|
+
1. Resolve the merged PR's base branch to its env via `.lisa.config.json` `deploy.branches` (`config-resolution`). If it maps to the production/terminal `done`, this phase is a **no-op** — native completion is correct there.
|
|
100
|
+
2. **Uniform / single-environment no-op.** When the project's env-keyed `done` map is uniform — every environment resolves to the same `status:done`, as in this repo (`production: main` only) and TunnlAI/frontend — dev-merge == terminal, so native completion is correct. Do nothing. Only a **non-uniform** env→`done` map (distinct `status:on-dev`/`status:on-stg`/`status:done` rungs) can desync.
|
|
101
|
+
3. Otherwise (non-uniform map, resolved env intermediate): re-read the Issue's native workflow `state`. If Linear natively moved it into a Done/Completed category while the derived `status:*` label is a lower env, **re-open** the native `state` back to the active/in-progress category (via `lisa-linear-access operation: save-issue`) so it mirrors the true env stage, and post a short `[lisa-linear-sync]` reconciliation comment. This applies the `leaf-only-lifecycle` "Terminal native closure" rule — native closure fires **only** at the production terminal `done` — as a *repair* of Linear front-running it. Cite the rule by slug; do not restate it.
|
|
102
|
+
4. **Safe default.** If the true terminal cannot be resolved (ambiguous env or unresolvable `done` map), do not change the native `state` — post a `[lisa-linear-sync]` reconciliation-suggestion comment and leave it untouched, mirroring the Phase 5 safe default.
|
|
103
|
+
|
|
95
104
|
## Phase 5 — Parent Status Rollup (`--rollup`)
|
|
96
105
|
|
|
97
106
|
When the caller passes `--rollup`, this skill **derives a parent/container's `status:*` label from the roll-up of its children** instead of acting on a leaf. A **Project** (the Epic equivalent) rolls up from its Issues; an **Issue** rolls up from its sub-Issues. This implements the Linear child-issue-status arm of the **Parent status rollup (the state machine)** section of the `leaf-only-lifecycle` rule — cite that rule, do not restate the policy.
|
|
@@ -38,7 +38,11 @@ close-out** roles and moves work *unstuck* or *fully closed*:
|
|
|
38
38
|
one missed by dependency-only re-checks: nothing else is blocking it, so re-running the same gate
|
|
39
39
|
against its current content is the only way to know it is now passable.
|
|
40
40
|
- **Terminal-open drift** — an item already carrying its true terminal lifecycle role (for
|
|
41
|
-
example GitHub `status:done`) but still open/active in the provider's native state.
|
|
41
|
+
example GitHub `status:done`) but still open/active in the provider's native state. The inverse
|
|
42
|
+
also drifts on Linear: a leaf whose native `state` was auto-completed by a magic-word / branch-linkage
|
|
43
|
+
merge into a **non-terminal** env (Linear completes on merge to any branch, unlike GitHub's
|
|
44
|
+
default-branch-scoped close) while its derived `status:*` label is still intermediate — reconcile
|
|
45
|
+
it back to active via `lisa-linear-sync` Phase 4b per `leaf-only-lifecycle`.
|
|
42
46
|
- **Rollup drift** — a parent/container item (Epic, Story, PRD, Linear Project, or equivalent)
|
|
43
47
|
whose own lifecycle state does not match the roll-up of its children's states per
|
|
44
48
|
`leaf-only-lifecycle`. This covers the *completed* case (all children terminal → close the parent
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: lisa-drive-pr-to-merge
|
|
3
|
-
description: This skill should be used to drive a pull request all the way to MERGED, handling ANYTHING that blocks the merge. It enables auto-merge when the repo supports it (direct-merge fallback otherwise), keeps the branch rebased/synced and resolves merge conflicts, fixes failing CI/deploy checks, addresses and resolves every human and bot review comment (CodeRabbit, etc.) — implementing valid feedback and replying-then-resolving invalid feedback — dismisses stale CHANGES_REQUESTED gates, and verifies the fix actually shipped (auto-merge race
|
|
3
|
+
description: This skill should be used to drive a pull request all the way to MERGED, handling ANYTHING that blocks the merge. It enables auto-merge when the repo supports it (direct-merge fallback otherwise), keeps the branch rebased/synced and resolves merge conflicts, fixes failing CI/deploy checks, addresses and resolves every human and bot review comment (CodeRabbit, etc.) — implementing valid feedback and replying-then-resolving invalid feedback — dismisses stale CHANGES_REQUESTED gates, and verifies the fix actually shipped — both merge ancestry and that a deploy/release run fired for the merge SHA (auto-merge race + zero-deploy-run check). Composable and inline — invoked by other skills (e.g. git-submit-pr, implement, sync-down) via the Skill tool, never as a standalone user command.
|
|
4
4
|
allowed-tools: ["Bash", "Read", "Edit", "Write", "Grep", "Glob", "Skill"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -246,11 +246,16 @@ head's checks to start, then re-enable auto-merge (section 1). In
|
|
|
246
246
|
`on_blocker=report` mode this whole step is off-limits (diagnose-only): do not
|
|
247
247
|
merge, close, or delete anything — return `blocked:pending-auto-fix`.
|
|
248
248
|
|
|
249
|
-
## 3. Merge and verify it actually shipped (ancestry
|
|
249
|
+
## 3. Merge and verify it actually shipped (ancestry + deploy run)
|
|
250
250
|
|
|
251
251
|
Enabling auto-merge + green checks + resolved threads is **not** proof the merge
|
|
252
|
-
included your fix
|
|
253
|
-
|
|
252
|
+
included your fix, and a passing merge **not** proof anything deployed. Both must
|
|
253
|
+
be verified after the PR reports `MERGED`.
|
|
254
|
+
|
|
255
|
+
### a. Ancestry check — is my code in the merged branch
|
|
256
|
+
|
|
257
|
+
Auto-merge can land the PRIOR head the instant gates go green, before a late fix
|
|
258
|
+
commit becomes the head:
|
|
254
259
|
|
|
255
260
|
```bash
|
|
256
261
|
git fetch origin
|
|
@@ -263,11 +268,78 @@ ship — fix forward with a new commit/PR and re-drive. Re-confirm after any com
|
|
|
263
268
|
that lands while auto-merge is enabled; a successful merge of an older head is a
|
|
264
269
|
failed drive-to-merge outcome, not a successful closeout.
|
|
265
270
|
|
|
271
|
+
### b. Deploy-run check — did a deploy/release workflow run actually fire
|
|
272
|
+
|
|
273
|
+
Ancestry proves your code is *in* the merged branch; it does **not** prove
|
|
274
|
+
anything deployed. GitHub can **suppress the `on: push` event for a merge commit
|
|
275
|
+
created by auto-merge or a bot token** (`GITHUB_TOKEN`), so the deploy workflow
|
|
276
|
+
fires **zero** runs — no run, not even a `startup_failure` — while the ancestry
|
|
277
|
+
check above stays green. Incident of record: TunnlAI/frontend **TUN-186** (PR #67)
|
|
278
|
+
merged to `dev` via auto-merge; the merge commit `1b3f836` produced **no**
|
|
279
|
+
`deploy.yml` run, and only the next human push `d1fe18c` (which carries `1b3f836`
|
|
280
|
+
as an ancestor) actually shipped it. **Never report shipped on ancestry alone.**
|
|
281
|
+
|
|
282
|
+
After ancestry passes, capture the merge SHA and poll for a **deploy/release
|
|
283
|
+
workflow run** whose head SHA **is the merge SHA or an including descendant** (a
|
|
284
|
+
run whose head has the merge SHA as an ancestor also shipped the merge, mirroring
|
|
285
|
+
`d1fe18c` shipping `1b3f836`), keyed to the merged-into branch. The observing
|
|
286
|
+
workflow name is **not fixed** — do **not** hardcode `deploy.yml`:
|
|
287
|
+
|
|
288
|
+
- **Downstream projects:** the deploy/release workflow run keyed to the base
|
|
289
|
+
branch resolved via `.lisa.config.json` `deploy.branches` (the merged-into env
|
|
290
|
+
branch) — the same "deploy run keyed to the merged-into branch via
|
|
291
|
+
`deploy.branches`" observation `lisa-linear-build-intake` performs before
|
|
292
|
+
relabeling.
|
|
293
|
+
- **lisa / other repos:** the repo's release or publish workflow for
|
|
294
|
+
`<baseRefName>`.
|
|
295
|
+
|
|
296
|
+
Discover the run with the same `gh run list --json …headSha…` pattern
|
|
297
|
+
`lisa-verify-workflow-change` uses:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
merge_sha=$(gh pr view <pr> --json mergeCommit -q .mergeCommit.oid)
|
|
301
|
+
gh run list --branch <baseRefName> --commit "$merge_sha" \
|
|
302
|
+
--json databaseId,workflowName,status,conclusion,headSha,headBranch,createdAt --limit 20
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Bounded wait:** a just-created run can take a few seconds to register — poll
|
|
306
|
+
briefly (a small number of short intervals / a short ceiling, mirroring the "wait
|
|
307
|
+
for that head's checks to start" bound used above) before concluding the run is
|
|
308
|
+
absent, so a not-yet-registered run is not mis-read as zero. When no run matches
|
|
309
|
+
the merge SHA directly, also accept a descendant run whose head has `$merge_sha`
|
|
310
|
+
as an ancestor (`git merge-base --is-ancestor "$merge_sha" <run_head_sha>`).
|
|
311
|
+
|
|
312
|
+
**Zero runs after the bounded wait — do NOT report shipped.** Recover in order:
|
|
313
|
+
|
|
314
|
+
1. **Dispatch the deploy, then re-verify.** Trigger the env's `workflow_dispatch`
|
|
315
|
+
for the merged-into branch and re-poll for a run that now covers the merge SHA
|
|
316
|
+
(or an including descendant):
|
|
317
|
+
```bash
|
|
318
|
+
gh workflow run <deploy-or-release-workflow> --ref <baseRefName>
|
|
319
|
+
```
|
|
320
|
+
Once such a run appears, the merge is confirmed shipped.
|
|
321
|
+
2. **Still zero, or dispatch not permitted → surface a blocker.** Emit a hard
|
|
322
|
+
block (`blocked:deploy`) reporting exactly what was observed — the merge SHA,
|
|
323
|
+
the base branch, and zero deploy runs. A failed/blocked path, **never** a
|
|
324
|
+
silent "done".
|
|
325
|
+
|
|
326
|
+
In **`on_blocker=report`** mode this deploy-run step is diagnose-only: dispatching
|
|
327
|
+
a workflow is an action, so do **not** run `gh workflow run` / `workflow_dispatch`
|
|
328
|
+
— classify the absence as `blocked:deploy` (or `blocked:no-deploy-run`) and return
|
|
329
|
+
it for the caller to act on, consistent with the report-mode contract (steps b–f
|
|
330
|
+
of section 2 are diagnose-only).
|
|
331
|
+
|
|
266
332
|
## 4. Terminal states
|
|
267
333
|
|
|
268
334
|
Loop until one of:
|
|
269
335
|
|
|
270
|
-
- **`MERGED`** and the ancestry check passes
|
|
336
|
+
- **`MERGED`** and the ancestry check passes **and** a deploy/release run for the
|
|
337
|
+
merge SHA (or an including descendant) is confirmed — observed directly or after
|
|
338
|
+
a `workflow_dispatch` recovery → success. Ancestry alone is **not** success.
|
|
339
|
+
- **`blocked:deploy`** — merged with ancestry green, but after the bounded wait no
|
|
340
|
+
deploy/release run fired for the merge SHA and dispatch recovery could not
|
|
341
|
+
confirm one (or was not permitted, e.g. `on_blocker=report`). Stop and report
|
|
342
|
+
the merge SHA, base branch, and zero observed runs — never a silent "done".
|
|
271
343
|
- **`awaiting-human`** (`auto_merge=false` only) → success. The PR is `OPEN`,
|
|
272
344
|
required checks are green, the review gate is clear, and
|
|
273
345
|
`mergeable == MERGEABLE`, with auto-merge deliberately not enabled
|
|
@@ -51,7 +51,9 @@ Add provider-appropriate linkage to the PR title and/or body without changing th
|
|
|
51
51
|
- For cross-repo issue refs, use the fully qualified form, for example `Closes CodySwannGT/lisa#614` or `Refs CodySwannGT/lisa#614`.
|
|
52
52
|
- **Linear**:
|
|
53
53
|
- Ensure the Linear issue identifier appears in the branch name when the branch is created upstream by `lisa-implement`.
|
|
54
|
-
- Include the identifier in the PR title or body, for example `Linear: ENG-123`, so Linear's GitHub integration can attach the PR.
|
|
54
|
+
- Include the identifier as a **non-closing** attach token in the PR title or body, for example `Linear: ENG-123` or `Refs ENG-123`, so Linear's GitHub integration can attach the PR without completing the Issue.
|
|
55
|
+
- **Do not** emit a Linear magic word (`Closes`/`Fixes`/`Resolves ENG-123`) in the PR title, body, or commit message unless the target branch is the terminal/production branch — the repository default branch or the configured production branch from `.lisa.config.json` `deploy.branches.production` (resolved via `config-resolution`). Unlike GitHub, whose `Closes` auto-close is scoped to the default branch, Linear's integration completes a linked Issue on merge to **any branch**, so a magic word on a non-terminal env merge (for example into `dev` or `staging`) auto-closes the Issue prematurely and front-runs the env-keyed `status:*` label ladder. This is the `leaf-only-lifecycle` "Terminal native closure" invariant (native closure only at the production terminal `done`) — cite it, do not restate.
|
|
56
|
+
- On a non-terminal env branch, use only the non-closing attach form and strip/neutralize any magic word copied from a ticket title or commit message. Branch-name linkage alone can still auto-complete the Issue where a Linear team enables "complete on any linked-PR merge" — behavior we cannot suppress from our side — so the post-merge reconciliation in `lisa-linear-sync` is the mandatory backstop, not an optional cleanup.
|
|
55
57
|
- **JIRA**:
|
|
56
58
|
- Ensure the JIRA issue key appears in the branch name when the branch is created upstream by `lisa-implement`.
|
|
57
59
|
- Include the key in the PR title or body, for example `JIRA: PROJ-456`, so the GitHub-JIRA integration can attach the PR.
|
|
@@ -283,7 +283,7 @@ If the lifecycle run returned Success:
|
|
|
283
283
|
- 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.
|
|
284
284
|
- 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.
|
|
285
285
|
4. Update labels via `lisa-linear-access operation: save-issue`: remove `$CLAIMED` (or `$REVIEW` if `lisa-linear-evidence` already moved it forward), add `$DONE`.
|
|
286
|
-
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.
|
|
286
|
+
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. Conversely, if `$DONE` is an intermediate env yet Linear already natively completed the Issue (a magic-word / branch-linkage front-run — Linear auto-completes on merge to **any branch**, per the asymmetry documented in `git-submit-pr`), reconcile it back to active via `lisa-linear-sync` Phase 4b so the native state mirrors the non-terminal env instead of a premature closure.
|
|
287
287
|
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.
|
|
288
288
|
|
|
289
289
|
For any non-Success outcome, do NOT transition. The Issue sits where the lifecycle left it — humans take it from there.
|
|
@@ -92,6 +92,15 @@ Verify exactly one `status:*` label remains after the update — having two simu
|
|
|
92
92
|
|
|
93
93
|
Without `--update-label`, this skill posts the comment only and does NOT touch labels.
|
|
94
94
|
|
|
95
|
+
## Phase 4b — Reconcile Native Auto-Close (Linear-specific)
|
|
96
|
+
|
|
97
|
+
Linear's GitHub integration completes a linked Issue on merge to **any branch** — unlike GitHub's default-branch-scoped `Closes` auto-close — so a magic word (`Closes`/`Fixes`/`Resolves ENG-123`) or branch-name linkage can natively move the Issue to a Done/Completed workflow `state` at a **non-terminal** env merge, front-running the env-keyed `status:*` label ladder. `git-submit-pr` prevents the magic-word case; this phase is the required post-merge repair for the residual (branch-linkage) case we cannot suppress server-side. Run it on a `pr-merged` sync whose resolved env is **intermediate** (below the production terminal `done`):
|
|
98
|
+
|
|
99
|
+
1. Resolve the merged PR's base branch to its env via `.lisa.config.json` `deploy.branches` (`config-resolution`). If it maps to the production/terminal `done`, this phase is a **no-op** — native completion is correct there.
|
|
100
|
+
2. **Uniform / single-environment no-op.** When the project's env-keyed `done` map is uniform — every environment resolves to the same `status:done`, as in this repo (`production: main` only) and TunnlAI/frontend — dev-merge == terminal, so native completion is correct. Do nothing. Only a **non-uniform** env→`done` map (distinct `status:on-dev`/`status:on-stg`/`status:done` rungs) can desync.
|
|
101
|
+
3. Otherwise (non-uniform map, resolved env intermediate): re-read the Issue's native workflow `state`. If Linear natively moved it into a Done/Completed category while the derived `status:*` label is a lower env, **re-open** the native `state` back to the active/in-progress category (via `lisa-linear-access operation: save-issue`) so it mirrors the true env stage, and post a short `[lisa-linear-sync]` reconciliation comment. This applies the `leaf-only-lifecycle` "Terminal native closure" rule — native closure fires **only** at the production terminal `done` — as a *repair* of Linear front-running it. Cite the rule by slug; do not restate it.
|
|
102
|
+
4. **Safe default.** If the true terminal cannot be resolved (ambiguous env or unresolvable `done` map), do not change the native `state` — post a `[lisa-linear-sync]` reconciliation-suggestion comment and leave it untouched, mirroring the Phase 5 safe default.
|
|
103
|
+
|
|
95
104
|
## Phase 5 — Parent Status Rollup (`--rollup`)
|
|
96
105
|
|
|
97
106
|
When the caller passes `--rollup`, this skill **derives a parent/container's `status:*` label from the roll-up of its children** instead of acting on a leaf. A **Project** (the Epic equivalent) rolls up from its Issues; an **Issue** rolls up from its sub-Issues. This implements the Linear child-issue-status arm of the **Parent status rollup (the state machine)** section of the `leaf-only-lifecycle` rule — cite that rule, do not restate the policy.
|
|
@@ -38,7 +38,11 @@ close-out** roles and moves work *unstuck* or *fully closed*:
|
|
|
38
38
|
one missed by dependency-only re-checks: nothing else is blocking it, so re-running the same gate
|
|
39
39
|
against its current content is the only way to know it is now passable.
|
|
40
40
|
- **Terminal-open drift** — an item already carrying its true terminal lifecycle role (for
|
|
41
|
-
example GitHub `status:done`) but still open/active in the provider's native state.
|
|
41
|
+
example GitHub `status:done`) but still open/active in the provider's native state. The inverse
|
|
42
|
+
also drifts on Linear: a leaf whose native `state` was auto-completed by a magic-word / branch-linkage
|
|
43
|
+
merge into a **non-terminal** env (Linear completes on merge to any branch, unlike GitHub's
|
|
44
|
+
default-branch-scoped close) while its derived `status:*` label is still intermediate — reconcile
|
|
45
|
+
it back to active via `lisa-linear-sync` Phase 4b per `leaf-only-lifecycle`.
|
|
42
46
|
- **Rollup drift** — a parent/container item (Epic, Story, PRD, Linear Project, or equivalent)
|
|
43
47
|
whose own lifecycle state does not match the roll-up of its children's states per
|
|
44
48
|
`leaf-only-lifecycle`. This covers the *completed* case (all children terminal → close the parent
|