@codyswann/lisa 2.60.0 → 2.60.1

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 (25) 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/rules/leaf-only-lifecycle.md +3 -3
  5. package/plugins/lisa/skills/github-build-intake/SKILL.md +18 -17
  6. package/plugins/lisa/skills/tracker-build-intake/SKILL.md +3 -3
  7. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  8. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  9. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  10. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  11. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  12. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  13. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  14. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  15. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  16. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  17. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  19. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  21. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  23. package/plugins/src/base/rules/leaf-only-lifecycle.md +3 -3
  24. package/plugins/src/base/skills/github-build-intake/SKILL.md +18 -17
  25. package/plugins/src/base/skills/tracker-build-intake/SKILL.md +3 -3
package/package.json CHANGED
@@ -82,7 +82,7 @@
82
82
  "lodash": ">=4.18.1"
83
83
  },
84
84
  "name": "@codyswann/lisa",
85
- "version": "2.60.0",
85
+ "version": "2.60.1",
86
86
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
87
87
  "main": "dist/index.js",
88
88
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.60.0",
3
+ "version": "2.60.1",
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.60.0",
3
+ "version": "2.60.1",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -10,7 +10,7 @@ The first two are the same idea seen from opposite ends: a parent never enters t
10
10
 
11
11
  ## Why this exists
12
12
 
13
- Build intake claims and implements whatever carries the build-ready role (the `ready` role — see `config-resolution`). A parent container (an Epic, a Story, a Linear Project, any issue with child work) is not a unit of implementation; it organizes work. If a parent is marked build-ready, an agent will try to implement the container itself — the wrong permission and lifecycle boundary. This surfaced in real PRD intake: a PRD decomposed into an Epic, Stories, and Sub-tasks, and *every* item received the build-ready label, so a subsequent build pass would have tried to "implement" the Epic.
13
+ Build intake processes whatever carries the build-ready role (the `ready` role — see `config-resolution`). A parent container (an Epic, a Story, a Linear Project, any issue with child work) is not a unit of implementation; it organizes work. If a parent is marked build-ready, an agent may try to implement the container itself unless intake gates it first — the wrong permission and lifecycle boundary. This surfaced in real PRD intake: a PRD decomposed into an Epic, Stories, and Sub-tasks, and *every* item received the build-ready label, so a subsequent build pass would have tried to "implement" the Epic.
14
14
 
15
15
  The fix is not vendor-specific. It belongs here, in a cross-vendor rule, and every writer / validator / intake path enforces it.
16
16
 
@@ -43,7 +43,7 @@ Where a vendor lacks native hierarchy for a given pair, a text link or metadata
43
43
 
44
44
  - **At decomposition / write time** — when a PRD decomposes into a hierarchy, only the leaf work units receive the `ready` role (status/label). Parent containers (Epic, Story, Project, and any parent issue that has child work) are created in their normal non-ready state and never receive the build-ready role directly. The leaves are what downstream build intake will claim.
45
45
  - **At validate time** — the `*-validate-*` gate FAILs any container carrying the build-ready role. This is the symmetric write-side guard: a stale or hand-applied build-ready role on a parent is a lifecycle error.
46
- - **At claim time** — build intake scans for the `ready` role but claims **only leaf work units**. A container that still carries a stale build-ready role (e.g. applied before this rule existed) is **not claimed**: intake either skips it or safely blocks it with a clear lifecycle-repair message (move the role to the leaves; roll the parent up). Intake never silently implements a container.
46
+ - **At claim time** — build intake scans for the `ready` role but dispatches **only leaf work units**. A container that still carries a stale build-ready role (e.g. applied before this rule existed) is **not dispatched**: intake either moves it into the vendor's parent/container progress state or safely blocks it with a clear lifecycle-repair message. Intake never silently implements a container.
47
47
 
