@codyswann/lisa 2.259.2 → 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.
Files changed (75) hide show
  1. package/package.json +1 -1
  2. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  3. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  4. package/plugins/lisa/.codex-plugin/skills/lisa-git-submit-pr/SKILL.md +3 -1
  5. package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +1 -1
  6. package/plugins/lisa/.codex-plugin/skills/lisa-linear-sync/SKILL.md +9 -0
  7. package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +5 -1
  8. package/plugins/lisa/skills/lisa-git-submit-pr/SKILL.md +3 -1
  9. package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +1 -1
  10. package/plugins/lisa/skills/lisa-linear-sync/SKILL.md +9 -0
  11. package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +5 -1
  12. package/plugins/lisa-agy/plugin.json +1 -1
  13. package/plugins/lisa-agy/skills/lisa-git-submit-pr/SKILL.md +3 -1
  14. package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +1 -1
  15. package/plugins/lisa-agy/skills/lisa-linear-sync/SKILL.md +9 -0
  16. package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +5 -1
  17. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  19. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  20. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-copilot/skills/lisa-git-submit-pr/SKILL.md +3 -1
  24. package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +1 -1
  25. package/plugins/lisa-copilot/skills/lisa-linear-sync/SKILL.md +9 -0
  26. package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +5 -1
  27. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-cursor/skills/lisa-git-submit-pr/SKILL.md +3 -1
  29. package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +1 -1
  30. package/plugins/lisa-cursor/skills/lisa-linear-sync/SKILL.md +9 -0
  31. package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +5 -1
  32. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  34. package/plugins/lisa-expo-agy/plugin.json +1 -1
  35. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  39. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  40. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  44. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  45. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  49. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  50. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  54. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  55. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  59. package/plugins/lisa-rails-agy/plugin.json +1 -1
  60. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  64. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  65. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  69. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  70. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  72. package/plugins/src/base/skills/lisa-git-submit-pr/SKILL.md +3 -1
  73. package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +1 -1
  74. package/plugins/src/base/skills/lisa-linear-sync/SKILL.md +9 -0
  75. 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.2",
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": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
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.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -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
@@ -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",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -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-cdk",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -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",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -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-expo",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.259.2",
3
+ "version": "2.259.3",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -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