@codyswann/lisa 2.221.4 → 2.221.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-github-validate-issue/SKILL.md +68 -9
- package/plugins/lisa/skills/lisa-github-validate-issue/SKILL.md +68 -9
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-github-validate-issue/SKILL.md +68 -9
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/skills/lisa-github-validate-issue/SKILL.md +68 -9
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/skills/lisa-github-validate-issue/SKILL.md +68 -9
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/skills/lisa-github-validate-issue/SKILL.md +68 -9
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.221.
|
|
105
|
+
"version": "2.221.6",
|
|
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": {
|
|
@@ -25,7 +25,7 @@ org: my-org
|
|
|
25
25
|
repo: my-repo
|
|
26
26
|
summary: "[CU-1.2] Upload contract PDF from settings"
|
|
27
27
|
priority: medium
|
|
28
|
-
parent_ref: "my-org/my-repo#1234" # Parent Epic for
|
|
28
|
+
parent_ref: "my-org/my-repo#1234" # Parent Epic for ordinary children; PRD for an Epic only in the same-repo GitHub self-host shape; Story/etc. for Sub-task
|
|
29
29
|
body: |
|
|
30
30
|
## Context / Business Value
|
|
31
31
|
...
|
|
@@ -63,7 +63,7 @@ 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
|
|
66
|
+
build_ready: true # caller asserts the configured build-ready role (github.labels.build.ready, default status:ready) is/would be applied — see S15
|
|
67
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
|
|
68
68
|
prd_source: "https://notion.so/..." # set when the issue was generated from a PRD — requires the Source Requirement section, see S16
|
|
69
69
|
```
|
|
@@ -213,9 +213,11 @@ This gate depends on S11. It is `N/A` for containers — an **Epic**, or any ite
|
|
|
213
213
|
|
|
214
214
|
#### S15 — Leaf-only build-ready
|
|
215
215
|
|
|
216
|
-
Enforces the build-side of the vendor-neutral `leaf-only-lifecycle` rule: **only a leaf work unit may carry the build-ready role.**
|
|
216
|
+
Enforces the build-side of the vendor-neutral `leaf-only-lifecycle` rule: **only a leaf work unit may carry the build-ready role.** Before evaluating this gate, resolve `READY_ROLE` from merged project config (`.lisa.config.local.json` over `.lisa.config.json`) at `github.labels.build.ready`, defaulting to `status:ready` per `config-resolution`. Use that resolved value everywhere this validator interprets build readiness; a project-specific label is not an alias for the literal default.
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
This is the symmetric write-side guard for the GitHub validator — a stale or hand-applied `READY_ROLE` 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.)
|
|
219
|
+
|
|
220
|
+
**When the gate applies.** Run S15 whenever the issue is build-ready — i.e. `build_ready = true`, or the spec/live labels include the resolved `READY_ROLE`. If the issue is not build-ready, S15 is `N/A` (nothing claims a non-ready issue, so the invariant is vacuous). For example, if `github.labels.build.ready = "queue:approved"`, a container carrying `queue:approved` FAILs S15 even when it does not carry the literal `status:ready` default.
|
|
219
221
|
|
|
220
222
|
**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.
|
|
221
223
|
|
|
@@ -233,7 +235,7 @@ PASS (the childless-parent exception) when the issue is build-ready and is a **l
|
|
|
233
235
|
| Epic | no | yes | **FAIL** (childless Epic — pure rollup container, exception does not apply) |
|
|
234
236
|
| any | any | no | **N/A** (not build-ready) |
|
|
235
237
|
|
|
236
|
-
Remediation: `"Build-ready (status:ready) is leaf-only per leaf-only-lifecycle. Move
|
|
238
|
+
Remediation (render `<READY_ROLE>` as the resolved configured label, never as a hard-coded default): `"Build-ready (<READY_ROLE>; status:ready by default) is leaf-only per leaf-only-lifecycle. Move <READY_ROLE> off this container onto its leaf children (or, for a childless Epic, 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."`
|
|
237
239
|
|
|
238
240
|
`product_relevant: false` — a build-ready container is a lifecycle/decomposition error for the caller to repair, not a product question.
|
|
239
241
|
|
|
@@ -284,8 +286,37 @@ gh issue view <number> --repo <org>/<repo> --json number,labels,state
|
|
|
284
286
|
```
|
|
285
287
|
|
|
286
288
|
Confirm the parent issue exists and:
|
|
287
|
-
|
|
288
|
-
- For
|
|
289
|
+
|
|
290
|
+
- For an `Epic` child, first resolve whether the validator can prove the native PRD-parent shape
|
|
291
|
+
allowed by `prd-lifecycle-rollup`: merged project config has `source = github` and
|
|
292
|
+
`tracker = github`; the spec/live child's `org` and `repo` match configured `github.org` and
|
|
293
|
+
`github.repo`; and `parent_ref` names that same `org/repo`. These facts are available from the
|
|
294
|
+
existing spec/live ref plus project config; do not infer the exception from label spelling alone.
|
|
295
|
+
Only in that proven same-repository GitHub self-host shape may the parent qualify by having one of
|
|
296
|
+
the configured PRD lifecycle labels from
|
|
297
|
+
`github.labels.prd` (`draft`, `ready`, `in_review`, `blocked`, `ticketed`, `shipped`, or
|
|
298
|
+
`verified`; defaults use the `prd-*` namespace). Resolve the configured values from
|
|
299
|
+
`.lisa.config.local.json` over `.lisa.config.json`, using the defaults from `config-resolution`.
|
|
300
|
+
The `sentinel` label is not a lifecycle role and does not qualify. This is the native
|
|
301
|
+
PRD→generated-Epic hierarchy used when GitHub is both source and tracker in one repository; the
|
|
302
|
+
PRD parent does **not** need `type:Epic`. If any self-host/same-repository predicate is false, a
|
|
303
|
+
PRD label does not grant the exception: native hierarchy cannot cross repositories or source
|
|
304
|
+
systems, so a PRD-labelled parent alone FAILs F2.
|
|
305
|
+
- For a `Sub-task` child: the parent has `type:Story`, `type:Task`, `type:Bug`, or
|
|
306
|
+
`type:Improvement` (anything that can host sub-tasks). This allowlist is unchanged; a PRD
|
|
307
|
+
lifecycle label or `type:Epic` alone does not qualify.
|
|
308
|
+
- For every other non-Sub-task child: the parent has `type:Epic`. A PRD lifecycle label alone does
|
|
309
|
+
not qualify, so the Epic→Story (and Epic→ordinary-leaf) hierarchy remains enforced.
|
|
310
|
+
|
|
311
|
+
| child type | relationship shape | qualifying parent label | F2 |
|
|
312
|
+
|---|---|---|---|
|
|
313
|
+
| `Epic` | source GitHub + tracker GitHub + configured child repo = parent repo | configured PRD lifecycle label | **PASS** |
|
|
314
|
+
| `Epic` | cross-repository or source/tracker is not same-repo GitHub | PRD lifecycle label only | **FAIL** |
|
|
315
|
+
| `Epic` | permitted self-host shape | unconfigured `prd-*` lookalike or `prd-intake-feedback` sentinel only | **FAIL** |
|
|
316
|
+
| `Sub-task` | any | `type:Story`, `type:Task`, `type:Bug`, or `type:Improvement` | **PASS** |
|
|
317
|
+
| `Sub-task` | any | PRD lifecycle label or `type:Epic` only | **FAIL** |
|
|
318
|
+
| any other non-Sub-task | any | `type:Epic` | **PASS** |
|
|
319
|
+
| any other non-Sub-task | any | PRD lifecycle label only | **FAIL** |
|
|
289
320
|
|
|
290
321
|
#### F3 — Linked issues exist
|
|
291
322
|
|
|
@@ -293,7 +324,35 @@ For each entry in `links`, run `gh issue view <number> --repo <link-org>/<link-r
|
|
|
293
324
|
|
|
294
325
|
#### F4 — Required labels populated
|
|
295
326
|
|
|
296
|
-
Per `Phase 5` of `lisa-github-write-issue`, every issue MUST carry
|
|
327
|
+
Per `Phase 5` of `lisa-github-write-issue`, every issue MUST carry
|
|
328
|
+
`type:<issue_type>` and `priority:<priority>`. These two labels are unconditional: if either is
|
|
329
|
+
missing from the proposed spec or live issue, FAIL with the missing label name.
|
|
330
|
+
|
|
331
|
+
The `status:*` requirement uses this validator's S15 leaf/container classification while preserving
|
|
332
|
+
the writer's documented `build_ready` control-input defaults:
|
|
333
|
+
|
|
334
|
+
1. Classify the issue structurally using the S15 child-resolution rules. A container (any issue
|
|
335
|
+
with child work, plus a childless `Epic`) may omit `status:*`; its state rolls up rather than
|
|
336
|
+
being assigned directly.
|
|
337
|
+
2. For a proposed leaf spec, normalize omitted `build_ready` to `true`, preserving the writer's
|
|
338
|
+
backward-compatible default-ready behavior. Explicit `build_ready: false` means backlog mode.
|
|
339
|
+
3. For a live issue ref, derive `build_ready` from the labels (`true` exactly when the S15-resolved
|
|
340
|
+
`READY_ROLE` from `github.labels.build.ready`, default `status:ready`, is present). A live backlog leaf without a status label
|
|
341
|
+
therefore validates as `build_ready: false`; live data cannot distinguish an explicit false from
|
|
342
|
+
a historical write that omitted the label.
|
|
343
|
+
4. A leaf with normalized `build_ready: true` MUST carry that same resolved `READY_ROLE`. A leaf with `build_ready: false` may omit
|
|
344
|
+
`status:*`.
|
|
345
|
+
|
|
346
|
+
| classification | normalized build_ready | status label | F4 |
|
|
347
|
+
|---|---:|---|---|
|
|
348
|
+
| container | any | omitted | **PASS** |
|
|
349
|
+
| leaf | `false` | omitted | **PASS** |
|
|
350
|
+
| leaf | `true` | configured build-ready role (`status:ready` by default) | **PASS** |
|
|
351
|
+
| leaf | `true` | omitted or a different `status:*` label | **FAIL** |
|
|
352
|
+
|
|
353
|
+
F4 does not make a container build-ready. S15 remains the independent lifecycle prohibition: any
|
|
354
|
+
container carrying the build-ready role still FAILs S15, even though F4's status-presence check is
|
|
355
|
+
not applicable to containers.
|
|
297
356
|
|
|
298
357
|
#### F5 — Required external access provable
|
|
299
358
|
|
|
@@ -322,7 +381,7 @@ system, and never invent or ask for credentials inline.
|
|
|
322
381
|
|
|
323
382
|
## Execution
|
|
324
383
|
|
|
325
|
-
1. Parse `$ARGUMENTS`. If
|
|
384
|
+
1. Parse `$ARGUMENTS`. Resolve `READY_ROLE` from merged `github.labels.build.ready` config (default `status:ready`). If the input is an issue ref, fetch via `gh issue view --json` and derive the spec fields — including `build_ready` (label set contains the resolved `READY_ROLE`, not a hard-coded label) 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 and preserve the proposed `build_ready` value for S15/F4 normalization.
|
|
326
385
|
2. Confirm `gh auth status` succeeds before any feasibility gate runs.
|
|
327
386
|
3. Run every Specification gate in order. Collect PASS / FAIL / N/A with a one-line reason.
|
|
328
387
|
4. Unless the caller passed `--spec-only`, run every Feasibility gate.
|
|
@@ -25,7 +25,7 @@ org: my-org
|
|
|
25
25
|
repo: my-repo
|
|
26
26
|
summary: "[CU-1.2] Upload contract PDF from settings"
|
|
27
27
|
priority: medium
|
|
28
|
-
parent_ref: "my-org/my-repo#1234" # Parent Epic for
|
|
28
|
+
parent_ref: "my-org/my-repo#1234" # Parent Epic for ordinary children; PRD for an Epic only in the same-repo GitHub self-host shape; Story/etc. for Sub-task
|
|
29
29
|
body: |
|
|
30
30
|
## Context / Business Value
|
|
31
31
|
...
|
|
@@ -63,7 +63,7 @@ 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
|
|
66
|
+
build_ready: true # caller asserts the configured build-ready role (github.labels.build.ready, default status:ready) is/would be applied — see S15
|
|
67
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
|
|
68
68
|
prd_source: "https://notion.so/..." # set when the issue was generated from a PRD — requires the Source Requirement section, see S16
|
|
69
69
|
```
|
|
@@ -213,9 +213,11 @@ This gate depends on S11. It is `N/A` for containers — an **Epic**, or any ite
|
|
|
213
213
|
|
|
214
214
|
#### S15 — Leaf-only build-ready
|
|
215
215
|
|
|
216
|
-
Enforces the build-side of the vendor-neutral `leaf-only-lifecycle` rule: **only a leaf work unit may carry the build-ready role.**
|
|
216
|
+
Enforces the build-side of the vendor-neutral `leaf-only-lifecycle` rule: **only a leaf work unit may carry the build-ready role.** Before evaluating this gate, resolve `READY_ROLE` from merged project config (`.lisa.config.local.json` over `.lisa.config.json`) at `github.labels.build.ready`, defaulting to `status:ready` per `config-resolution`. Use that resolved value everywhere this validator interprets build readiness; a project-specific label is not an alias for the literal default.
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
This is the symmetric write-side guard for the GitHub validator — a stale or hand-applied `READY_ROLE` 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.)
|
|
219
|
+
|
|
220
|
+
**When the gate applies.** Run S15 whenever the issue is build-ready — i.e. `build_ready = true`, or the spec/live labels include the resolved `READY_ROLE`. If the issue is not build-ready, S15 is `N/A` (nothing claims a non-ready issue, so the invariant is vacuous). For example, if `github.labels.build.ready = "queue:approved"`, a container carrying `queue:approved` FAILs S15 even when it does not carry the literal `status:ready` default.
|
|
219
221
|
|
|
220
222
|
**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.
|
|
221
223
|
|
|
@@ -233,7 +235,7 @@ PASS (the childless-parent exception) when the issue is build-ready and is a **l
|
|
|
233
235
|
| Epic | no | yes | **FAIL** (childless Epic — pure rollup container, exception does not apply) |
|
|
234
236
|
| any | any | no | **N/A** (not build-ready) |
|
|
235
237
|
|
|
236
|
-
Remediation: `"Build-ready (status:ready) is leaf-only per leaf-only-lifecycle. Move
|
|
238
|
+
Remediation (render `<READY_ROLE>` as the resolved configured label, never as a hard-coded default): `"Build-ready (<READY_ROLE>; status:ready by default) is leaf-only per leaf-only-lifecycle. Move <READY_ROLE> off this container onto its leaf children (or, for a childless Epic, 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."`
|
|
237
239
|
|
|
238
240
|
`product_relevant: false` — a build-ready container is a lifecycle/decomposition error for the caller to repair, not a product question.
|
|
239
241
|
|
|
@@ -284,8 +286,37 @@ gh issue view <number> --repo <org>/<repo> --json number,labels,state
|
|
|
284
286
|
```
|
|
285
287
|
|
|
286
288
|
Confirm the parent issue exists and:
|
|
287
|
-
|
|
288
|
-
- For
|
|
289
|
+
|
|
290
|
+
- For an `Epic` child, first resolve whether the validator can prove the native PRD-parent shape
|
|
291
|
+
allowed by `prd-lifecycle-rollup`: merged project config has `source = github` and
|
|
292
|
+
`tracker = github`; the spec/live child's `org` and `repo` match configured `github.org` and
|
|
293
|
+
`github.repo`; and `parent_ref` names that same `org/repo`. These facts are available from the
|
|
294
|
+
existing spec/live ref plus project config; do not infer the exception from label spelling alone.
|
|
295
|
+
Only in that proven same-repository GitHub self-host shape may the parent qualify by having one of
|
|
296
|
+
the configured PRD lifecycle labels from
|
|
297
|
+
`github.labels.prd` (`draft`, `ready`, `in_review`, `blocked`, `ticketed`, `shipped`, or
|
|
298
|
+
`verified`; defaults use the `prd-*` namespace). Resolve the configured values from
|
|
299
|
+
`.lisa.config.local.json` over `.lisa.config.json`, using the defaults from `config-resolution`.
|
|
300
|
+
The `sentinel` label is not a lifecycle role and does not qualify. This is the native
|
|
301
|
+
PRD→generated-Epic hierarchy used when GitHub is both source and tracker in one repository; the
|
|
302
|
+
PRD parent does **not** need `type:Epic`. If any self-host/same-repository predicate is false, a
|
|
303
|
+
PRD label does not grant the exception: native hierarchy cannot cross repositories or source
|
|
304
|
+
systems, so a PRD-labelled parent alone FAILs F2.
|
|
305
|
+
- For a `Sub-task` child: the parent has `type:Story`, `type:Task`, `type:Bug`, or
|
|
306
|
+
`type:Improvement` (anything that can host sub-tasks). This allowlist is unchanged; a PRD
|
|
307
|
+
lifecycle label or `type:Epic` alone does not qualify.
|
|
308
|
+
- For every other non-Sub-task child: the parent has `type:Epic`. A PRD lifecycle label alone does
|
|
309
|
+
not qualify, so the Epic→Story (and Epic→ordinary-leaf) hierarchy remains enforced.
|
|
310
|
+
|
|
311
|
+
| child type | relationship shape | qualifying parent label | F2 |
|
|
312
|
+
|---|---|---|---|
|
|
313
|
+
| `Epic` | source GitHub + tracker GitHub + configured child repo = parent repo | configured PRD lifecycle label | **PASS** |
|
|
314
|
+
| `Epic` | cross-repository or source/tracker is not same-repo GitHub | PRD lifecycle label only | **FAIL** |
|
|
315
|
+
| `Epic` | permitted self-host shape | unconfigured `prd-*` lookalike or `prd-intake-feedback` sentinel only | **FAIL** |
|
|
316
|
+
| `Sub-task` | any | `type:Story`, `type:Task`, `type:Bug`, or `type:Improvement` | **PASS** |
|
|
317
|
+
| `Sub-task` | any | PRD lifecycle label or `type:Epic` only | **FAIL** |
|
|
318
|
+
| any other non-Sub-task | any | `type:Epic` | **PASS** |
|
|
319
|
+
| any other non-Sub-task | any | PRD lifecycle label only | **FAIL** |
|
|
289
320
|
|
|
290
321
|
#### F3 — Linked issues exist
|
|
291
322
|
|
|
@@ -293,7 +324,35 @@ For each entry in `links`, run `gh issue view <number> --repo <link-org>/<link-r
|
|
|
293
324
|
|
|
294
325
|
#### F4 — Required labels populated
|
|
295
326
|
|
|
296
|
-
Per `Phase 5` of `lisa-github-write-issue`, every issue MUST carry
|
|
327
|
+
Per `Phase 5` of `lisa-github-write-issue`, every issue MUST carry
|
|
328
|
+
`type:<issue_type>` and `priority:<priority>`. These two labels are unconditional: if either is
|
|
329
|
+
missing from the proposed spec or live issue, FAIL with the missing label name.
|
|
330
|
+
|
|
331
|
+
The `status:*` requirement uses this validator's S15 leaf/container classification while preserving
|
|
332
|
+
the writer's documented `build_ready` control-input defaults:
|
|
333
|
+
|
|
334
|
+
1. Classify the issue structurally using the S15 child-resolution rules. A container (any issue
|
|
335
|
+
with child work, plus a childless `Epic`) may omit `status:*`; its state rolls up rather than
|
|
336
|
+
being assigned directly.
|
|
337
|
+
2. For a proposed leaf spec, normalize omitted `build_ready` to `true`, preserving the writer's
|
|
338
|
+
backward-compatible default-ready behavior. Explicit `build_ready: false` means backlog mode.
|
|
339
|
+
3. For a live issue ref, derive `build_ready` from the labels (`true` exactly when the S15-resolved
|
|
340
|
+
`READY_ROLE` from `github.labels.build.ready`, default `status:ready`, is present). A live backlog leaf without a status label
|
|
341
|
+
therefore validates as `build_ready: false`; live data cannot distinguish an explicit false from
|
|
342
|
+
a historical write that omitted the label.
|
|
343
|
+
4. A leaf with normalized `build_ready: true` MUST carry that same resolved `READY_ROLE`. A leaf with `build_ready: false` may omit
|
|
344
|
+
`status:*`.
|
|
345
|
+
|
|
346
|
+
| classification | normalized build_ready | status label | F4 |
|
|
347
|
+
|---|---:|---|---|
|
|
348
|
+
| container | any | omitted | **PASS** |
|
|
349
|
+
| leaf | `false` | omitted | **PASS** |
|
|
350
|
+
| leaf | `true` | configured build-ready role (`status:ready` by default) | **PASS** |
|
|
351
|
+
| leaf | `true` | omitted or a different `status:*` label | **FAIL** |
|
|
352
|
+
|
|
353
|
+
F4 does not make a container build-ready. S15 remains the independent lifecycle prohibition: any
|
|
354
|
+
container carrying the build-ready role still FAILs S15, even though F4's status-presence check is
|
|
355
|
+
not applicable to containers.
|
|
297
356
|
|
|
298
357
|
#### F5 — Required external access provable
|
|
299
358
|
|
|
@@ -322,7 +381,7 @@ system, and never invent or ask for credentials inline.
|
|
|
322
381
|
|
|
323
382
|
## Execution
|
|
324
383
|
|
|
325
|
-
1. Parse `$ARGUMENTS`. If
|
|
384
|
+
1. Parse `$ARGUMENTS`. Resolve `READY_ROLE` from merged `github.labels.build.ready` config (default `status:ready`). If the input is an issue ref, fetch via `gh issue view --json` and derive the spec fields — including `build_ready` (label set contains the resolved `READY_ROLE`, not a hard-coded label) 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 and preserve the proposed `build_ready` value for S15/F4 normalization.
|
|
326
385
|
2. Confirm `gh auth status` succeeds before any feasibility gate runs.
|
|
327
386
|
3. Run every Specification gate in order. Collect PASS / FAIL / N/A with a one-line reason.
|
|
328
387
|
4. Unless the caller passed `--spec-only`, run every Feasibility gate.
|
|
@@ -25,7 +25,7 @@ org: my-org
|
|
|
25
25
|
repo: my-repo
|
|
26
26
|
summary: "[CU-1.2] Upload contract PDF from settings"
|
|
27
27
|
priority: medium
|
|
28
|
-
parent_ref: "my-org/my-repo#1234" # Parent Epic for
|
|
28
|
+
parent_ref: "my-org/my-repo#1234" # Parent Epic for ordinary children; PRD for an Epic only in the same-repo GitHub self-host shape; Story/etc. for Sub-task
|
|
29
29
|
body: |
|
|
30
30
|
## Context / Business Value
|
|
31
31
|
...
|
|
@@ -63,7 +63,7 @@ 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
|
|
66
|
+
build_ready: true # caller asserts the configured build-ready role (github.labels.build.ready, default status:ready) is/would be applied — see S15
|
|
67
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
|
|
68
68
|
prd_source: "https://notion.so/..." # set when the issue was generated from a PRD — requires the Source Requirement section, see S16
|
|
69
69
|
```
|
|
@@ -213,9 +213,11 @@ This gate depends on S11. It is `N/A` for containers — an **Epic**, or any ite
|
|
|
213
213
|
|
|
214
214
|
#### S15 — Leaf-only build-ready
|
|
215
215
|
|
|
216
|
-
Enforces the build-side of the vendor-neutral `leaf-only-lifecycle` rule: **only a leaf work unit may carry the build-ready role.**
|
|
216
|
+
Enforces the build-side of the vendor-neutral `leaf-only-lifecycle` rule: **only a leaf work unit may carry the build-ready role.** Before evaluating this gate, resolve `READY_ROLE` from merged project config (`.lisa.config.local.json` over `.lisa.config.json`) at `github.labels.build.ready`, defaulting to `status:ready` per `config-resolution`. Use that resolved value everywhere this validator interprets build readiness; a project-specific label is not an alias for the literal default.
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
This is the symmetric write-side guard for the GitHub validator — a stale or hand-applied `READY_ROLE` 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.)
|
|
219
|
+
|
|
220
|
+
**When the gate applies.** Run S15 whenever the issue is build-ready — i.e. `build_ready = true`, or the spec/live labels include the resolved `READY_ROLE`. If the issue is not build-ready, S15 is `N/A` (nothing claims a non-ready issue, so the invariant is vacuous). For example, if `github.labels.build.ready = "queue:approved"`, a container carrying `queue:approved` FAILs S15 even when it does not carry the literal `status:ready` default.
|
|
219
221
|
|
|
220
222
|
**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.
|
|
221
223
|
|
|
@@ -233,7 +235,7 @@ PASS (the childless-parent exception) when the issue is build-ready and is a **l
|
|
|
233
235
|
| Epic | no | yes | **FAIL** (childless Epic — pure rollup container, exception does not apply) |
|
|
234
236
|
| any | any | no | **N/A** (not build-ready) |
|
|
235
237
|
|
|
236
|
-
Remediation: `"Build-ready (status:ready) is leaf-only per leaf-only-lifecycle. Move
|
|
238
|
+
Remediation (render `<READY_ROLE>` as the resolved configured label, never as a hard-coded default): `"Build-ready (<READY_ROLE>; status:ready by default) is leaf-only per leaf-only-lifecycle. Move <READY_ROLE> off this container onto its leaf children (or, for a childless Epic, 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."`
|
|
237
239
|
|
|
238
240
|
`product_relevant: false` — a build-ready container is a lifecycle/decomposition error for the caller to repair, not a product question.
|
|
239
241
|
|
|
@@ -284,8 +286,37 @@ gh issue view <number> --repo <org>/<repo> --json number,labels,state
|
|
|
284
286
|
```
|
|
285
287
|
|
|
286
288
|
Confirm the parent issue exists and:
|
|
287
|
-
|
|
288
|
-
- For
|
|
289
|
+
|
|
290
|
+
- For an `Epic` child, first resolve whether the validator can prove the native PRD-parent shape
|
|
291
|
+
allowed by `prd-lifecycle-rollup`: merged project config has `source = github` and
|
|
292
|
+
`tracker = github`; the spec/live child's `org` and `repo` match configured `github.org` and
|
|
293
|
+
`github.repo`; and `parent_ref` names that same `org/repo`. These facts are available from the
|
|
294
|
+
existing spec/live ref plus project config; do not infer the exception from label spelling alone.
|
|
295
|
+
Only in that proven same-repository GitHub self-host shape may the parent qualify by having one of
|
|
296
|
+
the configured PRD lifecycle labels from
|
|
297
|
+
`github.labels.prd` (`draft`, `ready`, `in_review`, `blocked`, `ticketed`, `shipped`, or
|
|
298
|
+
`verified`; defaults use the `prd-*` namespace). Resolve the configured values from
|
|
299
|
+
`.lisa.config.local.json` over `.lisa.config.json`, using the defaults from `config-resolution`.
|
|
300
|
+
The `sentinel` label is not a lifecycle role and does not qualify. This is the native
|
|
301
|
+
PRD→generated-Epic hierarchy used when GitHub is both source and tracker in one repository; the
|
|
302
|
+
PRD parent does **not** need `type:Epic`. If any self-host/same-repository predicate is false, a
|
|
303
|
+
PRD label does not grant the exception: native hierarchy cannot cross repositories or source
|
|
304
|
+
systems, so a PRD-labelled parent alone FAILs F2.
|
|
305
|
+
- For a `Sub-task` child: the parent has `type:Story`, `type:Task`, `type:Bug`, or
|
|
306
|
+
`type:Improvement` (anything that can host sub-tasks). This allowlist is unchanged; a PRD
|
|
307
|
+
lifecycle label or `type:Epic` alone does not qualify.
|
|
308
|
+
- For every other non-Sub-task child: the parent has `type:Epic`. A PRD lifecycle label alone does
|
|
309
|
+
not qualify, so the Epic→Story (and Epic→ordinary-leaf) hierarchy remains enforced.
|
|
310
|
+
|
|
311
|
+
| child type | relationship shape | qualifying parent label | F2 |
|
|
312
|
+
|---|---|---|---|
|
|
313
|
+
| `Epic` | source GitHub + tracker GitHub + configured child repo = parent repo | configured PRD lifecycle label | **PASS** |
|
|
314
|
+
| `Epic` | cross-repository or source/tracker is not same-repo GitHub | PRD lifecycle label only | **FAIL** |
|
|
315
|
+
| `Epic` | permitted self-host shape | unconfigured `prd-*` lookalike or `prd-intake-feedback` sentinel only | **FAIL** |
|
|
316
|
+
| `Sub-task` | any | `type:Story`, `type:Task`, `type:Bug`, or `type:Improvement` | **PASS** |
|
|
317
|
+
| `Sub-task` | any | PRD lifecycle label or `type:Epic` only | **FAIL** |
|
|
318
|
+
| any other non-Sub-task | any | `type:Epic` | **PASS** |
|
|
319
|
+
| any other non-Sub-task | any | PRD lifecycle label only | **FAIL** |
|
|
289
320
|
|
|
290
321
|
#### F3 — Linked issues exist
|
|
291
322
|
|
|
@@ -293,7 +324,35 @@ For each entry in `links`, run `gh issue view <number> --repo <link-org>/<link-r
|
|
|
293
324
|
|
|
294
325
|
#### F4 — Required labels populated
|
|
295
326
|
|
|
296
|
-
Per `Phase 5` of `lisa-github-write-issue`, every issue MUST carry
|
|
327
|
+
Per `Phase 5` of `lisa-github-write-issue`, every issue MUST carry
|
|
328
|
+
`type:<issue_type>` and `priority:<priority>`. These two labels are unconditional: if either is
|
|
329
|
+
missing from the proposed spec or live issue, FAIL with the missing label name.
|
|
330
|
+
|
|
331
|
+
The `status:*` requirement uses this validator's S15 leaf/container classification while preserving
|
|
332
|
+
the writer's documented `build_ready` control-input defaults:
|
|
333
|
+
|
|
334
|
+
1. Classify the issue structurally using the S15 child-resolution rules. A container (any issue
|
|
335
|
+
with child work, plus a childless `Epic`) may omit `status:*`; its state rolls up rather than
|
|
336
|
+
being assigned directly.
|
|
337
|
+
2. For a proposed leaf spec, normalize omitted `build_ready` to `true`, preserving the writer's
|
|
338
|
+
backward-compatible default-ready behavior. Explicit `build_ready: false` means backlog mode.
|
|
339
|
+
3. For a live issue ref, derive `build_ready` from the labels (`true` exactly when the S15-resolved
|
|
340
|
+
`READY_ROLE` from `github.labels.build.ready`, default `status:ready`, is present). A live backlog leaf without a status label
|
|
341
|
+
therefore validates as `build_ready: false`; live data cannot distinguish an explicit false from
|
|
342
|
+
a historical write that omitted the label.
|
|
343
|
+
4. A leaf with normalized `build_ready: true` MUST carry that same resolved `READY_ROLE`. A leaf with `build_ready: false` may omit
|
|
344
|
+
`status:*`.
|
|
345
|
+
|
|
346
|
+
| classification | normalized build_ready | status label | F4 |
|
|
347
|
+
|---|---:|---|---|
|
|
348
|
+
| container | any | omitted | **PASS** |
|
|
349
|
+
| leaf | `false` | omitted | **PASS** |
|
|
350
|
+
| leaf | `true` | configured build-ready role (`status:ready` by default) | **PASS** |
|
|
351
|
+
| leaf | `true` | omitted or a different `status:*` label | **FAIL** |
|
|
352
|
+
|
|
353
|
+
F4 does not make a container build-ready. S15 remains the independent lifecycle prohibition: any
|
|
354
|
+
container carrying the build-ready role still FAILs S15, even though F4's status-presence check is
|
|
355
|
+
not applicable to containers.
|
|
297
356
|
|
|
298
357
|
#### F5 — Required external access provable
|
|
299
358
|
|
|
@@ -322,7 +381,7 @@ system, and never invent or ask for credentials inline.
|
|
|
322
381
|
|
|
323
382
|
## Execution
|
|
324
383
|
|
|
325
|
-
1. Parse `$ARGUMENTS`. If
|
|
384
|
+
1. Parse `$ARGUMENTS`. Resolve `READY_ROLE` from merged `github.labels.build.ready` config (default `status:ready`). If the input is an issue ref, fetch via `gh issue view --json` and derive the spec fields — including `build_ready` (label set contains the resolved `READY_ROLE`, not a hard-coded label) 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 and preserve the proposed `build_ready` value for S15/F4 normalization.
|
|
326
385
|
2. Confirm `gh auth status` succeeds before any feasibility gate runs.
|
|
327
386
|
3. Run every Specification gate in order. Collect PASS / FAIL / N/A with a one-line reason.
|
|
328
387
|
4. Unless the caller passed `--spec-only`, run every Feasibility gate.
|