48
48
  The permission boundary is the maintainer-applied build-ready role, not authorship — do not add author-based guards (PRD #522 non-goal). This rule narrows *what* may carry that role, not *who* may apply it.
49
49
 
@@ -108,7 +108,7 @@ Skills that enforce this invariant or perform rollup cite this rule by slug (the
108
108
 
109
109
  - **Decomposition / write** (`*-to-tracker`, `*-write-*`) — apply the `ready` role to leaves only; never to containers.
110
110
  - **Validate** (`*-validate-*`) — FAIL a container carrying the build-ready role; FAIL a childless Epic/Story/Spike marked build-ready.
111
- - **Build intake** (`*-build-intake`, `tracker-build-intake`) — claim leaves only; skip or safe-block containers with stale build-ready roles.
111
+ - **Build intake** (`*-build-intake`, `tracker-build-intake`) — dispatch leaves only; move or safe-block containers with stale build-ready roles according to vendor lifecycle semantics.
112
112
  - **Rollup** — derive parent state from children per the state machine above.
113
113
  - **Terminal native closure** (`*-build-intake`, terminal helpers) — after a leaf reaches the true terminal `done` role, finalize it through the provider's native close / complete / resolve mechanism where available; never do this for intermediate env states.
114
114
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: github-build-intake
3
- description: "GitHub counterpart to lisa:jira-build-intake. Scans a GitHub repository for issues carrying the configured `ready` build label, claims each leaf work unit by relabeling to the configured `claimed` label, runs the implementation/build flow via lisa:github-agent, and relabels to the configured `done` label on completion. Enforces the claim-time arm of the `leaf-only-lifecycle` rule: a parent/container with open child work (or a childless Epic/Story/Spike) that still carries a stale build-ready label is skipped or safe-blocked with a lifecycle-repair comment, never claimed. The `ready` label is the human-flipped signal that an issue is truly ready for development — mirroring how Notion PRDs work product Draft → Ready → (us) In Review → Blocked|Ticketed."
3
+ description: "GitHub counterpart to lisa:jira-build-intake. Scans a GitHub repository for issues carrying the configured `ready` build label, claims each leaf work unit by relabeling to the configured `claimed` label, runs the implementation/build flow via lisa:github-agent, and relabels to the configured `done` label on completion. Enforces the claim-time arm of the `leaf-only-lifecycle` rule: a parent/container with open child work (or a childless Epic/Story/Spike) that still carries a stale build-ready label is moved out of the ready pickup queue into the configured `claimed` label with a lifecycle-repair comment, never dispatched to lisa:github-agent. The `ready` label is the human-flipped signal that an issue is truly ready for direct development pickup — mirroring how Notion PRDs work product Draft → Ready → (us) In Review → Blocked|Ticketed."
4
4
  allowed-tools: ["Skill", "Bash"]
5
5
  ---
6
6
 
@@ -135,11 +135,11 @@ If none of the configured role labels exist on the repo → label convention not
135
135
 
136
136
  ### Phase 3 — Process each ready issue (serial)
137
137
 
138
- #### 3a. Leaf-only claim gate (skip / safe-block containers)
138
+ #### 3a. Leaf-only claim gate (repair containers)
139
139
 
140
- Build intake claims **only independently implementable leaf work units**. This enforces the claim-time arm of the vendor-neutral `leaf-only-lifecycle` rule: a parent/container that still carries a stale build-ready role (e.g. `status:ready` applied before this rule existed, or hand-applied to an Epic/Story) is **never claimed** — intake skips it or safe-blocks it with a clear lifecycle-repair message. It is the claim-time complement to the write-time labeling in `lisa:github-write-issue` and the validate-time S15 gate in `lisa:github-validate-issue`; all three cite the same rule so the classification never drifts. **Never silently implement a container.**
140
+ Build intake dispatches **only independently implementable leaf work units** to the build agent. This enforces the claim-time arm of the vendor-neutral `leaf-only-lifecycle` rule: a parent/container that still carries a stale build-ready role (e.g. `status:ready` applied before this rule existed, or hand-applied to an Epic/Story) is **never dispatched** — intake moves it out of the pickup queue by replacing `$READY` with `$CLAIMED`, then posts a clear lifecycle-repair message. It is the claim-time complement to the write-time labeling in `lisa:github-write-issue` and the validate-time S15 gate in `lisa:github-validate-issue`; all three cite the same rule so the classification never drifts. **Never silently implement a container.**
141
141
 
142
- Run this gate **before** the claim relabel, for every candidate issue. Do NOT relabel, comment "Claimed", or invoke `lisa:github-agent` for an issue that fails the gate.
142
+ Run this gate **before** the leaf claim relabel, for every candidate issue. Do NOT comment "Claimed" or invoke `lisa:github-agent` for an issue that fails the gate. A container repair still changes labels: remove `$READY`, add `$CLAIMED`, and explain that parent/container `$CLAIMED` means rollup/build-lane progress through child/leaf work, not direct implementation.
143
143
 
144
144
  **Resolve container vs. leaf — structural first, then nominal.** Per `leaf-only-lifecycle` the classification is structural: an issue is a **container** if it has **open** child work, whatever its declared type; otherwise the **type label** decides. Resolve child work using the same hierarchy `lisa:github-read-issue` uses — native sub-issues first, then body parentage (task-list checkboxes referencing other issues, `Parent: #<n>` references). Dependency links such as `Blocked by:` are not parentage; they are handled by the active dependency hold gate below.
145
145
 
@@ -168,16 +168,17 @@ Classify and act (first match wins). `type:` is read from the issue's labels (`t
168
168
 
169
169
  | Condition | Class | Action |
170
170
  |---|---|---|
171
- | `OPEN_CHILDREN > 0` (open child work, any type) | **Container** | **Skip / safe-block — do NOT claim** |
172
- | no open children AND `type ∈ {Epic, Story, Spike}` | **Childless container-type** | **Skip / safe-block — do NOT claim** |
171
+ | `OPEN_CHILDREN > 0` (open child work, any type) | **Container** | **Move to `$CLAIMED` as lifecycle repair — do NOT dispatch** |
172
+ | no open children AND `type ∈ {Epic, Story, Spike}` | **Childless container-type** | **Move to `$CLAIMED` as lifecycle repair — do NOT dispatch** |
173
173
  | no open children AND `type ∈ {Bug, Task, Sub-task, Improvement}` (or no `type:` label) | **Leaf work unit** | **Proceed to 3b claim** |
174
174
 
175
- The childless-parent exception is narrow: childlessness enables a claim **only** for types that are leaf work units to begin with. A childless Epic/Story/Spike is an incomplete decomposition, not an implementable unit — it is never claimed.
175
+ The childless-parent exception is narrow: childlessness enables direct build-agent dispatch **only** for types that are leaf work units to begin with. A childless Epic/Story/Spike is an incomplete decomposition, not an implementable unit — it is moved out of the ready pickup queue for repair/rollup and never dispatched.
176
176
 
177
- **Safe-block (default action for a flagged container).** Leave the build-ready role in place (don't silently strip it that hides the lifecycle error), post a single lifecycle-repair comment, and record the issue under "Skipped (container)" in the summary. Do NOT relabel to `$CLAIMED`. Keep the comment idempotent — skip posting if an identical `[claude-build-intake]` lifecycle-repair comment already exists on the issue, so a re-entrant cycle doesn't spam it.
177
+ **Lifecycle repair (default action for a flagged container).** Move the issue out of the pickup queue by removing `$READY` and adding `$CLAIMED`, post a single lifecycle-repair comment, and record the issue under "Repaired (container)" in the summary. Do NOT invoke `lisa:github-agent`. Keep the comment idempotent — skip posting if an identical `[claude-build-intake]` lifecycle-repair comment already exists on the issue, so a re-entrant cycle doesn't spam it.
178
178
 
179
179
  ```bash
180
- gh issue comment <number> --repo <org>/<repo> --body "[claude-build-intake] Not claimed: this issue carries the build-ready role ($READY) but is a container with open child work (or a childless Epic/Story/Spike), which violates the leaf-only-lifecycle rule. Build-ready is leaf-only — an agent claims and implements leaves, never a container. Repair: move $READY off this parent onto its leaf children (or, for a childless Epic/Story/Spike, decompose it into leaf children or reclassify it to a leaf type). A parent's lifecycle state rolls up from its children and is never set to ready directly."
180
+ gh issue edit <number> --repo <org>/<repo> --remove-label "$READY" --add-label "$CLAIMED"
181
+ gh issue comment <number> --repo <org>/<repo> --body "[claude-build-intake] Lifecycle repair: this issue carried the build-ready role ($READY) but is a parent/container with open child work (or a childless Epic/Story/Spike). I moved it to $CLAIMED without invoking the build agent. For parent/container issues, $CLAIMED means rollup/build-lane progress through child/leaf work; direct implementation must happen on leaf issues. Build-ready is leaf-only per leaf-only-lifecycle — move $READY onto its leaf children, or decompose/reclassify a childless Epic/Story/Spike."
181
182
  ```
182
183
 
183
184
  This gate never blocks a legitimate flat Task/Bug: those have no open children and a leaf `type:`, so they fall straight through to the claim in 3b.
@@ -269,8 +270,8 @@ Cycle completed: <ISO timestamp>
269
270
  Issues processed: <n>
270
271
  - $DONE (build complete, PR ready): <n>
271
272
  - <org>/<repo>#<number> <title> → PR <URL>
272
- - Skipped (container — leaf-only-lifecycle): <n>
273
- - <org>/<repo>#<number> <title> — build-ready on a parent with open child work; lifecycle-repair comment posted
273
+ - Repaired (container — leaf-only-lifecycle): <n>
274
+ - <org>/<repo>#<number> <title> — build-ready on a parent/container; moved $READY $CLAIMED without invoking lisa:github-agent; lifecycle-repair comment posted
274
275
  - Skipped (active blockers): <n>
275
276
  - <org>/<repo>#<number> <title> — waiting on <blocker refs>
276
277
  - Blocked (pre-flight verify failed): <n>
@@ -285,10 +286,10 @@ Total PRs opened: <n>
285
286
 
286
287
  ## Idempotency & safety
287
288
 
288
- - **Leaf-only claim gate runs first**: Phase 3a classifies each candidate before any claim; a container with open child work (or a childless Epic/Story/Spike) is skipped/safe-blocked, never claimed. The safe-block comment is idempotent — a re-entrant cycle does not re-post it.
289
- - **Dependency hold runs before claim**: explicit `Blocked by:` relationships are resolved before `$READY → $CLAIMED`; active blockers leave the candidate in `$READY` and are reported as skipped, not blocked.
290
- - **Claim-first ordering**: `$CLAIMED` set BEFORE `lisa:github-agent` invocation no double-pickup.
291
- - **No writes outside the lifecycle**: this skill only relabels `$READY → $CLAIMED` and `$CLAIMED → $DONE`. Every other label change is owned by `lisa:github-agent`.
289
+ - **Leaf-only claim gate runs first**: Phase 3a classifies each candidate before any leaf claim; a container with open child work (or a childless Epic/Story/Spike) is moved `$READY` → `$CLAIMED` as lifecycle repair and never dispatched. The lifecycle-repair comment is idempotent — a re-entrant cycle does not re-post it.
290
+ - **Dependency hold runs before leaf claim**: explicit `Blocked by:` relationships are resolved after container repair is ruled out but before `$READY → $CLAIMED`; active blockers leave the leaf candidate in `$READY` and are reported as skipped, not blocked.
291
+ - **Claim-first ordering**: `$CLAIMED` set BEFORE `lisa:github-agent` invocation for leaves; containers are also moved to `$CLAIMED` to leave the ready pickup queue, but are not dispatched.
292
+ - **No writes outside the lifecycle**: this skill only relabels `$READY → $CLAIMED` and `$CLAIMED → $DONE`. For containers, `$READY → $CLAIMED` is a lifecycle repair, not a direct build claim. Every other label change is owned by `lisa:github-agent`.
292
293
  - **Terminal native closure**: after `$CLAIMED → $DONE`, close the GitHub issue only when `$DONE` is the true terminal done value per `leaf-only-lifecycle`; intermediate env labels stay open.
293
294
  - **Failure isolation**: per-issue exceptions caught and recorded; the cycle continues.
294
295
  - **Single cycle per repo**: do not run two `lisa:github-build-intake` cycles in parallel against the same repo — concurrent claims could race. The scheduling layer is responsible for serialization.
@@ -311,8 +312,8 @@ If the repo has not adopted the `status:*` label namespace, this skill cannot ru
311
312
 
312
313
  ## Rules
313
314
 
314
- - **Claim leaves only.** Per the `leaf-only-lifecycle` rule, never claim a container — an issue with open child work, or a childless Epic/Story/Spike — even if it carries the build-ready role. Skip or safe-block it (Phase 3a); never silently implement a container.
315
- - Never relabel an issue the cycle didn't claim. The `$CLAIMED` label is the signature of cycle ownership.
315
+ - **Dispatch leaves only.** Per the `leaf-only-lifecycle` rule, never dispatch a container — an issue with open child work, or a childless Epic/Story/Spike — even if it carries the build-ready role. Move it `$READY $CLAIMED` as lifecycle repair (Phase 3a); never silently implement a container.
316
+ - Never relabel an issue outside the cycle's allowed transitions. The `$CLAIMED` label is the signature of cycle ownership for leaves, and the parent/container progress state for lifecycle repairs.
316
317
  - Never bypass `lisa:github-agent` to do build work directly. `lisa:github-agent` owns the per-issue lifecycle.
317
318
  - Never auto-transition past `$DONE`. Downstream labels (terminal `status:done`, etc.) are owned by QA / PM / merge automation.
318
319
  - Never close a GitHub issue at intermediate env states (`status:on-dev`, `status:on-stg`, or configured equivalents). Native close happens only at the terminal `done` value.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: tracker-build-intake
3
- description: "Vendor-neutral wrapper for the build-queue batch scanner. Reads `tracker` from .lisa.config.json (default: jira) and dispatches to lisa:jira-build-intake (JQL/project-key queue), lisa:github-build-intake (GitHub repo queue keyed off the `status:ready` label), or lisa:linear-build-intake (Linear team queue keyed off the `status:ready` label). Every vendor scanner enforces the claim-time arm of the `leaf-only-lifecycle` rule — claim leaf work units only; skip or safe-block a container with open child work (or a childless Epic/Story/Spike) that carries a stale build-ready role. Counterpart to lisa:intake's PRD-side dispatchers."
3
+ description: "Vendor-neutral wrapper for the build-queue batch scanner. Reads `tracker` from .lisa.config.json (default: jira) and dispatches to lisa:jira-build-intake (JQL/project-key queue), lisa:github-build-intake (GitHub repo queue keyed off the `status:ready` label), or lisa:linear-build-intake (Linear team queue keyed off the `status:ready` label). Every vendor scanner enforces the claim-time arm of the `leaf-only-lifecycle` rule — dispatch leaf work units only; move or safe-block a container with open child work (or a childless Epic/Story/Spike) that carries a stale build-ready role according to the vendor's lifecycle semantics. Counterpart to lisa:intake's PRD-side dispatchers."
4
4
  allowed-tools: ["Skill", "Bash", "Read"]
5
5
  ---
6
6
 
@@ -27,7 +27,7 @@ The vendor scanners also own the terminal native-closure step from `leaf-only-li
27
27
  This shim is dispatch only — it does not reclassify or re-gate items — but the contract it forwards is part of the build-intake API, so it is documented here once and the three vendor scanners implement it identically. Per the vendor-neutral `leaf-only-lifecycle` rule, **build intake claims only independently implementable leaf work units**:
28
28
 
29
29
  - A **leaf work unit** (Bug, Task, Sub-task, Improvement with no open child work) is claimed and built.
30
- - A **container** — anything with open child work, or a childless Epic/Story/Spike — that still carries a stale build-ready role is **never claimed**. The vendor scanner skips it or safe-blocks it with an idempotent lifecycle-repair comment (move the build-ready role off the parent onto its leaf children; a parent's state rolls up from its children and is never set to ready directly).
30
+ - A **container** — anything with open child work, or a childless Epic/Story/Spike — that still carries a stale build-ready role is **never dispatched**. The GitHub scanner moves it out of the pickup queue by replacing `status:ready` with `status:in-progress` and posting an idempotent lifecycle-repair comment; other vendor scanners skip or safe-block according to their native lifecycle semantics.
31
31
 
32
32
  This is the claim-time arm of the rule. Its siblings are the write-time labeling (`lisa:tracker-write` → the vendor `*-write-*` skills apply build-ready to leaves only) and the validate-time S15 gate (`lisa:tracker-validate` → the vendor `*-validate-*` skills FAIL a build-ready container). All three arms cite `leaf-only-lifecycle` so no vendor drifts. Each vendor scanner implements the gate against its own hierarchy:
33
33
 
@@ -55,6 +55,6 @@ Intermediate env states are not native closure. A vendor scanner that resolves `
55
55
 
56
56
  - Single cycle per invocation — the vendor skill processes the current `Ready` set and exits.
57
57
  - The vendor skills run their own pre-flight checks (JIRA workflow transitions for the JIRA path; label namespace adoption for the GitHub and Linear paths) before processing items. Never bypass.
58
- - **Leaf-only claim, every vendor.** Per the `leaf-only-lifecycle` rule, each vendor scanner claims leaf work units only and skips / safe-blocks a container (open child work, or a childless Epic/Story/Spike) carrying a stale build-ready role. This shim does not re-implement the gate — it relies on the vendor scanner's Phase 3a — but the contract is uniform across `jira`, `github`, and `linear` so behavior never drifts by tracker.
58
+ - **Leaf-only dispatch, every vendor.** Per the `leaf-only-lifecycle` rule, each vendor scanner dispatches leaf work units only and moves or safe-blocks a container (open child work, or a childless Epic/Story/Spike) carrying a stale build-ready role according to its lifecycle semantics. This shim does not re-implement the gate — it relies on the vendor scanner's Phase 3a — but the contract is uniform across `jira`, `github`, and `linear` so behavior never drifts by tracker.
59
59
  - **Terminal native closure, every capable vendor.** Per the same rule, each vendor scanner finalizes native open/closed state only at the true terminal `done` value. This shim never performs native closure itself, but callers can rely on the dispatched vendor scanner to apply the contract.
60
60
  - Never run two intake cycles concurrently against overlapping queues — the scheduling layer is responsible for serialization.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.60.0",
3
+ "version": "2.60.1",
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.60.0",
3
+ "version": "2.60.1",
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-expo",
3
- "version": "2.60.0",
3
+ "version": "2.60.1",
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.60.0",
3
+ "version": "2.60.1",
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-harper-fabric",
3
- "version": "2.60.0",
3
+ "version": "2.60.1",
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.60.0",
3
+ "version": "2.60.1",
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-nestjs",
3
- "version": "2.60.0",
3
+ "version": "2.60.1",
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.60.0",
3
+ "version": "2.60.1",
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-openclaw",
3
- "version": "2.60.0",
3
+ "version": "2.60.1",
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.60.0",
3
+ "version": "2.60.1",
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-rails",
3
- "version": "2.60.0",
3
+ "version": "2.60.1",
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.60.0",
3
+ "version": "2.60.1",
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-typescript",
3
- "version": "2.60.0",
3
+ "version": "2.60.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint 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.60.0",
3
+ "version": "2.60.1",
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-wiki",
3
- "version": "2.60.0",
3
+ "version": "2.60.1",
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.60.0",
3
+ "version": "2.60.1",
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"
@@ -10,7 +10,7 @@ The first two are the same idea seen from opposite ends: a parent never enters t
10
10
 
11
11
  ## Why this exists
12
12
 
13
- Build intake claims and implements whatever carries the build-ready role (the `ready` role — see `config-resolution`). A parent container (an Epic, a Story, a Linear Project, any issue with child work) is not a unit of implementation; it organizes work. If a parent is marked build-ready, an agent will try to implement the container itself — the wrong permission and lifecycle boundary. This surfaced in real PRD intake: a PRD decomposed into an Epic, Stories, and Sub-tasks, and *every* item received the build-ready label, so a subsequent build pass would have tried to "implement" the Epic.
13
+ Build intake processes whatever carries the build-ready role (the `ready` role — see `config-resolution`). A parent container (an Epic, a Story, a Linear Project, any issue with child work) is not a unit of implementation; it organizes work. If a parent is marked build-ready, an agent may try to implement the container itself unless intake gates it first — the wrong permission and lifecycle boundary. This surfaced in real PRD intake: a PRD decomposed into an Epic, Stories, and Sub-tasks, and *every* item received the build-ready label, so a subsequent build pass would have tried to "implement" the Epic.
14
14
 
15
15
  The fix is not vendor-specific. It belongs here, in a cross-vendor rule, and every writer / validator / intake path enforces it.
16
16
 
@@ -43,7 +43,7 @@ Where a vendor lacks native hierarchy for a given pair, a text link or metadata
43
43
 
44
44
  - **At decomposition / write time** — when a PRD decomposes into a hierarchy, only the leaf work units receive the `ready` role (status/label). Parent containers (Epic, Story, Project, and any parent issue that has child work) are created in their normal non-ready state and never receive the build-ready role directly. The leaves are what downstream build intake will claim.
45
45
  - **At validate time** — the `*-validate-*` gate FAILs any container carrying the build-ready role. This is the symmetric write-side guard: a stale or hand-applied build-ready role on a parent is a lifecycle error.
46
- - **At claim time** — build intake scans for the `ready` role but claims **only leaf work units**. A container that still carries a stale build-ready role (e.g. applied before this rule existed) is **not claimed**: intake either skips it or safely blocks it with a clear lifecycle-repair message (move the role to the leaves; roll the parent up). Intake never silently implements a container.
46
+ - **At claim time** — build intake scans for the `ready` role but dispatches **only leaf work units**. A container that still carries a stale build-ready role (e.g. applied before this rule existed) is **not dispatched**: intake either moves it into the vendor's parent/container progress state or safely blocks it with a clear lifecycle-repair message. Intake never silently implements a container.
47
47
 
48
48
  The permission boundary is the maintainer-applied build-ready role, not authorship — do not add author-based guards (PRD #522 non-goal). This rule narrows *what* may carry that role, not *who* may apply it.
49
49
 
@@ -108,7 +108,7 @@ Skills that enforce this invariant or perform rollup cite this rule by slug (the
108
108
 
109
109
  - **Decomposition / write** (`*-to-tracker`, `*-write-*`) — apply the `ready` role to leaves only; never to containers.
110
110
  - **Validate** (`*-validate-*`) — FAIL a container carrying the build-ready role; FAIL a childless Epic/Story/Spike marked build-ready.
111
- - **Build intake** (`*-build-intake`, `tracker-build-intake`) — claim leaves only; skip or safe-block containers with stale build-ready roles.
111
+ - **Build intake** (`*-build-intake`, `tracker-build-intake`) — dispatch leaves only; move or safe-block containers with stale build-ready roles according to vendor lifecycle semantics.
112
112
  - **Rollup** — derive parent state from children per the state machine above.
113
113
  - **Terminal native closure** (`*-build-intake`, terminal helpers) — after a leaf reaches the true terminal `done` role, finalize it through the provider's native close / complete / resolve mechanism where available; never do this for intermediate env states.
114
114
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: github-build-intake
3
- description: "GitHub counterpart to lisa:jira-build-intake. Scans a GitHub repository for issues carrying the configured `ready` build label, claims each leaf work unit by relabeling to the configured `claimed` label, runs the implementation/build flow via lisa:github-agent, and relabels to the configured `done` label on completion. Enforces the claim-time arm of the `leaf-only-lifecycle` rule: a parent/container with open child work (or a childless Epic/Story/Spike) that still carries a stale build-ready label is skipped or safe-blocked with a lifecycle-repair comment, never claimed. The `ready` label is the human-flipped signal that an issue is truly ready for development — mirroring how Notion PRDs work product Draft → Ready → (us) In Review → Blocked|Ticketed."
3
+ description: "GitHub counterpart to lisa:jira-build-intake. Scans a GitHub repository for issues carrying the configured `ready` build label, claims each leaf work unit by relabeling to the configured `claimed` label, runs the implementation/build flow via lisa:github-agent, and relabels to the configured `done` label on completion. Enforces the claim-time arm of the `leaf-only-lifecycle` rule: a parent/container with open child work (or a childless Epic/Story/Spike) that still carries a stale build-ready label is moved out of the ready pickup queue into the configured `claimed` label with a lifecycle-repair comment, never dispatched to lisa:github-agent. The `ready` label is the human-flipped signal that an issue is truly ready for direct development pickup — mirroring how Notion PRDs work product Draft → Ready → (us) In Review → Blocked|Ticketed."
4
4
  allowed-tools: ["Skill", "Bash"]
5
5
  ---
6
6
 
@@ -135,11 +135,11 @@ If none of the configured role labels exist on the repo → label convention not
135
135
 
136
136
  ### Phase 3 — Process each ready issue (serial)
137
137
 
138
- #### 3a. Leaf-only claim gate (skip / safe-block containers)
138
+ #### 3a. Leaf-only claim gate (repair containers)
139
139
 
140
- Build intake claims **only independently implementable leaf work units**. This enforces the claim-time arm of the vendor-neutral `leaf-only-lifecycle` rule: a parent/container that still carries a stale build-ready role (e.g. `status:ready` applied before this rule existed, or hand-applied to an Epic/Story) is **never claimed** — intake skips it or safe-blocks it with a clear lifecycle-repair message. It is the claim-time complement to the write-time labeling in `lisa:github-write-issue` and the validate-time S15 gate in `lisa:github-validate-issue`; all three cite the same rule so the classification never drifts. **Never silently implement a container.**
140
+ Build intake dispatches **only independently implementable leaf work units** to the build agent. This enforces the claim-time arm of the vendor-neutral `leaf-only-lifecycle` rule: a parent/container that still carries a stale build-ready role (e.g. `status:ready` applied before this rule existed, or hand-applied to an Epic/Story) is **never dispatched** — intake moves it out of the pickup queue by replacing `$READY` with `$CLAIMED`, then posts a clear lifecycle-repair message. It is the claim-time complement to the write-time labeling in `lisa:github-write-issue` and the validate-time S15 gate in `lisa:github-validate-issue`; all three cite the same rule so the classification never drifts. **Never silently implement a container.**
141
141
 
142
- Run this gate **before** the claim relabel, for every candidate issue. Do NOT relabel, comment "Claimed", or invoke `lisa:github-agent` for an issue that fails the gate.
142
+ Run this gate **before** the leaf claim relabel, for every candidate issue. Do NOT comment "Claimed" or invoke `lisa:github-agent` for an issue that fails the gate. A container repair still changes labels: remove `$READY`, add `$CLAIMED`, and explain that parent/container `$CLAIMED` means rollup/build-lane progress through child/leaf work, not direct implementation.
143
143
 
144
144
  **Resolve container vs. leaf — structural first, then nominal.** Per `leaf-only-lifecycle` the classification is structural: an issue is a **container** if it has **open** child work, whatever its declared type; otherwise the **type label** decides. Resolve child work using the same hierarchy `lisa:github-read-issue` uses — native sub-issues first, then body parentage (task-list checkboxes referencing other issues, `Parent: #<n>` references). Dependency links such as `Blocked by:` are not parentage; they are handled by the active dependency hold gate below.
145
145
 
@@ -168,16 +168,17 @@ Classify and act (first match wins). `type:` is read from the issue's labels (`t
168
168
 
169
169
  | Condition | Class | Action |
170
170
  |---|---|---|
171
- | `OPEN_CHILDREN > 0` (open child work, any type) | **Container** | **Skip / safe-block — do NOT claim** |
172
- | no open children AND `type ∈ {Epic, Story, Spike}` | **Childless container-type** | **Skip / safe-block — do NOT claim** |
171
+ | `OPEN_CHILDREN > 0` (open child work, any type) | **Container** | **Move to `$CLAIMED` as lifecycle repair — do NOT dispatch** |
172
+ | no open children AND `type ∈ {Epic, Story, Spike}` | **Childless container-type** | **Move to `$CLAIMED` as lifecycle repair — do NOT dispatch** |
173
173
  | no open children AND `type ∈ {Bug, Task, Sub-task, Improvement}` (or no `type:` label) | **Leaf work unit** | **Proceed to 3b claim** |
174
174
 
175
- The childless-parent exception is narrow: childlessness enables a claim **only** for types that are leaf work units to begin with. A childless Epic/Story/Spike is an incomplete decomposition, not an implementable unit — it is never claimed.
175
+ The childless-parent exception is narrow: childlessness enables direct build-agent dispatch **only** for types that are leaf work units to begin with. A childless Epic/Story/Spike is an incomplete decomposition, not an implementable unit — it is moved out of the ready pickup queue for repair/rollup and never dispatched.
176
176
 
177
- **Safe-block (default action for a flagged container).** Leave the build-ready role in place (don't silently strip it that hides the lifecycle error), post a single lifecycle-repair comment, and record the issue under "Skipped (container)" in the summary. Do NOT relabel to `$CLAIMED`. Keep the comment idempotent — skip posting if an identical `[claude-build-intake]` lifecycle-repair comment already exists on the issue, so a re-entrant cycle doesn't spam it.
177
+ **Lifecycle repair (default action for a flagged container).** Move the issue out of the pickup queue by removing `$READY` and adding `$CLAIMED`, post a single lifecycle-repair comment, and record the issue under "Repaired (container)" in the summary. Do NOT invoke `lisa:github-agent`. Keep the comment idempotent — skip posting if an identical `[claude-build-intake]` lifecycle-repair comment already exists on the issue, so a re-entrant cycle doesn't spam it.
178
178
 
179
179
  ```bash
180
- gh issue comment <number> --repo <org>/<repo> --body "[claude-build-intake] Not claimed: this issue carries the build-ready role ($READY) but is a container with open child work (or a childless Epic/Story/Spike), which violates the leaf-only-lifecycle rule. Build-ready is leaf-only — an agent claims and implements leaves, never a container. Repair: move $READY off this parent onto its leaf children (or, for a childless Epic/Story/Spike, decompose it into leaf children or reclassify it to a leaf type). A parent's lifecycle state rolls up from its children and is never set to ready directly."
180
+ gh issue edit <number> --repo <org>/<repo> --remove-label "$READY" --add-label "$CLAIMED"
181
+ gh issue comment <number> --repo <org>/<repo> --body "[claude-build-intake] Lifecycle repair: this issue carried the build-ready role ($READY) but is a parent/container with open child work (or a childless Epic/Story/Spike). I moved it to $CLAIMED without invoking the build agent. For parent/container issues, $CLAIMED means rollup/build-lane progress through child/leaf work; direct implementation must happen on leaf issues. Build-ready is leaf-only per leaf-only-lifecycle — move $READY onto its leaf children, or decompose/reclassify a childless Epic/Story/Spike."
181
182
  ```
182
183
 
183
184
  This gate never blocks a legitimate flat Task/Bug: those have no open children and a leaf `type:`, so they fall straight through to the claim in 3b.
@@ -269,8 +270,8 @@ Cycle completed: <ISO timestamp>
269
270
  Issues processed: <n>
270
271
  - $DONE (build complete, PR ready): <n>
271
272
  - <org>/<repo>#<number> <title> → PR <URL>
272
- - Skipped (container — leaf-only-lifecycle): <n>
273
- - <org>/<repo>#<number> <title> — build-ready on a parent with open child work; lifecycle-repair comment posted
273
+ - Repaired (container — leaf-only-lifecycle): <n>
274
+ - <org>/<repo>#<number> <title> — build-ready on a parent/container; moved $READY $CLAIMED without invoking lisa:github-agent; lifecycle-repair comment posted
274
275
  - Skipped (active blockers): <n>
275
276
  - <org>/<repo>#<number> <title> — waiting on <blocker refs>
276
277
  - Blocked (pre-flight verify failed): <n>
@@ -285,10 +286,10 @@ Total PRs opened: <n>
285
286
 
286
287
  ## Idempotency & safety
287
288
 
288
- - **Leaf-only claim gate runs first**: Phase 3a classifies each candidate before any claim; a container with open child work (or a childless Epic/Story/Spike) is skipped/safe-blocked, never claimed. The safe-block comment is idempotent — a re-entrant cycle does not re-post it.
289
- - **Dependency hold runs before claim**: explicit `Blocked by:` relationships are resolved before `$READY → $CLAIMED`; active blockers leave the candidate in `$READY` and are reported as skipped, not blocked.
290
- - **Claim-first ordering**: `$CLAIMED` set BEFORE `lisa:github-agent` invocation no double-pickup.
291
- - **No writes outside the lifecycle**: this skill only relabels `$READY → $CLAIMED` and `$CLAIMED → $DONE`. Every other label change is owned by `lisa:github-agent`.
289
+ - **Leaf-only claim gate runs first**: Phase 3a classifies each candidate before any leaf claim; a container with open child work (or a childless Epic/Story/Spike) is moved `$READY` → `$CLAIMED` as lifecycle repair and never dispatched. The lifecycle-repair comment is idempotent — a re-entrant cycle does not re-post it.
290
+ - **Dependency hold runs before leaf claim**: explicit `Blocked by:` relationships are resolved after container repair is ruled out but before `$READY → $CLAIMED`; active blockers leave the leaf candidate in `$READY` and are reported as skipped, not blocked.
291
+ - **Claim-first ordering**: `$CLAIMED` set BEFORE `lisa:github-agent` invocation for leaves; containers are also moved to `$CLAIMED` to leave the ready pickup queue, but are not dispatched.
292
+ - **No writes outside the lifecycle**: this skill only relabels `$READY → $CLAIMED` and `$CLAIMED → $DONE`. For containers, `$READY → $CLAIMED` is a lifecycle repair, not a direct build claim. Every other label change is owned by `lisa:github-agent`.
292
293
  - **Terminal native closure**: after `$CLAIMED → $DONE`, close the GitHub issue only when `$DONE` is the true terminal done value per `leaf-only-lifecycle`; intermediate env labels stay open.
293
294
  - **Failure isolation**: per-issue exceptions caught and recorded; the cycle continues.
294
295
  - **Single cycle per repo**: do not run two `lisa:github-build-intake` cycles in parallel against the same repo — concurrent claims could race. The scheduling layer is responsible for serialization.
@@ -311,8 +312,8 @@ If the repo has not adopted the `status:*` label namespace, this skill cannot ru
311
312
 
312
313
  ## Rules
313
314
 
314
- - **Claim leaves only.** Per the `leaf-only-lifecycle` rule, never claim a container — an issue with open child work, or a childless Epic/Story/Spike — even if it carries the build-ready role. Skip or safe-block it (Phase 3a); never silently implement a container.
315
- - Never relabel an issue the cycle didn't claim. The `$CLAIMED` label is the signature of cycle ownership.
315
+ - **Dispatch leaves only.** Per the `leaf-only-lifecycle` rule, never dispatch a container — an issue with open child work, or a childless Epic/Story/Spike — even if it carries the build-ready role. Move it `$READY $CLAIMED` as lifecycle repair (Phase 3a); never silently implement a container.
316
+ - Never relabel an issue outside the cycle's allowed transitions. The `$CLAIMED` label is the signature of cycle ownership for leaves, and the parent/container progress state for lifecycle repairs.
316
317
  - Never bypass `lisa:github-agent` to do build work directly. `lisa:github-agent` owns the per-issue lifecycle.
317
318
  - Never auto-transition past `$DONE`. Downstream labels (terminal `status:done`, etc.) are owned by QA / PM / merge automation.
318
319
  - Never close a GitHub issue at intermediate env states (`status:on-dev`, `status:on-stg`, or configured equivalents). Native close happens only at the terminal `done` value.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: tracker-build-intake
3
- description: "Vendor-neutral wrapper for the build-queue batch scanner. Reads `tracker` from .lisa.config.json (default: jira) and dispatches to lisa:jira-build-intake (JQL/project-key queue), lisa:github-build-intake (GitHub repo queue keyed off the `status:ready` label), or lisa:linear-build-intake (Linear team queue keyed off the `status:ready` label). Every vendor scanner enforces the claim-time arm of the `leaf-only-lifecycle` rule — claim leaf work units only; skip or safe-block a container with open child work (or a childless Epic/Story/Spike) that carries a stale build-ready role. Counterpart to lisa:intake's PRD-side dispatchers."
3
+ description: "Vendor-neutral wrapper for the build-queue batch scanner. Reads `tracker` from .lisa.config.json (default: jira) and dispatches to lisa:jira-build-intake (JQL/project-key queue), lisa:github-build-intake (GitHub repo queue keyed off the `status:ready` label), or lisa:linear-build-intake (Linear team queue keyed off the `status:ready` label). Every vendor scanner enforces the claim-time arm of the `leaf-only-lifecycle` rule — dispatch leaf work units only; move or safe-block a container with open child work (or a childless Epic/Story/Spike) that carries a stale build-ready role according to the vendor's lifecycle semantics. Counterpart to lisa:intake's PRD-side dispatchers."
4
4
  allowed-tools: ["Skill", "Bash", "Read"]
5
5
  ---
6
6
 
@@ -27,7 +27,7 @@ The vendor scanners also own the terminal native-closure step from `leaf-only-li
27
27
  This shim is dispatch only — it does not reclassify or re-gate items — but the contract it forwards is part of the build-intake API, so it is documented here once and the three vendor scanners implement it identically. Per the vendor-neutral `leaf-only-lifecycle` rule, **build intake claims only independently implementable leaf work units**:
28
28
 
29
29
  - A **leaf work unit** (Bug, Task, Sub-task, Improvement with no open child work) is claimed and built.
30
- - A **container** — anything with open child work, or a childless Epic/Story/Spike — that still carries a stale build-ready role is **never claimed**. The vendor scanner skips it or safe-blocks it with an idempotent lifecycle-repair comment (move the build-ready role off the parent onto its leaf children; a parent's state rolls up from its children and is never set to ready directly).
30
+ - A **container** — anything with open child work, or a childless Epic/Story/Spike — that still carries a stale build-ready role is **never dispatched**. The GitHub scanner moves it out of the pickup queue by replacing `status:ready` with `status:in-progress` and posting an idempotent lifecycle-repair comment; other vendor scanners skip or safe-block according to their native lifecycle semantics.
31
31
 
32
32
  This is the claim-time arm of the rule. Its siblings are the write-time labeling (`lisa:tracker-write` → the vendor `*-write-*` skills apply build-ready to leaves only) and the validate-time S15 gate (`lisa:tracker-validate` → the vendor `*-validate-*` skills FAIL a build-ready container). All three arms cite `leaf-only-lifecycle` so no vendor drifts. Each vendor scanner implements the gate against its own hierarchy:
33
33
 
@@ -55,6 +55,6 @@ Intermediate env states are not native closure. A vendor scanner that resolves `
55
55
 
56
56
  - Single cycle per invocation — the vendor skill processes the current `Ready` set and exits.
57
57
  - The vendor skills run their own pre-flight checks (JIRA workflow transitions for the JIRA path; label namespace adoption for the GitHub and Linear paths) before processing items. Never bypass.
58
- - **Leaf-only claim, every vendor.** Per the `leaf-only-lifecycle` rule, each vendor scanner claims leaf work units only and skips / safe-blocks a container (open child work, or a childless Epic/Story/Spike) carrying a stale build-ready role. This shim does not re-implement the gate — it relies on the vendor scanner's Phase 3a — but the contract is uniform across `jira`, `github`, and `linear` so behavior never drifts by tracker.
58
+ - **Leaf-only dispatch, every vendor.** Per the `leaf-only-lifecycle` rule, each vendor scanner dispatches leaf work units only and moves or safe-blocks a container (open child work, or a childless Epic/Story/Spike) carrying a stale build-ready role according to its lifecycle semantics. This shim does not re-implement the gate — it relies on the vendor scanner's Phase 3a — but the contract is uniform across `jira`, `github`, and `linear` so behavior never drifts by tracker.
59
59
  - **Terminal native closure, every capable vendor.** Per the same rule, each vendor scanner finalizes native open/closed state only at the true terminal `done` value. This shim never performs native closure itself, but callers can rely on the dispatched vendor scanner to apply the contract.
60
60
  - Never run two intake cycles concurrently against overlapping queues — the scheduling layer is responsible for serialization.