@codyswann/lisa 2.27.0 → 2.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/skills/github-to-tracker/SKILL.md +6 -0
- package/plugins/lisa/skills/github-validate-issue/SKILL.md +33 -2
- package/plugins/lisa/skills/github-write-issue/SKILL.md +18 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/src/base/skills/github-to-tracker/SKILL.md +6 -0
- package/plugins/src/base/skills/github-validate-issue/SKILL.md +33 -2
- package/plugins/src/base/skills/github-write-issue/SKILL.md +18 -1
package/package.json
CHANGED
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"lodash": ">=4.18.1"
|
|
83
83
|
},
|
|
84
84
|
"name": "@codyswann/lisa",
|
|
85
|
-
"version": "2.
|
|
85
|
+
"version": "2.29.0",
|
|
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": {
|
|
@@ -198,6 +198,8 @@ For each epic identified in Phase 1, **invoke the `lisa:tracker-write` shim** (d
|
|
|
198
198
|
- `artifacts`: the full Phase 1.5 artifact list — every artifact, regardless of domain. The Epic is the canonical hub.
|
|
199
199
|
- `priority`, `labels`, `components`, `fix_version`: as appropriate
|
|
200
200
|
|
|
201
|
+
**Leaf-only build-ready (`leaf-only-lifecycle`)**: an Epic is a container, not a leaf work unit. Do NOT mark it build-ready — `lisa:tracker-write` must not be passed `status:ready` for an Epic, and the Epic's lifecycle state rolls up from its children. The build-ready label is applied only in Phase 5.
|
|
202
|
+
|
|
201
203
|
Capture the returned epic ref — Phase 4 needs it as the parent for Stories.
|
|
202
204
|
|
|
203
205
|
### Phase 4: Create Stories
|
|
@@ -225,6 +227,8 @@ For each Story, **invoke `lisa:tracker-write`** with:
|
|
|
225
227
|
| Infrastructure | `ops`, `reference` |
|
|
226
228
|
| Mixed / setup ("X.0") | All domains |
|
|
227
229
|
|
|
230
|
+
**Leaf-only build-ready (`leaf-only-lifecycle`)**: a Story is a container (it has child Sub-tasks), not a leaf work unit. Do NOT mark it build-ready — never pass `status:ready` to `lisa:tracker-write` for a Story. Its lifecycle state rolls up from its Sub-tasks. The build-ready label is applied only in Phase 5.
|
|
231
|
+
|
|
228
232
|
Capture each returned story ref — Phase 5 needs it.
|
|
229
233
|
|
|
230
234
|
### Phase 5: Create Sub-tasks
|
|
@@ -237,6 +241,8 @@ Each sub-task MUST:
|
|
|
237
241
|
1. **Be scoped to exactly ONE repo** — indicated in brackets in the summary: `[repo-name]`.
|
|
238
242
|
2. **Include an Empirical Verification Plan** — real user-like verification, NOT unit tests, linting, or typechecking.
|
|
239
243
|
|
|
244
|
+
**Leaf-only build-ready (`leaf-only-lifecycle`)**: Sub-tasks are the **leaf work units** of the decomposition — they are the ONLY items in the hierarchy that receive the build-ready label. `lisa:tracker-write` applies `status:ready` here so downstream build intake (`lisa:github-build-intake`) claims the leaves and never the Epic or Stories. Apply `status:ready` to each Sub-task; never to its parent Story or Epic (Phases 3–4). `lisa:github-write-issue` enforces the same invariant on the write side, so a Sub-task split into per-repo children (the cross-repo case above) carries build-ready on the children, not on any intermediate parent that gains child work.
|
|
245
|
+
|
|
240
246
|
Sub-tasks inherit their parent Story's artifacts by reference (the parent link). Do not pass the same artifact list to every sub-task.
|
|
241
247
|
|
|
242
248
|
### Phase 5.5: Artifact Preservation Gate (mandatory)
|
|
@@ -63,6 +63,8 @@ artifacts_attached: true # → requires Source Precedence section
|
|
|
63
63
|
links: [{ ref: "my-org/my-repo#99", type: "is blocked by" }] # known issue links (may be empty)
|
|
64
64
|
remote_links: [{ url: "https://github.com/.../pull/42", title: "PR #42" }]
|
|
65
65
|
journey_followup: auto # auto | none — see S11
|
|
66
|
+
build_ready: true # caller asserts the build-ready role (status:ready) is/would be applied — see S15
|
|
67
|
+
child_refs: ["my-org/my-repo#601", "my-org/my-repo#602"] # known child work (sub-issues / task-list / "Blocked by" parentage) — see S15
|
|
66
68
|
```
|
|
67
69
|
|
|
68
70
|
If the caller passes only an issue ref, fetch via `gh issue view <number> --repo <org>/<repo> --json number,title,body,labels,state,milestone,assignees`, parse the body sections, derive the spec fields, then run gates. The parser lives in `lisa:github-read-issue` (composition).
|
|
@@ -89,6 +91,7 @@ Each gate is tagged with a fixed `category` and a `product_relevant` boolean. Ca
|
|
|
89
91
|
| S12 Source Precedence | `design-ux` | true |
|
|
90
92
|
| S13 Relationship Search | `dependency` | true |
|
|
91
93
|
| S14 Evidence manifest binding (leaf work units) | `acceptance-criteria` | true |
|
|
94
|
+
| S15 Leaf-only build-ready | `structural` | false |
|
|
92
95
|
| F1 Issue type label exists in repo | `structural` | false |
|
|
93
96
|
| F2 Parent sub-issue exists and is the right type | `structural` | false |
|
|
94
97
|
| F3 Linked issues exist | `structural` | false |
|
|
@@ -198,6 +201,33 @@ FAIL when the Validation Journey is present but declares zero `[EVIDENCE: name]`
|
|
|
198
201
|
|
|
199
202
|
This gate depends on S11. It is `N/A` for Epic / Story / Spike (coordination containers, not work units) and for leaf units with `runtime_behavior_change = false` (doc-only / config-only / type-only). If S11 fails because the Validation Journey is absent, S14 also FAILs (there is no manifest to bind) with remediation pointing back to `lisa:github-add-journey`.
|
|
200
203
|
|
|
204
|
+
#### S15 — Leaf-only build-ready
|
|
205
|
+
|
|
206
|
+
Enforces the build-side of the vendor-neutral `leaf-only-lifecycle` rule: **only a leaf work unit may carry the build-ready role.** This is the symmetric write-side guard for the GitHub validator — a stale or hand-applied `status:ready` on a container is a lifecycle error and must FAIL here, regardless of how the issue was produced. (Mirrors the "Build-ready label is leaf-only" rule that `lisa:github-write-issue` applies at write time.)
|
|
207
|
+
|
|
208
|
+
**When the gate applies.** Run S15 whenever the issue is build-ready — i.e. `build_ready = true`, or the spec/live labels include `status:ready`. If the issue is not build-ready, S15 is `N/A` (nothing claims a non-ready issue, so the invariant is vacuous).
|
|
209
|
+
|
|
210
|
+
**Resolve container vs. leaf — structural first, then nominal.** Per `leaf-only-lifecycle` the classification is structural: an item is a **container** if it has child work, whatever its declared type; otherwise the **type label** decides. Determine child work from (in order) `child_refs`, native sub-issues, body task-list checkboxes, and `Blocked by #<n>` / parent references — the same hierarchy resolution `lisa:github-read-issue` uses. When validating a live ref, query sub-issues alongside the issue fetch.
|
|
211
|
+
|
|
212
|
+
Apply this decision and FAIL the two invariant-violating cases:
|
|
213
|
+
|
|
214
|
+
1. **Container with child work + build-ready** — `issue_type ∈ {Epic, Story, Spike}` OR child work is present (any type that has children), AND build-ready. FAIL. A parent organizes work; it is never claimed and implemented directly. Its lifecycle state rolls up from its children.
|
|
215
|
+
2. **Childless container-type + build-ready** — `issue_type ∈ {Epic, Story, Spike}` with **no** child work, AND build-ready. Still FAIL: these types are coordination containers by design, and an empty one is an incomplete decomposition, not an implementable unit (the childless-parent exception in `leaf-only-lifecycle` does **not** promote an Epic/Story/Spike to build-ready).
|
|
216
|
+
|
|
217
|
+
PASS (the childless-parent exception) when the issue is build-ready and is a **leaf work unit**: `issue_type ∈ {Bug, Task, Sub-task, Improvement}` AND has **no** child work. A flat Task or Bug with no sub-issues is a valid build-ready leaf and must not be stranded.
|
|
218
|
+
|
|
219
|
+
| issue_type | has child work | build-ready | S15 |
|
|
220
|
+
|---|---|---|---|
|
|
221
|
+
| Bug / Task / Sub-task / Improvement | no | yes | **PASS** (leaf) |
|
|
222
|
+
| Bug / Task / Sub-task / Improvement | yes | yes | **FAIL** (structurally a container) |
|
|
223
|
+
| Epic / Story / Spike | yes | yes | **FAIL** (container with children) |
|
|
224
|
+
| Epic / Story / Spike | no | yes | **FAIL** (childless container-type, exception does not apply) |
|
|
225
|
+
| any | any | no | **N/A** (not build-ready) |
|
|
226
|
+
|
|
227
|
+
Remediation: `"Build-ready (status:ready) is leaf-only per leaf-only-lifecycle. Move status:ready off this container 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."`
|
|
228
|
+
|
|
229
|
+
`product_relevant: false` — a build-ready container is a lifecycle/decomposition error for the caller to repair, not a product question.
|
|
230
|
+
|
|
201
231
|
### Feasibility Gates (require GitHub lookups; skip in `--spec-only`)
|
|
202
232
|
|
|
203
233
|
#### F1 — Issue type label exists in repo
|
|
@@ -230,7 +260,7 @@ Per `Phase 5` of `lisa:github-write-issue`, every issue MUST carry: `type:<issue
|
|
|
230
260
|
|
|
231
261
|
## Execution
|
|
232
262
|
|
|
233
|
-
1. Parse `$ARGUMENTS`. If it's an issue ref, fetch via `gh issue view --json` and derive the spec fields. Otherwise parse the YAML spec.
|
|
263
|
+
1. Parse `$ARGUMENTS`. If it's an issue ref, fetch via `gh issue view --json` and derive the spec fields — including `build_ready` (label set contains `status:ready`) and `child_refs` (native sub-issues plus body task-list / `Blocked by #<n>` parentage, resolved as in `lisa:github-read-issue`) so S15 can classify the issue. Otherwise parse the YAML spec.
|
|
234
264
|
2. Confirm `gh auth status` succeeds before any feasibility gate runs.
|
|
235
265
|
3. Run every Specification gate in order. Collect PASS / FAIL / N/A with a one-line reason.
|
|
236
266
|
4. Unless the caller passed `--spec-only`, run every Feasibility gate.
|
|
@@ -258,6 +288,7 @@ Output is a single fenced text block. Callers parse it; do not add free-form pro
|
|
|
258
288
|
- [PASS|FAIL|N/A] S12 Source Precedence — <one-line reason>
|
|
259
289
|
- [PASS|FAIL|N/A] S13 Relationship Search — <one-line reason>
|
|
260
290
|
- [PASS|FAIL|N/A] S14 Evidence manifest binding — <one-line reason>
|
|
291
|
+
- [PASS|FAIL|N/A] S15 Leaf-only build-ready — <one-line reason>
|
|
261
292
|
|
|
262
293
|
### Feasibility Gates (omit this section when --spec-only)
|
|
263
294
|
- [PASS|FAIL|N/A] F1 Issue type label exists in repo — <one-line reason>
|
|
@@ -283,7 +314,7 @@ The verdict is `PASS` if every applicable gate is `PASS`. Any `FAIL` makes the v
|
|
|
283
314
|
|
|
284
315
|
Same shape and meaning as `lisa:jira-validate-ticket` so downstream PRD-intake skills (Notion, Confluence, Linear, GitHub) can format comments uniformly:
|
|
285
316
|
|
|
286
|
-
- **gate**: the gate ID (`S1`–`
|
|
317
|
+
- **gate**: the gate ID (`S1`–`S15`, `F1`–`F4`).
|
|
287
318
|
- **category**: the gate's fixed category from the table.
|
|
288
319
|
- **product_relevant**: matches the gate's table entry. `false` means the failure is an internal data-quality problem the caller should fix without bothering product.
|
|
289
320
|
- **what**: plain-language, product-readable.
|
|
@@ -206,6 +206,12 @@ Milestones map to `fix-version:<value>` labels OR native GitHub Milestones — p
|
|
|
206
206
|
|
|
207
207
|
Create labels lazily — call `gh label create` if a referenced label doesn't exist. Use a stable color palette per category so the issue board reads cleanly.
|
|
208
208
|
|
|
209
|
+
### Build-ready label is leaf-only
|
|
210
|
+
|
|
211
|
+
The build-ready status label (`status:ready`) is governed by the `leaf-only-lifecycle` rule. **Apply `status:ready` only when the issue is a leaf work unit** — an individually implementable issue type (`Bug`, `Task`, `Sub-task`, `Improvement`) that has **no child work**. A container (`Epic`, `Story`, `Spike`, or *any* issue that has sub-issues) is **never** written with `status:ready`; its lifecycle state rolls up from its children. The classification is structural: an item is a container if it has child work, regardless of its declared type (see the childless-parent exception in the rule). Do not hand-apply `status:ready` to a parent.
|
|
212
|
+
|
|
213
|
+
For non-build-ready issues created fresh (Epics, Stories, and other containers), omit the status label entirely; the container's rollup state is derived, not set directly.
|
|
214
|
+
|
|
209
215
|
## Phase 5.5 — Validate (Pre-write Gate)
|
|
210
216
|
|
|
211
217
|
Before any write, invoke `lisa:github-validate-issue` with the full proposed spec assembled from Phases 2 / 3 / 4 / 5. Pass it as a YAML block per the `lisa:github-validate-issue` schema, including `runtime_behavior_change`, `authenticated_surface`, and `artifacts_attached` flags so the right gates run.
|
|
@@ -218,8 +224,9 @@ If the validator reports `FAIL`, do NOT proceed to Phase 6. Fix the spec and re-
|
|
|
218
224
|
|
|
219
225
|
### CREATE
|
|
220
226
|
|
|
221
|
-
1. Compose the body markdown from Phases 2/3/4 in a temp file (avoid quoting hell):
|
|
227
|
+
1. Compose the body markdown from Phases 2/3/4 in a temp file (avoid quoting hell). Apply `status:ready` **only for a leaf work unit** per the Phase 5 leaf-only rule (`leaf-only-lifecycle`) — omit it for `Epic` / `Story` / `Spike` and any issue that has child work:
|
|
222
228
|
```bash
|
|
229
|
+
# Leaf work unit (Bug / Task / Sub-task / Improvement with no children):
|
|
223
230
|
gh issue create \
|
|
224
231
|
--repo <org>/<repo> \
|
|
225
232
|
--title "<summary>" \
|
|
@@ -227,6 +234,16 @@ If the validator reports `FAIL`, do NOT proceed to Phase 6. Fix the spec and re-
|
|
|
227
234
|
--label "type:<type>" --label "status:ready" --label "priority:<priority>" \
|
|
228
235
|
[--label "component:<name>" ...] [--milestone "<milestone>"] \
|
|
229
236
|
[--assignee "<login>"]
|
|
237
|
+
|
|
238
|
+
# Container (Epic / Story / Spike / any issue with child work):
|
|
239
|
+
# identical, but WITHOUT --label "status:ready" — its state rolls up from children.
|
|
240
|
+
gh issue create \
|
|
241
|
+
--repo <org>/<repo> \
|
|
242
|
+
--title "<summary>" \
|
|
243
|
+
--body-file /tmp/issue-body.md \
|
|
244
|
+
--label "type:<type>" --label "priority:<priority>" \
|
|
245
|
+
[--label "component:<name>" ...] [--milestone "<milestone>"] \
|
|
246
|
+
[--assignee "<login>"]
|
|
230
247
|
```
|
|
231
248
|
2. Capture the returned issue number.
|
|
232
249
|
3. **Link to parent sub-issue** (if non-Epic): use the GraphQL sub-issue API.
|
|
@@ -198,6 +198,8 @@ For each epic identified in Phase 1, **invoke the `lisa:tracker-write` shim** (d
|
|
|
198
198
|
- `artifacts`: the full Phase 1.5 artifact list — every artifact, regardless of domain. The Epic is the canonical hub.
|
|
199
199
|
- `priority`, `labels`, `components`, `fix_version`: as appropriate
|
|
200
200
|
|
|
201
|
+
**Leaf-only build-ready (`leaf-only-lifecycle`)**: an Epic is a container, not a leaf work unit. Do NOT mark it build-ready — `lisa:tracker-write` must not be passed `status:ready` for an Epic, and the Epic's lifecycle state rolls up from its children. The build-ready label is applied only in Phase 5.
|
|
202
|
+
|
|
201
203
|
Capture the returned epic ref — Phase 4 needs it as the parent for Stories.
|
|
202
204
|
|
|
203
205
|
### Phase 4: Create Stories
|
|
@@ -225,6 +227,8 @@ For each Story, **invoke `lisa:tracker-write`** with:
|
|
|
225
227
|
| Infrastructure | `ops`, `reference` |
|
|
226
228
|
| Mixed / setup ("X.0") | All domains |
|
|
227
229
|
|
|
230
|
+
**Leaf-only build-ready (`leaf-only-lifecycle`)**: a Story is a container (it has child Sub-tasks), not a leaf work unit. Do NOT mark it build-ready — never pass `status:ready` to `lisa:tracker-write` for a Story. Its lifecycle state rolls up from its Sub-tasks. The build-ready label is applied only in Phase 5.
|
|
231
|
+
|
|
228
232
|
Capture each returned story ref — Phase 5 needs it.
|
|
229
233
|
|
|
230
234
|
### Phase 5: Create Sub-tasks
|
|
@@ -237,6 +241,8 @@ Each sub-task MUST:
|
|
|
237
241
|
1. **Be scoped to exactly ONE repo** — indicated in brackets in the summary: `[repo-name]`.
|
|
238
242
|
2. **Include an Empirical Verification Plan** — real user-like verification, NOT unit tests, linting, or typechecking.
|
|
239
243
|
|
|
244
|
+
**Leaf-only build-ready (`leaf-only-lifecycle`)**: Sub-tasks are the **leaf work units** of the decomposition — they are the ONLY items in the hierarchy that receive the build-ready label. `lisa:tracker-write` applies `status:ready` here so downstream build intake (`lisa:github-build-intake`) claims the leaves and never the Epic or Stories. Apply `status:ready` to each Sub-task; never to its parent Story or Epic (Phases 3–4). `lisa:github-write-issue` enforces the same invariant on the write side, so a Sub-task split into per-repo children (the cross-repo case above) carries build-ready on the children, not on any intermediate parent that gains child work.
|
|
245
|
+
|
|
240
246
|
Sub-tasks inherit their parent Story's artifacts by reference (the parent link). Do not pass the same artifact list to every sub-task.
|
|
241
247
|
|
|
242
248
|
### Phase 5.5: Artifact Preservation Gate (mandatory)
|
|
@@ -63,6 +63,8 @@ artifacts_attached: true # → requires Source Precedence section
|
|
|
63
63
|
links: [{ ref: "my-org/my-repo#99", type: "is blocked by" }] # known issue links (may be empty)
|
|
64
64
|
remote_links: [{ url: "https://github.com/.../pull/42", title: "PR #42" }]
|
|
65
65
|
journey_followup: auto # auto | none — see S11
|
|
66
|
+
build_ready: true # caller asserts the build-ready role (status:ready) is/would be applied — see S15
|
|
67
|
+
child_refs: ["my-org/my-repo#601", "my-org/my-repo#602"] # known child work (sub-issues / task-list / "Blocked by" parentage) — see S15
|
|
66
68
|
```
|
|
67
69
|
|
|
68
70
|
If the caller passes only an issue ref, fetch via `gh issue view <number> --repo <org>/<repo> --json number,title,body,labels,state,milestone,assignees`, parse the body sections, derive the spec fields, then run gates. The parser lives in `lisa:github-read-issue` (composition).
|
|
@@ -89,6 +91,7 @@ Each gate is tagged with a fixed `category` and a `product_relevant` boolean. Ca
|
|
|
89
91
|
| S12 Source Precedence | `design-ux` | true |
|
|
90
92
|
| S13 Relationship Search | `dependency` | true |
|
|
91
93
|
| S14 Evidence manifest binding (leaf work units) | `acceptance-criteria` | true |
|
|
94
|
+
| S15 Leaf-only build-ready | `structural` | false |
|
|
92
95
|
| F1 Issue type label exists in repo | `structural` | false |
|
|
93
96
|
| F2 Parent sub-issue exists and is the right type | `structural` | false |
|
|
94
97
|
| F3 Linked issues exist | `structural` | false |
|
|
@@ -198,6 +201,33 @@ FAIL when the Validation Journey is present but declares zero `[EVIDENCE: name]`
|
|
|
198
201
|
|
|
199
202
|
This gate depends on S11. It is `N/A` for Epic / Story / Spike (coordination containers, not work units) and for leaf units with `runtime_behavior_change = false` (doc-only / config-only / type-only). If S11 fails because the Validation Journey is absent, S14 also FAILs (there is no manifest to bind) with remediation pointing back to `lisa:github-add-journey`.
|
|
200
203
|
|
|
204
|
+
#### S15 — Leaf-only build-ready
|
|
205
|
+
|
|
206
|
+
Enforces the build-side of the vendor-neutral `leaf-only-lifecycle` rule: **only a leaf work unit may carry the build-ready role.** This is the symmetric write-side guard for the GitHub validator — a stale or hand-applied `status:ready` on a container is a lifecycle error and must FAIL here, regardless of how the issue was produced. (Mirrors the "Build-ready label is leaf-only" rule that `lisa:github-write-issue` applies at write time.)
|
|
207
|
+
|
|
208
|
+
**When the gate applies.** Run S15 whenever the issue is build-ready — i.e. `build_ready = true`, or the spec/live labels include `status:ready`. If the issue is not build-ready, S15 is `N/A` (nothing claims a non-ready issue, so the invariant is vacuous).
|
|
209
|
+
|
|
210
|
+
**Resolve container vs. leaf — structural first, then nominal.** Per `leaf-only-lifecycle` the classification is structural: an item is a **container** if it has child work, whatever its declared type; otherwise the **type label** decides. Determine child work from (in order) `child_refs`, native sub-issues, body task-list checkboxes, and `Blocked by #<n>` / parent references — the same hierarchy resolution `lisa:github-read-issue` uses. When validating a live ref, query sub-issues alongside the issue fetch.
|
|
211
|
+
|
|
212
|
+
Apply this decision and FAIL the two invariant-violating cases:
|
|
213
|
+
|
|
214
|
+
1. **Container with child work + build-ready** — `issue_type ∈ {Epic, Story, Spike}` OR child work is present (any type that has children), AND build-ready. FAIL. A parent organizes work; it is never claimed and implemented directly. Its lifecycle state rolls up from its children.
|
|
215
|
+
2. **Childless container-type + build-ready** — `issue_type ∈ {Epic, Story, Spike}` with **no** child work, AND build-ready. Still FAIL: these types are coordination containers by design, and an empty one is an incomplete decomposition, not an implementable unit (the childless-parent exception in `leaf-only-lifecycle` does **not** promote an Epic/Story/Spike to build-ready).
|
|
216
|
+
|
|
217
|
+
PASS (the childless-parent exception) when the issue is build-ready and is a **leaf work unit**: `issue_type ∈ {Bug, Task, Sub-task, Improvement}` AND has **no** child work. A flat Task or Bug with no sub-issues is a valid build-ready leaf and must not be stranded.
|
|
218
|
+
|
|
219
|
+
| issue_type | has child work | build-ready | S15 |
|
|
220
|
+
|---|---|---|---|
|
|
221
|
+
| Bug / Task / Sub-task / Improvement | no | yes | **PASS** (leaf) |
|
|
222
|
+
| Bug / Task / Sub-task / Improvement | yes | yes | **FAIL** (structurally a container) |
|
|
223
|
+
| Epic / Story / Spike | yes | yes | **FAIL** (container with children) |
|
|
224
|
+
| Epic / Story / Spike | no | yes | **FAIL** (childless container-type, exception does not apply) |
|
|
225
|
+
| any | any | no | **N/A** (not build-ready) |
|
|
226
|
+
|
|
227
|
+
Remediation: `"Build-ready (status:ready) is leaf-only per leaf-only-lifecycle. Move status:ready off this container 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."`
|
|
228
|
+
|
|
229
|
+
`product_relevant: false` — a build-ready container is a lifecycle/decomposition error for the caller to repair, not a product question.
|
|
230
|
+
|
|
201
231
|
### Feasibility Gates (require GitHub lookups; skip in `--spec-only`)
|
|
202
232
|
|
|
203
233
|
#### F1 — Issue type label exists in repo
|
|
@@ -230,7 +260,7 @@ Per `Phase 5` of `lisa:github-write-issue`, every issue MUST carry: `type:<issue
|
|
|
230
260
|
|
|
231
261
|
## Execution
|
|
232
262
|
|
|
233
|
-
1. Parse `$ARGUMENTS`. If it's an issue ref, fetch via `gh issue view --json` and derive the spec fields. Otherwise parse the YAML spec.
|
|
263
|
+
1. Parse `$ARGUMENTS`. If it's an issue ref, fetch via `gh issue view --json` and derive the spec fields — including `build_ready` (label set contains `status:ready`) and `child_refs` (native sub-issues plus body task-list / `Blocked by #<n>` parentage, resolved as in `lisa:github-read-issue`) so S15 can classify the issue. Otherwise parse the YAML spec.
|
|
234
264
|
2. Confirm `gh auth status` succeeds before any feasibility gate runs.
|
|
235
265
|
3. Run every Specification gate in order. Collect PASS / FAIL / N/A with a one-line reason.
|
|
236
266
|
4. Unless the caller passed `--spec-only`, run every Feasibility gate.
|
|
@@ -258,6 +288,7 @@ Output is a single fenced text block. Callers parse it; do not add free-form pro
|
|
|
258
288
|
- [PASS|FAIL|N/A] S12 Source Precedence — <one-line reason>
|
|
259
289
|
- [PASS|FAIL|N/A] S13 Relationship Search — <one-line reason>
|
|
260
290
|
- [PASS|FAIL|N/A] S14 Evidence manifest binding — <one-line reason>
|
|
291
|
+
- [PASS|FAIL|N/A] S15 Leaf-only build-ready — <one-line reason>
|
|
261
292
|
|
|
262
293
|
### Feasibility Gates (omit this section when --spec-only)
|
|
263
294
|
- [PASS|FAIL|N/A] F1 Issue type label exists in repo — <one-line reason>
|
|
@@ -283,7 +314,7 @@ The verdict is `PASS` if every applicable gate is `PASS`. Any `FAIL` makes the v
|
|
|
283
314
|
|
|
284
315
|
Same shape and meaning as `lisa:jira-validate-ticket` so downstream PRD-intake skills (Notion, Confluence, Linear, GitHub) can format comments uniformly:
|
|
285
316
|
|
|
286
|
-
- **gate**: the gate ID (`S1`–`
|
|
317
|
+
- **gate**: the gate ID (`S1`–`S15`, `F1`–`F4`).
|
|
287
318
|
- **category**: the gate's fixed category from the table.
|
|
288
319
|
- **product_relevant**: matches the gate's table entry. `false` means the failure is an internal data-quality problem the caller should fix without bothering product.
|
|
289
320
|
- **what**: plain-language, product-readable.
|
|
@@ -206,6 +206,12 @@ Milestones map to `fix-version:<value>` labels OR native GitHub Milestones — p
|
|
|
206
206
|
|
|
207
207
|
Create labels lazily — call `gh label create` if a referenced label doesn't exist. Use a stable color palette per category so the issue board reads cleanly.
|
|
208
208
|
|
|
209
|
+
### Build-ready label is leaf-only
|
|
210
|
+
|
|
211
|
+
The build-ready status label (`status:ready`) is governed by the `leaf-only-lifecycle` rule. **Apply `status:ready` only when the issue is a leaf work unit** — an individually implementable issue type (`Bug`, `Task`, `Sub-task`, `Improvement`) that has **no child work**. A container (`Epic`, `Story`, `Spike`, or *any* issue that has sub-issues) is **never** written with `status:ready`; its lifecycle state rolls up from its children. The classification is structural: an item is a container if it has child work, regardless of its declared type (see the childless-parent exception in the rule). Do not hand-apply `status:ready` to a parent.
|
|
212
|
+
|
|
213
|
+
For non-build-ready issues created fresh (Epics, Stories, and other containers), omit the status label entirely; the container's rollup state is derived, not set directly.
|
|
214
|
+
|
|
209
215
|
## Phase 5.5 — Validate (Pre-write Gate)
|
|
210
216
|
|
|
211
217
|
Before any write, invoke `lisa:github-validate-issue` with the full proposed spec assembled from Phases 2 / 3 / 4 / 5. Pass it as a YAML block per the `lisa:github-validate-issue` schema, including `runtime_behavior_change`, `authenticated_surface`, and `artifacts_attached` flags so the right gates run.
|
|
@@ -218,8 +224,9 @@ If the validator reports `FAIL`, do NOT proceed to Phase 6. Fix the spec and re-
|
|
|
218
224
|
|
|
219
225
|
### CREATE
|
|
220
226
|
|
|
221
|
-
1. Compose the body markdown from Phases 2/3/4 in a temp file (avoid quoting hell):
|
|
227
|
+
1. Compose the body markdown from Phases 2/3/4 in a temp file (avoid quoting hell). Apply `status:ready` **only for a leaf work unit** per the Phase 5 leaf-only rule (`leaf-only-lifecycle`) — omit it for `Epic` / `Story` / `Spike` and any issue that has child work:
|
|
222
228
|
```bash
|
|
229
|
+
# Leaf work unit (Bug / Task / Sub-task / Improvement with no children):
|
|
223
230
|
gh issue create \
|
|
224
231
|
--repo <org>/<repo> \
|
|
225
232
|
--title "<summary>" \
|
|
@@ -227,6 +234,16 @@ If the validator reports `FAIL`, do NOT proceed to Phase 6. Fix the spec and re-
|
|
|
227
234
|
--label "type:<type>" --label "status:ready" --label "priority:<priority>" \
|
|
228
235
|
[--label "component:<name>" ...] [--milestone "<milestone>"] \
|
|
229
236
|
[--assignee "<login>"]
|
|
237
|
+
|
|
238
|
+
# Container (Epic / Story / Spike / any issue with child work):
|
|
239
|
+
# identical, but WITHOUT --label "status:ready" — its state rolls up from children.
|
|
240
|
+
gh issue create \
|
|
241
|
+
--repo <org>/<repo> \
|
|
242
|
+
--title "<summary>" \
|
|
243
|
+
--body-file /tmp/issue-body.md \
|
|
244
|
+
--label "type:<type>" --label "priority:<priority>" \
|
|
245
|
+
[--label "component:<name>" ...] [--milestone "<milestone>"] \
|
|
246
|
+
[--assignee "<login>"]
|
|
230
247
|
```
|
|
231
248
|
2. Capture the returned issue number.
|
|
232
249
|
3. **Link to parent sub-issue** (if non-Epic): use the GraphQL sub-issue API.
|