@codyswann/lisa 2.104.6 → 2.105.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.
Files changed (46) hide show
  1. package/dist/utils/usage-accounting-rollup.d.ts +13 -0
  2. package/dist/utils/usage-accounting-rollup.d.ts.map +1 -0
  3. package/dist/utils/usage-accounting-rollup.js +46 -0
  4. package/dist/utils/usage-accounting-rollup.js.map +1 -0
  5. package/dist/utils/usage-accounting.d.ts +11 -1
  6. package/dist/utils/usage-accounting.d.ts.map +1 -1
  7. package/dist/utils/usage-accounting.js +23 -6
  8. package/dist/utils/usage-accounting.js.map +1 -1
  9. package/package.json +1 -1
  10. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  11. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  12. package/plugins/lisa/rules/config-resolution.md +7 -19
  13. package/plugins/lisa/rules/prd-lifecycle-rollup.md +16 -15
  14. package/plugins/lisa/scripts/queue-contract-resolution.mjs +0 -20
  15. package/plugins/lisa/skills/confluence-prd-intake/SKILL.md +14 -35
  16. package/plugins/lisa/skills/github-prd-intake/SKILL.md +13 -30
  17. package/plugins/lisa/skills/linear-prd-intake/SKILL.md +14 -32
  18. package/plugins/lisa/skills/notion-prd-intake/SKILL.md +12 -31
  19. package/plugins/lisa/skills/setup-confluence/SKILL.md +1 -1
  20. package/plugins/lisa/skills/verify-prd/SKILL.md +7 -7
  21. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  23. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  25. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  27. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  29. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  31. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  33. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  35. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  37. package/plugins/src/base/rules/config-resolution.md +7 -19
  38. package/plugins/src/base/rules/prd-lifecycle-rollup.md +16 -15
  39. package/plugins/src/base/scripts/queue-contract-resolution.mjs +0 -20
  40. package/plugins/src/base/skills/confluence-prd-intake/SKILL.md +14 -35
  41. package/plugins/src/base/skills/github-prd-intake/SKILL.md +13 -30
  42. package/plugins/src/base/skills/linear-prd-intake/SKILL.md +14 -32
  43. package/plugins/src/base/skills/notion-prd-intake/SKILL.md +12 -31
  44. package/plugins/src/base/skills/setup-confluence/SKILL.md +1 -1
  45. package/plugins/src/base/skills/verify-prd/SKILL.md +7 -7
  46. package/typescript/create-only/.github/workflows/claude.yml +3 -0
@@ -59,26 +59,13 @@ current_role_for_prd() {
59
59
  done
60
60
  echo "unknown"
61
61
  }
62
-
63
- # Resolve a boolean rollup flag. Local overrides global per-key; default when unset.
64
- # NOTE: Confluence rollup config lives under `confluence.rollup` (NOT
65
- # `confluence.parents.rollup`) — see the config-resolution rule.
66
- read_rollup_flag() {
67
- local key="$1" default="$2"
68
- local local_v global_v
69
- local_v=$(jq -r ".confluence.rollup.${key} // empty" .lisa.config.local.json 2>/dev/null)
70
- global_v=$(jq -r ".confluence.rollup.${key} // empty" .lisa.config.json 2>/dev/null)
71
- echo "${local_v:-${global_v:-$default}}"
72
- }
73
-
74
- CLOSE_ON_SHIPPED=$(read_rollup_flag closeOnShipped false)
75
62
  ```
76
63
 
77
64
  In prose below, the role names refer to the resolved parent-page IDs: e.g. "the `ready` parent" means whatever `confluence.parents.ready` resolves to.
78
65
 
79
- This skill is the Confluence counterpart of `lisa:notion-prd-intake`, and shares its PRD closure rollup phase (3f) with `lisa:github-prd-intake` and `lisa:linear-prd-intake`. The phases, gates, comment templates, and rules are identical — the only differences are (1) the lifecycle is encoded as **parent-page placement** instead of a status property, and (2) the fetch / comment / update tools route through `lisa:atlassian-access`. Keep all four intake skills behaviorally aligned: when changing intake logic — including the rollup phase — change them together.
66
+ This skill is the Confluence counterpart of `lisa:notion-prd-intake`, and shares its PRD shipped rollup phase (3f) with `lisa:github-prd-intake` and `lisa:linear-prd-intake`. The phases, gates, comment templates, and rules are identical — the only differences are (1) the lifecycle is encoded as **parent-page placement** instead of a status property, and (2) the fetch / comment / update tools route through `lisa:atlassian-access`. Keep all four intake skills behaviorally aligned: when changing intake logic — including the rollup phase — change them together.
80
67
 
81
- The **PRD closure rollup phase (3f)** re-parents a `ticketed` PRD to the `shipped` parent (and optionally archives it) once all its generated top-level work is terminal, per the `prd-lifecycle-rollup` rule. This is the Confluence leg of the same vendor-neutral rollup that `lisa:github-prd-intake` implements for GitHub (LPC-1.3 #584); only the vendor surface (parent-page placement + documented generated-work section, since Confluence has no native ticket hierarchy) differs.
68
+ The **PRD shipped rollup phase (3f)** re-parents a `ticketed` PRD to the `shipped` parent once all its generated top-level work is terminal, per the `prd-lifecycle-rollup` rule. This is the Confluence leg of the same vendor-neutral rollup that `lisa:github-prd-intake` implements for GitHub (LPC-1.3 #584); only the vendor surface (parent-page placement + documented generated-work section, since Confluence has no native ticket hierarchy) differs.
82
69
 
83
70
  ## Confirmation policy
84
71
 
@@ -118,9 +105,9 @@ This skill transitions:
118
105
  - `in_review` → `blocked` (gate failures or coverage gaps)
119
106
  - `in_review` → `ticketed` (success)
120
107
  - `ticketed` → `blocked` (post-write coverage gaps from Phase 3e)
121
- - `ticketed` → `shipped` (PRD closure rollup, Phase 3f — only when **all** generated top-level children are terminal)
108
+ - `ticketed` → `shipped` (PRD shipped rollup, Phase 3f — only when **all** generated top-level children are terminal)
122
109
 
123
- It never re-parents PRDs into or out of the `draft` or `verified` parents — those parents are owned by product (`verified` is set by `/lisa:verify-prd` after empirical PRD-level acceptance). The `shipped` parent is set by this skill's **rollup phase (3f)** when, and only when, the PRD's generated top-level work is all terminal — per the `prd-lifecycle-rollup` rule; product may also re-parent there by hand. Rollup never advances a PRD to `shipped` on partial completion, and never archives a PRD page unless `confluence.rollup.closeOnShipped` is configured `true` (default `false` re-parent under `shipped`, leave the page active).
110
+ It never re-parents PRDs into or out of the `draft` or `verified` parents — those parents are owned by product (`verified` is set by `/lisa:verify-prd` after empirical PRD-level acceptance). The `shipped` parent is set by this skill's **rollup phase (3f)** when, and only when, the PRD's generated top-level work is all terminal — per the `prd-lifecycle-rollup` rule; product may also re-parent there by hand. Rollup never advances a PRD to `shipped` on partial completion, and never archives a PRD page at shipped. `/lisa:verify-prd` archives the page only after a verified PASS.
124
111
 
125
112
  A "transition" means: update the PRD's `parentId` to the new role's parent-page id via `lisa:atlassian-access` `operation: write-page payload: { id, parentId, title, version: { number: <next> } }`. The v2 PUT endpoint requires the next version number and the page title in the payload; the body content is not strictly required for a re-parent-only edit, but some Atlassian deployments reject PUTs without a body. The skill MUST therefore GET the page first via `read-page`, capture title + current version + current body, then PUT with `parentId` swapped and `version.number` bumped — preserving body content is non-negotiable, this skill never edits PRD content. See `transition_prd` helper in Phase 3a for the canonical implementation.
126
113
 
@@ -297,25 +284,19 @@ Per-ticket gates prove each ticket is well-formed; they do NOT prove the *set* o
297
284
 
298
285
  3. The created tickets remain in the destination tracker regardless of the verdict — they are valid in their own right. The audit only tells us whether *more* are needed.
299
286
 
300
- #### 3f. PRD closure rollup (config-gated)
287
+ #### 3f. PRD shipped rollup
301
288
 
302
289
  A PRD's lifecycle terminal state (`shipped`) is **derived** from whether the work it generated is done — it is never set by hand here on its own authority. This phase implements the Confluence leg of that derivation, per the `prd-lifecycle-rollup` rule (cite it by slug; do not restate its taxonomy or terminal-state semantics here). It is behaviorally identical to `lisa:github-prd-intake`'s Phase 3f — only the vendor surface (parent-page re-parenting via `lisa:atlassian-access` + the documented generated-work section) differs from GitHub's (issue close + labels via `gh`).
303
290
 
304
291
  Rollup runs over PRD pages that are already under the `ticketed` parent (the only state from which a PRD can ship): the freshly-ticketed PRD from Phase 3c, and — because rollup also catches PRDs whose children finished in a *later* cycle — every page currently parented under `$TICKETED_PARENT`. (Re-read its direct children via `lisa:atlassian-access` `operation: read-page-descendants id: $TICKETED_PARENT`.) Process each independently; one PRD never blocks another's rollup.
305
292
 
306
- ##### 3f.0 Resolve closure config
293
+ ##### 3f.0 Shipped remains active for verification
307
294
 
308
- Closure is gated on `confluence.rollup.closeOnShipped` (default `false`), resolved via `read_rollup_flag` (defined in the Workflow resolution block, same local-overrides-global precedence the lifecycle parents use). Note the config lives under `confluence.rollup` (NOT `confluence.parents.rollup`):
309
-
310
- ```bash
311
- CLOSE_ON_SHIPPED=$(read_rollup_flag closeOnShipped false)
312
- ```
313
-
314
- When `false` (the default), rollup re-parents the PRD under `$SHIPPED_PARENT` but leaves the page **active** for a human to archive. When `true`, rollup also archives the page (where the deployment supports archival) after the `shipped` re-parent. Closure NEVER happens before all generated top-level work is terminal (`prd-lifecycle-rollup` rule; PRD #525 non-goal).
295
+ There is no archive configuration at the shipped hop. Rollup re-parents the PRD under `$SHIPPED_PARENT` and leaves the page **active** so Phase 3g can dispatch `/lisa:verify-prd`. Provider-native archival is owned by `/lisa:verify-prd` after it transitions the PRD to the verified parent on a PASS.
315
296
 
316
297
  ##### 3f.1 Idempotency guard (no-op if already shipped)
317
298
 
318
- Rollup is keyed by the PRD's current state. If the PRD is already parented under `$SHIPPED_PARENT` (and is already archived, when `$CLOSE_ON_SHIPPED` is `true`), it is a **no-op** — do not re-parent, do not re-archive, do not re-comment. Record it as `already shipped (no-op)` in the cycle summary and move on. This is what makes re-running intake safe.
299
+ Rollup is keyed by the PRD's current state. If the PRD is already parented under `$SHIPPED_PARENT`, it is a **no-op** — do not re-parent, do not archive, do not re-comment. Record it as `already shipped (no-op)` in the cycle summary and move on. This is what makes re-running intake safe.
319
300
 
320
301
  ##### 3f.2 Read the generated top-level child set
321
302
 
@@ -340,7 +321,7 @@ The set of **required** children for the all-terminal check is the top-level chi
340
321
  **All required children terminal** (every required top-level child is terminal; at least one required child exists):
341
322
 
342
323
  1. Re-parent to `shipped`: `transition_prd "$PRD_ID" shipped` (GET-then-PUT via `lisa:atlassian-access` preserving the body verbatim). After the re-parent, re-read the page and confirm `parentId` matches `$SHIPPED_PARENT` (the single-parent invariant).
343
- 2. **If `$CLOSE_ON_SHIPPED` is `true`**, archive the PRD page where the deployment supports archival. When `false`, leave it active.
324
+ 2. Leave the PRD active for `/lisa:verify-prd`; do not archive at the shipped hop.
344
325
  3. Post a short rollup footer comment via `lisa:atlassian-access` `operation: comment-page kind: footer` naming the terminal child set and (when dropped children exist) the dropped set, so the audit trail records *why* the PRD shipped. Lead with `"Shipped by Claude — all generated top-level work is complete."`
345
326
 
346
327
  **Any required child incomplete / blocked**:
@@ -350,7 +331,7 @@ The set of **required** children for the all-terminal check is the top-level chi
350
331
 
351
332
  ##### 3f.5 Rollup cites the rule
352
333
 
353
- This phase implements exactly one PRD-lifecycle hop — `ticketed → shipped` — and the optional config-gated archive that follows it. All terminal-state semantics, the generated-top-level-work boundary, and the dedupe-by-child-ref idempotency come from the `prd-lifecycle-rollup` rule; this skill is its Confluence implementation, not a second source of truth.
334
+ This phase implements exactly one PRD-lifecycle hop — `ticketed → shipped` — and deliberately leaves native archival to `/lisa:verify-prd` after the verified PASS. All terminal-state semantics, the generated-top-level-work boundary, and the dedupe-by-child-ref idempotency come from the `prd-lifecycle-rollup` rule; this skill is its Confluence implementation, not a second source of truth.
354
335
 
355
336
  #### 3g. PRD verification dispatch (close the loop on shipped PRDs)
356
337
 
@@ -360,7 +341,7 @@ Re-query the PRDs currently parented under the shipped lifecycle parent via `lis
360
341
 
361
342
  **Per-cycle combined bound:** each scheduler cycle dispatches at most one ready PRD (the Phase 3 single-ready-PRD claim) **and** at most one shipped PRD for verification (this Phase 3g dispatch), for a maximum of two PRD operations per cycle. Ready intake runs first (Phase 3), then shipped verify (Phase 3g).
362
343
 
363
- `lisa:verify-prd` owns the outcome: on a CONFORMS verdict with all empirical checks passing it transitions the PRD to the verified parent and posts evidence; on a conformance miss or a failing/unavailable check it **re-parents the PRD shipped → ticketed** (never the blocked parent) and creates **build-ready** fix tickets registered as the PRD's generated work, then posts a failure report — the fix tickets auto-build, rollup (3f) re-ships the PRD once they are terminal, and a later cycle re-verifies (the self-healing loop). Either branch moves the PRD out of the shipped parent, so it is not re-picked this cycle; a PRD whose generated work is not actually terminal is guard-stopped by `lisa:verify-prd` (left under shipped) — that is verify-prd's gate, not this skill's. A PRD archived on ship (`confluence.rollup.closeOnShipped = true`) is out of the open verification queue. This phase, like 3f, is **behaviorally identical across all four intake skills** (`github-prd-intake`, `linear-prd-intake`, `notion-prd-intake`, `confluence-prd-intake`) — only the `$SHIPPED` query surface differs; keep them aligned. Record the dispatched PRD + verify-prd's verdict in the summary.
344
+ `lisa:verify-prd` owns the outcome: on a CONFORMS verdict with all empirical checks passing it transitions the PRD to the verified parent and posts evidence; on a conformance miss or a failing/unavailable check it **re-parents the PRD shipped → ticketed** (never the blocked parent) and creates **build-ready** fix tickets registered as the PRD's generated work, then posts a failure report — the fix tickets auto-build, rollup (3f) re-ships the PRD once they are terminal, and a later cycle re-verifies (the self-healing loop). Either branch moves the PRD out of the shipped parent, so it is not re-picked this cycle; a PRD whose generated work is not actually terminal is guard-stopped by `lisa:verify-prd` (left under shipped) — that is verify-prd's gate, not this skill's. This phase, like 3f, is **behaviorally identical across all four intake skills** (`github-prd-intake`, `linear-prd-intake`, `notion-prd-intake`, `confluence-prd-intake`) — only the `$SHIPPED` query surface differs; keep them aligned. Record the dispatched PRD + verify-prd's verdict in the summary.
364
345
 
365
346
  ### Phase 4 — Summary report
366
347
 
@@ -390,11 +371,11 @@ Print to the agent's output. Do not write this summary to Confluence or the dest
390
371
  ## Idempotency & safety
391
372
 
392
373
  - **One item per cycle**: this skill processes the first eligible ready PRD from Phase 2, then exits. New or remaining PRDs under the `ready` parent are picked up by later scheduler invocations.
393
- - **No writes outside the lifecycle**: this skill only ever writes to the destination tracker via `lisa:confluence-to-tracker` (which delegates to `lisa:tracker-write`), and only ever re-parents PRDs among `in_review`, `blocked`, `ticketed`, and `shipped` (the last via the rollup phase 3f only) via `lisa:atlassian-access` `operation: write-page`. It never edits PRD body content, never re-parents into or out of `draft`, never deletes pages. It re-parents under `shipped` and may archive the PRD page **only** through the config-gated rollup phase (3f).
374
+ - **No writes outside the lifecycle**: this skill only ever writes to the destination tracker via `lisa:confluence-to-tracker` (which delegates to `lisa:tracker-write`), and only ever re-parents PRDs among `in_review`, `blocked`, `ticketed`, and `shipped` (the last via the rollup phase 3f only) via `lisa:atlassian-access` `operation: write-page`. It never edits PRD body content, never re-parents into or out of `draft`, never archives pages at the shipped hop, and never deletes pages.
394
375
  - **Claim-first ordering**: the re-parent to `in_review` happens BEFORE validation runs, so a re-entrant call won't double-process.
395
376
  - **Failure handling**: an exception processing the selected PRD is caught and recorded under "Errors" in the summary, then the cycle exits. The PRD that errored is left under whatever parent it currently occupies (usually `in_review` if claim succeeded) — the human investigates from there.
396
377
  - **Single-parent invariant**: a page has exactly one parent by construction in Confluence — the multi-state ambiguity that label-based systems can hit (two `prd-*` labels simultaneously) cannot occur here. After every transition, re-read the page and confirm `parentId` matches the expected role; if not, surface as an Error and skip.
397
- - **Rollup idempotency**: rollup (Phase 3f) is a no-op on a PRD already parented under `$SHIPPED_PARENT` (and already archived when `closeOnShipped` is `true`) — no duplicate re-parent, no duplicate archive, no duplicate comment. The all-terminal condition is a pure function of the children's current states (deduped by child-ref identity), so recomputing it is safe to re-run. Archival NEVER precedes the all-terminal condition.
378
+ - **Rollup idempotency**: rollup (Phase 3f) is a no-op on a PRD already parented under `$SHIPPED_PARENT` — no duplicate re-parent, no shipped-time archive, no duplicate comment. The all-terminal condition is a pure function of the children's current states (deduped by child-ref identity), so recomputing it is safe to re-run. Native archival only follows verified PASS in `/lisa:verify-prd`.
398
379
 
399
380
  ## Configuration
400
381
 
@@ -413,13 +394,11 @@ Destination tracker config (jira / github / linear) is consumed by `lisa:tracker
413
394
  | `.lisa.config.json` `confluence.parents.ticketed` | yes | Parent page id for "successfully ticketed" |
414
395
  | `.lisa.config.json` `confluence.parents.draft` | recommended | Parent page id for PRDs still being drafted by product |
415
396
  | `.lisa.config.json` `confluence.parents.shipped` | recommended | Parent page id the rollup phase (3f) re-parents delivered PRDs under; product may also use it by hand |
416
- | `.lisa.config.json` `confluence.rollup.closeOnShipped` | no (default `false`) | When `true`, rollup archives the PRD page after the `shipped` re-parent; when `false`, re-parents under `shipped` and leaves the page active |
417
-
418
397
  ## Rules
419
398
 
420
399
  - Never write to the destination tracker outside of `lisa:confluence-to-tracker` → `lisa:tracker-write`. The validator's verdict gates progress; bypassing it produces broken tickets.
421
400
  - Never re-parent a PRD into a lifecycle parent this skill doesn't own (`in_review`, `blocked`, `ticketed`, and `shipped` via the rollup phase only). Product owns `draft` and `ready` (as the entry signal); product and the rollup phase (3f) both re-parent under `shipped`.
422
- - Re-parent under `shipped` (and archive the PRD page when `closeOnShipped` is configured) only from the rollup phase, and only when all generated top-level children are terminal per the `prd-lifecycle-rollup` rule. Never ship or archive on partial completion.
401
+ - Re-parent under `shipped` only from the rollup phase, and only when all generated top-level children are terminal per the `prd-lifecycle-rollup` rule. Never ship on partial completion and never archive at shipped.
423
402
  - Never edit the PRD's body. Communication with product happens only through Confluence comments. The `write-page` call preserves the body verbatim — fetch then PUT with body unchanged.
424
403
  - Never post a single page-level dump of all gate failures. One inline comment per `prd_anchor` group (or one footer summary for unanchored failures only). Comments must be inline-anchored where possible, categorized, plain-language, and contain a concrete recommendation.
425
404
  - Never include a gate ID, internal skill name, or engineering shorthand in a comment body.
@@ -39,7 +39,7 @@ In prose below, the role names refer to the resolved labels: e.g. "the `ready` l
39
39
 
40
40
  This skill is the GitHub counterpart of `lisa:notion-prd-intake`, `lisa:confluence-prd-intake`, and `lisa:linear-prd-intake`. Phases, gates, comment templates, and rules are identical — the only differences are (1) the lifecycle is encoded as **issue labels** (mirroring Linear's project labels and Confluence's page labels), (2) the fetch / update tools are the `gh` CLI, and (3) clarifying-question comments land directly on the source PRD issue (because GitHub Issues *do* have native comments — no sentinel issue required, unlike Linear). Keep all four skills behaviorally aligned: when changing intake logic, change them together.
41
41
 
42
- The **PRD closure rollup phase (3f)** transitions a `$TICKETED` PRD to `$SHIPPED` (and optionally closes it) once all its generated top-level work is terminal, per the `prd-lifecycle-rollup` rule. This phase is GitHub-only here because its vendor surface (issue close + labels via `gh`) is GitHub-specific; the Linear / Confluence / Notion intake skills carry the **same** vendor-neutral rollup with their own surfaces (sibling sub-task #584, now landed). All four intake skills are behaviorally aligned across the rollup phase too — keep them in sync when changing rollup logic.
42
+ The **PRD shipped rollup phase (3f)** transitions a `$TICKETED` PRD to `$SHIPPED` once all its generated top-level work is terminal, per the `prd-lifecycle-rollup` rule. This phase is GitHub-only here because its vendor surface (issue close + labels via `gh`) is GitHub-specific; the Linear / Confluence / Notion intake skills carry the **same** vendor-neutral rollup with their own surfaces (sibling sub-task #584, now landed). All four intake skills are behaviorally aligned across the rollup phase too — keep them in sync when changing rollup logic.
43
43
 
44
44
  ## Confirmation policy
45
45
 
@@ -79,9 +79,9 @@ This skill transitions:
79
79
  - `$IN_REVIEW` → `$BLOCKED` (gate failures or coverage gaps)
80
80
  - `$IN_REVIEW` → `$TICKETED` (success)
81
81
  - `$TICKETED` → `$BLOCKED` (post-write coverage gaps from Phase 3e)
82
- - `$TICKETED` → `$SHIPPED` (PRD closure rollup, Phase 3f — only when **all** generated top-level children are terminal)
82
+ - `$TICKETED` → `$SHIPPED` (PRD shipped rollup, Phase 3f — only when **all** generated top-level children are terminal)
83
83
 
84
- The `draft` and `verified` labels are owned by product and are never touched here (`verified` is set by `/lisa:verify-prd` after empirical PRD-level acceptance). The `shipped` label is set by this skill's **rollup phase (3f)** when, and only when, the PRD's generated top-level work is all terminal — per the `prd-lifecycle-rollup` rule; product may also set it by hand. Rollup never advances a PRD to `shipped` on partial completion, and never closes a PRD issue unless `github.labels.prd.rollup.closeOnShipped` is configured `true` (default `false` set `shipped`, leave open).
84
+ The `draft` and `verified` labels are owned by product and are never touched here (`verified` is set by `/lisa:verify-prd` after empirical PRD-level acceptance). The `shipped` label is set by this skill's **rollup phase (3f)** when, and only when, the PRD's generated top-level work is all terminal — per the `prd-lifecycle-rollup` rule; product may also set it by hand. Rollup never advances a PRD to `shipped` on partial completion, and never closes a PRD issue at shipped. `/lisa:verify-prd` closes the issue only after a verified PASS.
85
85
 
86
86
  A "transition" means: remove the old lifecycle label and add the new one (`gh issue edit <num> --remove-label <old> --add-label <new>`). The skill MUST verify exactly one lifecycle label is present after the update.
87
87
 
@@ -245,34 +245,19 @@ Per-ticket gates prove each ticket is well-formed; they do NOT prove the *set* o
245
245
 
246
246
  3. The created tickets remain in the destination tracker regardless of the verdict. The audit only tells us whether *more* are needed.
247
247
 
248
- #### 3f. PRD closure rollup (config-gated)
248
+ #### 3f. PRD shipped rollup
249
249
 
250
250
  A PRD's lifecycle terminal state (`shipped`) is **derived** from whether the work it generated is done — it is never set by hand here on its own authority. This phase implements the GitHub leg of that derivation, per the `prd-lifecycle-rollup` rule (cite it by slug; do not restate its taxonomy or terminal-state semantics here). Linear / Confluence / Notion rollup is a sibling sub-task (#584) and is out of scope for this skill.
251
251
 
252
252
  Rollup runs over PRD issues that are already `$TICKETED` (the only state from which a PRD can ship): the freshly-ticketed PRD from Phase 3c, and — because rollup also catches PRDs whose children finished in a *later* cycle — every issue currently carrying `$TICKETED`. Process each independently; one PRD never blocks another's rollup.
253
253
 
254
- ##### 3f.0 Resolve closure config
254
+ ##### 3f.0 Shipped remains open for verification
255
255
 
256
- Closure is gated on `github.labels.prd.rollup.closeOnShipped` (default `false`). Resolve it with the same local-overrides-global precedence the lifecycle labels use:
257
-
258
- ```bash
259
- # Resolve a boolean rollup flag. Local overrides global per-key; default when unset.
260
- read_rollup_flag() {
261
- local key="$1" default="$2"
262
- local local_v global_v
263
- local_v=$(jq -r ".github.labels.prd.rollup.${key} // empty" .lisa.config.local.json 2>/dev/null)
264
- global_v=$(jq -r ".github.labels.prd.rollup.${key} // empty" .lisa.config.json 2>/dev/null)
265
- echo "${local_v:-${global_v:-$default}}"
266
- }
267
-
268
- CLOSE_ON_SHIPPED=$(read_rollup_flag closeOnShipped false)
269
- ```
270
-
271
- When `false` (the default), rollup sets `$SHIPPED` but leaves the PRD issue **open** for a human to close. When `true`, rollup also closes the PRD issue after the `$SHIPPED` transition. Closure NEVER happens before all generated top-level work is terminal (`prd-lifecycle-rollup` rule; PRD #525 non-goal).
256
+ There is no close/archive configuration at the shipped hop. Rollup sets `$SHIPPED` and leaves the PRD issue **open** so Phase 3g can dispatch `/lisa:verify-prd`. Provider-native issue closure is owned by `/lisa:verify-prd` after it transitions `$SHIPPED → verified` on a PASS.
272
257
 
273
258
  ##### 3f.1 Idempotency guard (no-op if already shipped)
274
259
 
275
- Rollup is keyed by the PRD's current state. If the PRD already carries `$SHIPPED` (and is already closed, when `$CLOSE_ON_SHIPPED` is `true`), it is a **no-op** — do not re-transition, do not re-close, do not re-comment. Record it as `already shipped (no-op)` in the cycle summary and move on. This is what makes re-running intake safe.
260
+ Rollup is keyed by the PRD's current state. If the PRD already carries `$SHIPPED`, it is a **no-op** — do not re-transition, do not close, do not re-comment. Record it as `already shipped (no-op)` in the cycle summary and move on. This is what makes re-running intake safe.
276
261
 
277
262
  ##### 3f.2 Read the generated top-level child set
278
263
 
@@ -326,7 +311,7 @@ The set of **required** children for the all-terminal check is the top-level chi
326
311
  **All required children terminal** (every required top-level child is terminal; at least one required child exists):
327
312
 
328
313
  1. Transition labels: `gh issue edit <prd-num> --repo <org>/<repo> --remove-label "$TICKETED" --add-label "$SHIPPED"`. Verify exactly one lifecycle label remains (the single-label invariant).
329
- 2. **If `$CLOSE_ON_SHIPPED` is `true`**, close the PRD issue: `gh issue close <prd-num> --repo <org>/<repo> --reason completed`. When `false`, leave it open.
314
+ 2. Leave the PRD issue open for `/lisa:verify-prd`; do not close at the shipped hop.
330
315
  3. Post a short rollup comment naming the terminal child set and (when dropped children exist) the dropped set, so the audit trail records *why* the PRD shipped. Lead with `"Shipped by Claude — all generated top-level work is complete."`
331
316
 
332
317
  **Any required child incomplete / blocked**:
@@ -336,7 +321,7 @@ The set of **required** children for the all-terminal check is the top-level chi
336
321
 
337
322
  ##### 3f.5 Rollup is GitHub-only and cites the rule
338
323
 
339
- This phase only touches GitHub PRD issues. It implements exactly one PRD-lifecycle hop — `$TICKETED → $SHIPPED` — and the optional config-gated close that follows it. All terminal-state semantics, the generated-top-level-work boundary, the env-keyed `done` resolution, and the dedupe-by-child-ref idempotency come from the `prd-lifecycle-rollup` rule; this skill is its GitHub implementation, not a second source of truth.
324
+ This phase only touches GitHub PRD issues. It implements exactly one PRD-lifecycle hop — `$TICKETED → $SHIPPED` — and deliberately leaves native closure to `/lisa:verify-prd` after `$SHIPPED verified`. All terminal-state semantics, the generated-top-level-work boundary, the env-keyed `done` resolution, and the dedupe-by-child-ref idempotency come from the `prd-lifecycle-rollup` rule; this skill is its GitHub implementation, not a second source of truth.
340
325
 
341
326
  #### 3g. PRD verification dispatch (close the loop on shipped PRDs)
342
327
 
@@ -348,8 +333,6 @@ Re-query the PRDs currently carrying `$SHIPPED` via `gh issue list --repo <org>/
348
333
 
349
334
  `lisa:verify-prd` owns the outcome: on a CONFORMS verdict with all empirical checks passing it transitions `$SHIPPED → verified` and posts evidence; on a conformance miss or a failing/unavailable check it **re-opens the PRD `$SHIPPED → ticketed`** (never `blocked`) and creates **build-ready** fix tickets registered as the PRD's generated work, then posts a failure report — the fix tickets auto-build, rollup (3f) re-ships the PRD once they are terminal, and a later cycle re-verifies (the self-healing loop). Either branch moves the PRD out of `$SHIPPED`, so it is not re-picked this cycle; a PRD whose generated work is not actually terminal is guard-stopped by `lisa:verify-prd` (left `$SHIPPED`) — that is verify-prd's gate, not this skill's.
350
335
 
351
- **`closeOnShipped` constraint:** when `github.labels.prd.rollup.closeOnShipped = true`, issues are closed immediately after reaching `$SHIPPED`. This Phase 3g query (`--state open`) will not find them, so those PRDs are permanently excluded from `lisa:verify-prd` dispatch. If PRD verification is required, set `github.labels.prd.rollup.closeOnShipped = false` (or omit it); closing on ship is an explicit opt-out of the shipped→verified verification loop.
352
-
353
336
  This phase, like 3f, is **behaviorally identical across all four intake skills** (`github-prd-intake`, `linear-prd-intake`, `notion-prd-intake`, `confluence-prd-intake`) — only the `$SHIPPED` query surface differs; keep them aligned. Record the dispatched PRD + verify-prd's verdict in the summary.
354
337
 
355
338
  ### Phase 4 — Summary report
@@ -371,7 +354,7 @@ PRDs processed: <n>
371
354
 
372
355
  Rollup (Phase 3f):
373
356
  - $SHIPPED: <n>
374
- - <issue-ref> "<title>" → all <child-count> top-level children terminal (<dropped-count> dropped); closed: <yes|no (closeOnShipped off)>
357
+ - <issue-ref> "<title>" → all <child-count> top-level children terminal (<dropped-count> dropped); left open for verify-prd
375
358
  - Held open (incomplete children): <n>
376
359
  - <issue-ref> "<title>" → <incomplete-count> of <child-count> top-level children still open
377
360
  - Already shipped (no-op): <n>
@@ -394,11 +377,11 @@ When the configured destination tracker is GitHub Issues AND the PRD repo is the
394
377
  ## Idempotency & safety
395
378
 
396
379
  - **One item per cycle**: this skill processes the first eligible ready PRD issue from Phase 2, then exits. New or remaining ready issues are picked up by later scheduler invocations.
397
- - **No writes outside the lifecycle**: this skill only ever writes to the destination tracker via `lisa:github-to-tracker` (which delegates to `lisa:tracker-write`), only ever changes labels among `$IN_REVIEW`, `$BLOCKED`, `$TICKETED`, `$SHIPPED`, only ever comments on the source PRD issue. It never edits PRD bodies and never touches the `draft` label. It sets the `$SHIPPED` label and may close the PRD issue **only** through the config-gated rollup phase (3f), and never deletes any issue.
380
+ - **No writes outside the lifecycle**: this skill only ever writes to the destination tracker via `lisa:github-to-tracker` (which delegates to `lisa:tracker-write`), only ever changes labels among `$IN_REVIEW`, `$BLOCKED`, `$TICKETED`, `$SHIPPED`, only ever comments on the source PRD issue. It never edits PRD bodies, never touches the `draft` label, never closes PRD issues at the shipped hop, and never deletes any issue.
398
381
  - **Claim-first ordering**: the label flip to `$IN_REVIEW` happens BEFORE validation runs.
399
382
  - **Failure handling**: an exception processing the selected PRD is caught and recorded under "Errors" in the summary, then the cycle exits. The PRD that errored is left labeled `$IN_REVIEW` — humans investigate from there.
400
383
  - **Single-label invariant**: after every transition, verify exactly one lifecycle label is present.
401
- - **Rollup idempotency**: rollup (Phase 3f) is a no-op on a PRD already carrying `$SHIPPED` (and already closed when `closeOnShipped` is `true`) — no duplicate transition, no duplicate close, no duplicate comment. The all-terminal condition is a pure function of the children's current states, so recomputing it is safe to re-run. Closure NEVER precedes the all-terminal condition.
384
+ - **Rollup idempotency**: rollup (Phase 3f) is a no-op on a PRD already carrying `$SHIPPED` — no duplicate transition, no shipped-time close, no duplicate comment. The all-terminal condition is a pure function of the children's current states, so recomputing it is safe to re-run. Native closure only follows verified PASS in `/lisa:verify-prd`.
402
385
 
403
386
  ## Configuration
404
387
 
@@ -421,7 +404,7 @@ Destination tracker config (jira / github / linear) is consumed by `lisa:tracker
421
404
 
422
405
  - Never write to the destination tracker outside of `lisa:github-to-tracker` → `lisa:tracker-write`.
423
406
  - Never add or remove a label this skill doesn't own (`$IN_REVIEW`, `$BLOCKED`, `$TICKETED`, and `$SHIPPED` via the rollup phase only). Product owns the `draft` and `ready` PRD labels; product and the rollup phase (3f) both set `shipped`.
424
- - Set `$SHIPPED` (and close the PRD when `closeOnShipped` is configured) only from the rollup phase, and only when all generated top-level children are terminal per the `prd-lifecycle-rollup` rule. Never ship or close on partial completion.
407
+ - Set `$SHIPPED` only from the rollup phase, and only when all generated top-level children are terminal per the `prd-lifecycle-rollup` rule. Never ship on partial completion and never close at shipped.
425
408
  - Never edit a PRD's body. Communication with product happens only via comments.
426
409
  - Never post a single dump of all gate failures on one comment. One comment per `prd_anchor` group, plus one rollup for unanchored failures.
427
410
  - Never include a gate ID, internal skill name, or engineering shorthand in a comment body.
@@ -34,24 +34,13 @@ BLOCKED=$(read_role blocked "prd-blocked")
34
34
  TICKETED=$(read_role ticketed "prd-ticketed")
35
35
  SHIPPED=$(read_role shipped "prd-shipped")
36
36
  SENTINEL=$(read_role sentinel "prd-intake-feedback")
37
-
38
- # Resolve a boolean rollup flag. Local overrides global per-key; default when unset.
39
- read_rollup_flag() {
40
- local key="$1" default="$2"
41
- local local_v global_v
42
- local_v=$(jq -r ".linear.labels.prd.rollup.${key} // empty" .lisa.config.local.json 2>/dev/null)
43
- global_v=$(jq -r ".linear.labels.prd.rollup.${key} // empty" .lisa.config.json 2>/dev/null)
44
- echo "${local_v:-${global_v:-$default}}"
45
- }
46
-
47
- CLOSE_ON_SHIPPED=$(read_rollup_flag closeOnShipped false)
48
37
  ```
49
38
 
50
39
  In prose below, the role names refer to the resolved labels: e.g. "the `ready` label" means whatever `linear.labels.prd.ready` resolves to (default: `prd-ready`).
51
40
 
52
- This skill is the Linear counterpart of `lisa:notion-prd-intake` and `lisa:confluence-prd-intake`, and shares its PRD closure rollup phase (3f) with `lisa:github-prd-intake`. The phases, gates, comment templates, and rules are identical — the only differences are (1) the lifecycle is encoded as **project labels** instead of a status property, (2) the fetch / update tools are Linear MCP, and (3) clarifying-question comments land on a sentinel feedback Issue under the project (because Linear's MCP does not expose project-level comments). Keep all four intake skills behaviorally aligned: when changing intake logic — including the rollup phase — change them together.
41
+ This skill is the Linear counterpart of `lisa:notion-prd-intake` and `lisa:confluence-prd-intake`, and shares its PRD shipped rollup phase (3f) with `lisa:github-prd-intake`. The phases, gates, comment templates, and rules are identical — the only differences are (1) the lifecycle is encoded as **project labels** instead of a status property, (2) the fetch / update tools are Linear MCP, and (3) clarifying-question comments land on a sentinel feedback Issue under the project (because Linear's MCP does not expose project-level comments). Keep all four intake skills behaviorally aligned: when changing intake logic — including the rollup phase — change them together.
53
42
 
54
- The **PRD closure rollup phase (3f)** transitions a `$TICKETED` PRD project to `$SHIPPED` (and optionally closes/archives it) once all its generated top-level work is terminal, per the `prd-lifecycle-rollup` rule. This is the Linear leg of the same vendor-neutral rollup that `lisa:github-prd-intake` implements for GitHub (LPC-1.3 #584); only the vendor surface (Linear workflow states + project labels) differs.
43
+ The **PRD shipped rollup phase (3f)** transitions a `$TICKETED` PRD project to `$SHIPPED` once all its generated top-level work is terminal, per the `prd-lifecycle-rollup` rule. This is the Linear leg of the same vendor-neutral rollup that `lisa:github-prd-intake` implements for GitHub (LPC-1.3 #584); only the vendor surface (Linear workflow states + project labels) differs.
55
44
 
56
45
  ## Confirmation policy
57
46
 
@@ -89,9 +78,9 @@ This skill transitions:
89
78
  - `$IN_REVIEW` → `$BLOCKED` (gate failures or coverage gaps)
90
79
  - `$IN_REVIEW` → `$TICKETED` (success)
91
80
  - `$TICKETED` → `$BLOCKED` (post-write coverage gaps from Phase 3e)
92
- - `$TICKETED` → `$SHIPPED` (PRD closure rollup, Phase 3f — only when **all** generated top-level children are terminal)
81
+ - `$TICKETED` → `$SHIPPED` (PRD shipped rollup, Phase 3f — only when **all** generated top-level children are terminal)
93
82
 
94
- It never touches the `draft` or `verified` labels — those labels are owned by product (`verified` is set by `/lisa:verify-prd` after empirical PRD-level acceptance). The `shipped` label is set by this skill's **rollup phase (3f)** when, and only when, the PRD project's generated top-level work is all terminal — per the `prd-lifecycle-rollup` rule; product may also set it by hand. Rollup never advances a PRD to `shipped` on partial completion, and never archives a PRD project unless `linear.labels.prd.rollup.closeOnShipped` is configured `true` (default `false` set `shipped`, leave the project active).
83
+ It never touches the `draft` or `verified` labels — those labels are owned by product (`verified` is set by `/lisa:verify-prd` after empirical PRD-level acceptance). The `shipped` label is set by this skill's **rollup phase (3f)** when, and only when, the PRD project's generated top-level work is all terminal — per the `prd-lifecycle-rollup` rule; product may also set it by hand. Rollup never advances a PRD to `shipped` on partial completion, and never archives a PRD project at shipped. `/lisa:verify-prd` archives or completes the project only after a verified PASS.
95
84
 
96
85
  A "transition" means: remove the old lifecycle label and add the new one in a single `save_project` call (passing the full new label set in the `labels` array). The skill MUST verify that exactly one lifecycle label exists on the project after the update — having two simultaneously breaks idempotency.
97
86
 
@@ -239,25 +228,19 @@ Per-ticket gates prove each ticket is well-formed; they do NOT prove the *set* o
239
228
 
240
229
  3. The created tickets remain in the destination tracker regardless of the verdict — they are valid in their own right. The audit only tells us whether *more* are needed.
241
230
 
242
- #### 3f. PRD closure rollup (config-gated)
231
+ #### 3f. PRD shipped rollup
243
232
 
244
233
  A PRD's lifecycle terminal state (`shipped`) is **derived** from whether the work it generated is done — it is never set by hand here on its own authority. This phase implements the Linear leg of that derivation, per the `prd-lifecycle-rollup` rule (cite it by slug; do not restate its taxonomy or terminal-state semantics here). It is behaviorally identical to `lisa:github-prd-intake`'s Phase 3f — only the vendor surface (Linear workflow states + project labels via Linear MCP) differs from GitHub's (issue close + labels via `gh`).
245
234
 
246
235
  Rollup runs over PRD projects that are already `$TICKETED` (the only state from which a PRD can ship): the freshly-ticketed project from Phase 3c, and — because rollup also catches PRDs whose children finished in a *later* cycle — every project currently carrying `$TICKETED`. Process each independently; one PRD never blocks another's rollup.
247
236
 
248
- ##### 3f.0 Resolve closure config
249
-
250
- Closure is gated on `linear.labels.prd.rollup.closeOnShipped` (default `false`), resolved via `read_rollup_flag` (defined in the Workflow resolution block, same local-overrides-global precedence the lifecycle labels use):
251
-
252
- ```bash
253
- CLOSE_ON_SHIPPED=$(read_rollup_flag closeOnShipped false)
254
- ```
237
+ ##### 3f.0 Shipped remains active for verification
255
238
 
256
- When `false` (the default), rollup sets `$SHIPPED` but leaves the PRD project **active** for a human to archive. When `true`, rollup also moves the project to a closed/archived state after the `$SHIPPED` transition. Closure NEVER happens before all generated top-level work is terminal (`prd-lifecycle-rollup` rule; PRD #525 non-goal).
239
+ There is no close/archive configuration at the shipped hop. Rollup sets `$SHIPPED` and leaves the PRD project **active** so Phase 3g can dispatch `/lisa:verify-prd`. Provider-native archive/completion is owned by `/lisa:verify-prd` after it transitions `$SHIPPED verified` on a PASS.
257
240
 
258
241
  ##### 3f.1 Idempotency guard (no-op if already shipped)
259
242
 
260
- Rollup is keyed by the PRD's current state. If the PRD project already carries `$SHIPPED` (and is already archived, when `$CLOSE_ON_SHIPPED` is `true`), it is a **no-op** — do not re-transition, do not re-archive, do not re-comment. Record it as `already shipped (no-op)` in the cycle summary and move on. This is what makes re-running intake safe.
243
+ Rollup is keyed by the PRD's current state. If the PRD project already carries `$SHIPPED`, it is a **no-op** — do not re-transition, do not archive, do not re-comment. Record it as `already shipped (no-op)` in the cycle summary and move on. This is what makes re-running intake safe.
261
244
 
262
245
  ##### 3f.2 Read the generated top-level child set
263
246
 
@@ -284,7 +267,7 @@ The set of **required** children for the all-terminal check is the top-level chi
284
267
  **All required children terminal** (every required top-level child is terminal; at least one required child exists):
285
268
 
286
269
  1. Transition labels: remove `$TICKETED`, add `$SHIPPED` via `mcp__linear-server__save_project({id, labels})`. Verify exactly one lifecycle label remains (the single-label invariant).
287
- 2. **If `$CLOSE_ON_SHIPPED` is `true`**, move the PRD project to a closed/archived state via `save_project` (set the project to a completed/canceled state or archive it). When `false`, leave it active.
270
+ 2. Leave the PRD active for `/lisa:verify-prd`; do not archive at the shipped hop.
288
271
  3. Post a short rollup comment on the sentinel feedback issue naming the terminal child set and (when dropped children exist) the dropped set, so the audit trail records *why* the PRD shipped. Lead with `"Shipped by Claude — all generated top-level work is complete."`
289
272
 
290
273
  **Any required child incomplete / blocked**:
@@ -294,13 +277,13 @@ The set of **required** children for the all-terminal check is the top-level chi
294
277
 
295
278
  ##### 3f.5 Rollup cites the rule
296
279
 
297
- This phase implements exactly one PRD-lifecycle hop — `$TICKETED → $SHIPPED` — and the optional config-gated archive that follows it. All terminal-state semantics, the generated-top-level-work boundary, and the dedupe-by-child-ref idempotency come from the `prd-lifecycle-rollup` rule; this skill is its Linear implementation, not a second source of truth.
280
+ This phase implements exactly one PRD-lifecycle hop — `$TICKETED → $SHIPPED` — and deliberately leaves native archive/completion to `/lisa:verify-prd` after `$SHIPPED → verified`. All terminal-state semantics, the generated-top-level-work boundary, and the dedupe-by-child-ref idempotency come from the `prd-lifecycle-rollup` rule; this skill is its Linear implementation, not a second source of truth.
298
281
 
299
282
  #### 3g. PRD verification dispatch (close the loop on shipped PRDs)
300
283
 
301
284
  `shipped` and `verified` are distinct facts about a PRD (see the `prd-lifecycle-rollup` rule's "PRD-level verification vs ticket verification" and "Closing the loop" sections). Rollup (3f) only reaches `$SHIPPED`; the `shipped → verified` (pass) / `shipped → ticketed` (fail) hops are owned by `/lisa:verify-prd`. This phase **closes that loop** by dispatching the initiative-level acceptance gate for shipped PRDs. It never performs the verification transition itself — the "never sets the verification outcome" invariant holds: `lisa:verify-prd`, not this skill, sets `verified` (or, on failure, re-opens the PRD to `ticketed`).
302
285
 
303
- Re-query the projects currently carrying the `$SHIPPED` label via `mcp__linear-server__list_projects` (filtered by the `$SHIPPED` project label, **including archived projects** — so PRDs archived on ship via `linear.labels.prd.rollup.closeOnShipped = true` are still dispatched to `lisa:verify-prd` for the shipped→verified progression). Pick the **first** one and invoke `lisa:verify-prd <project-url>`. Process **one shipped PRD per cycle** — `lisa:verify-prd` is a heavy full flow (spec-conformance + empirical verification + fix-issue creation), so it is bounded exactly like the single-ready-PRD claim in Phase 3; the scheduler drains the rest.
286
+ Re-query the projects currently carrying the `$SHIPPED` label via `mcp__linear-server__list_projects` (filtered by the `$SHIPPED` project label, **including archived projects** — so shipped PRDs remain active for `lisa:verify-prd`). Pick the **first** one and invoke `lisa:verify-prd <project-url>`. Process **one shipped PRD per cycle** — `lisa:verify-prd` is a heavy full flow (spec-conformance + empirical verification + fix-issue creation), so it is bounded exactly like the single-ready-PRD claim in Phase 3; the scheduler drains the rest.
304
287
 
305
288
  **Per-cycle combined bound:** each scheduler cycle dispatches at most one ready PRD (the Phase 3 single-ready-PRD claim) **and** at most one shipped PRD for verification (this Phase 3g dispatch), for a maximum of two PRD operations per cycle. Ready intake runs first (Phase 3), then shipped verify (Phase 3g).
306
289
 
@@ -352,11 +335,11 @@ Idempotency: the helper finds-or-creates. Re-runs of the cycle reuse the same se
352
335
  ## Idempotency & safety
353
336
 
354
337
  - **One item per cycle**: this skill processes the first eligible ready project from Phase 2, then exits. New or remaining `$READY` projects are picked up by later scheduler invocations.
355
- - **No writes outside the lifecycle**: this skill only ever writes to the destination tracker via `lisa:linear-to-tracker` (which delegates to `lisa:tracker-write`), only ever changes Linear project labels among `$IN_REVIEW`, `$BLOCKED`, `$TICKETED`, and `$SHIPPED` (the last via the rollup phase 3f only), only ever creates/comments on the sentinel feedback issue (never any other Linear issue). It never edits project descriptions, never edits Linear documents, never touches the `draft` label, and never deletes projects. It sets the `$SHIPPED` label and may archive the PRD project **only** through the config-gated rollup phase (3f).
338
+ - **No writes outside the lifecycle**: this skill only ever writes to the destination tracker via `lisa:linear-to-tracker` (which delegates to `lisa:tracker-write`), only ever changes Linear project labels among `$IN_REVIEW`, `$BLOCKED`, `$TICKETED`, and `$SHIPPED` (the last via the rollup phase 3f only), only ever creates/comments on the sentinel feedback issue (never any other Linear issue). It never edits project descriptions, never edits Linear documents, never touches the `draft` label, never archives projects at the shipped hop, and never deletes projects.
356
339
  - **Claim-first ordering**: the label flip to `$IN_REVIEW` happens BEFORE validation runs, so a re-entrant call won't double-process.
357
340
  - **Failure handling**: an exception processing the selected project is caught and recorded under "Errors" in the summary, then the cycle exits. The project that errored is left labelled `$IN_REVIEW` — the human investigates from there.
358
341
  - **Single-label invariant**: after every transition, verify exactly one lifecycle label is present on the project. If two are present (rare race), surface as an Error and skip — do NOT auto-resolve, the human decides.
359
- - **Rollup idempotency**: rollup (Phase 3f) is a no-op on a PRD project already carrying `$SHIPPED` (and already archived when `closeOnShipped` is `true`) — no duplicate transition, no duplicate archive, no duplicate comment. The all-terminal condition is a pure function of the children's current states (deduped by child-ref identity), so recomputing it is safe to re-run. Archival NEVER precedes the all-terminal condition.
342
+ - **Rollup idempotency**: rollup (Phase 3f) is a no-op on a PRD project already carrying `$SHIPPED` — no duplicate transition, no shipped-time archive, no duplicate comment. The all-terminal condition is a pure function of the children's current states (deduped by child-ref identity), so recomputing it is safe to re-run. Native archive/completion only follows verified PASS in `/lisa:verify-prd`.
360
343
 
361
344
  ## Configuration
362
345
 
@@ -374,14 +357,13 @@ Destination tracker config (jira / github / linear) is consumed by `lisa:tracker
374
357
  | `.lisa.config.json` `linear.labels.prd.blocked` | `prd-blocked` | Project label set on validation failure |
375
358
  | `.lisa.config.json` `linear.labels.prd.ticketed` | `prd-ticketed` | Project label set on success |
376
359
  | `.lisa.config.json` `linear.labels.prd.shipped` | `prd-shipped` | Project label set by the rollup phase (3f) when all generated top-level work is terminal; product may also set it by hand |
377
- | `.lisa.config.json` `linear.labels.prd.rollup.closeOnShipped` | `false` | When `true`, rollup archives the PRD project after the `$SHIPPED` transition; when `false`, sets `$SHIPPED` and leaves it active |
378
360
  | `.lisa.config.json` `linear.labels.prd.sentinel` | `prd-intake-feedback` | Issue-level label marking the sentinel feedback issue |
379
361
 
380
362
  ## Rules
381
363
 
382
364
  - Never write to the destination tracker outside of `lisa:linear-to-tracker` → `lisa:tracker-write`. The validator's verdict gates progress; bypassing it produces broken tickets.
383
365
  - Never add or remove a label this skill doesn't own (`$IN_REVIEW`, `$BLOCKED`, `$TICKETED`, and `$SHIPPED` via the rollup phase only). Product owns the `draft` and `ready` labels; product and the rollup phase (3f) both set `shipped`. The issue-level `$SENTINEL` label is owned by this skill but is not a lifecycle label.
384
- - Set `$SHIPPED` (and archive the PRD project when `closeOnShipped` is configured) only from the rollup phase, and only when all generated top-level children are terminal per the `prd-lifecycle-rollup` rule. Never ship or archive on partial completion.
366
+ - Set `$SHIPPED` only from the rollup phase, and only when all generated top-level children are terminal per the `prd-lifecycle-rollup` rule. Never ship on partial completion and never archive at shipped.
385
367
  - Never edit a project's description or any attached Linear document. Communication with product happens only through comments on sub-issues or on the sentinel feedback issue.
386
368
  - Never post a single dump of all gate failures on one comment. One comment per `prd_anchor` group on the relevant sub-issue (or one comment on the sentinel feedback issue for unanchored failures only). Comments must be sub-issue-anchored where possible, categorized, plain-language, and contain a concrete recommendation.
387
369
  - Never include a gate ID, internal skill name, or engineering shorthand in a comment body.
@@ -37,22 +37,11 @@ BLOCKED=$(read_role blocked "Blocked")
37
37
  TICKETED=$(read_role ticketed "Ticketed")
38
38
  SHIPPED=$(read_role shipped "Shipped")
39
39
  STATUS_PROP=$(jq -r '.notion.statusProperty // "Status"' .lisa.config.json 2>/dev/null)
40
-
41
- # Resolve a boolean rollup flag. Local overrides global per-key; default when unset.
42
- read_rollup_flag() {
43
- local key="$1" default="$2"
44
- local local_v global_v
45
- local_v=$(jq -r ".notion.rollup.${key} // empty" .lisa.config.local.json 2>/dev/null)
46
- global_v=$(jq -r ".notion.rollup.${key} // empty" .lisa.config.json 2>/dev/null)
47
- echo "${local_v:-${global_v:-$default}}"
48
- }
49
-
50
- CLOSE_ON_SHIPPED=$(read_rollup_flag closeOnShipped false)
51
40
  ```
52
41
 
53
42
  In prose below, the role names refer to the resolved values: e.g. "the `ready` status" means whatever `notion.values.ready` resolves to (default: `Ready`).
54
43
 
55
- This skill shares its PRD closure rollup phase (3f) with `lisa:github-prd-intake`, `lisa:linear-prd-intake`, and `lisa:confluence-prd-intake`. The phases, gates, comment templates, and rollup behavior are identical across all four intake skills — only the vendor surface differs. Keep all four behaviorally aligned: when changing intake logic — including the rollup phase — change them together. The **PRD closure rollup phase (3f)** transitions a `$TICKETED` PRD to `$SHIPPED` (and optionally archives it) once all its generated top-level work is terminal, per the `prd-lifecycle-rollup` rule; this is the Notion leg of the same vendor-neutral rollup (LPC-1.3 #584), using the documented generated-work section since Notion has no native ticket hierarchy.
44
+ This skill shares its PRD shipped rollup phase (3f) with `lisa:github-prd-intake`, `lisa:linear-prd-intake`, and `lisa:confluence-prd-intake`. The phases, gates, comment templates, and rollup behavior are identical across all four intake skills — only the vendor surface differs. Keep all four behaviorally aligned: when changing intake logic — including the rollup phase — change them together. The **PRD shipped rollup phase (3f)** transitions a `$TICKETED` PRD to `$SHIPPED` once all its generated top-level work is terminal, per the `prd-lifecycle-rollup` rule; this is the Notion leg of the same vendor-neutral rollup (LPC-1.3 #584), using the documented generated-work section since Notion has no native ticket hierarchy.
56
45
 
57
46
  ## Confirmation policy
58
47
 
@@ -84,7 +73,7 @@ draft → ready → in_review → blocked | ticketed → shipped → verified
84
73
 
85
74
  `verified` is the terminal status after `shipped`: it means the shipped product has been empirically checked against the PRD (set by `/lisa:verify-prd`, not by this intake skill). A failed post-ship verification does **not** use `blocked`; `/lisa:verify-prd` re-opens the PRD `shipped → ticketed` and creates build-ready fix tickets that auto-build and trigger a re-verify (the self-healing loop), introducing no `verifying` / `verification-failed` status. Like `draft` and `shipped`, `verified` is **product-owned** — this intake skill never sets, clears, or otherwise touches it. See the "PRD-level verification vs ticket verification" section of the `prd-lifecycle-rollup` rule.
86
75
 
87
- This skill transitions `ready → in_review`, then `in_review → blocked` or `in_review → ticketed`, then (via the rollup phase 3f) `ticketed → shipped`. It never touches `draft` or `verified` — those statuses are owned by product (`verified` is set by `/lisa:verify-prd` after empirical PRD-level acceptance). The `shipped` status is set by this skill's **rollup phase (3f)** when, and only when, the PRD's generated top-level work is all terminal — per the `prd-lifecycle-rollup` rule; product may also set it by hand. Rollup never advances a PRD to `shipped` on partial completion, and never archives a PRD page unless `notion.rollup.closeOnShipped` is configured `true` (default `false` set `$SHIPPED`, leave the page active).
76
+ This skill transitions `ready → in_review`, then `in_review → blocked` or `in_review → ticketed`, then (via the rollup phase 3f) `ticketed → shipped`. It never touches `draft` or `verified` — those statuses are owned by product (`verified` is set by `/lisa:verify-prd` after empirical PRD-level acceptance). The `shipped` status is set by this skill's **rollup phase (3f)** when, and only when, the PRD's generated top-level work is all terminal — per the `prd-lifecycle-rollup` rule; product may also set it by hand. Rollup never advances a PRD to `shipped` on partial completion, and never archives a PRD page at shipped. `/lisa:verify-prd` archives the page only after a verified PASS.
88
77
 
89
78
  ## Phases
90
79
 
@@ -243,25 +232,19 @@ The access skill resolves a `prd_anchor` substring to the matching block ID by p
243
232
 
244
233
  Stop immediately after the claimed PRD is ticketed, blocked, or recorded as an error.
245
234
 
246
- #### 3f. PRD closure rollup (config-gated)
235
+ #### 3f. PRD shipped rollup
247
236
 
248
237
  A PRD's lifecycle terminal state (`shipped`) is **derived** from whether the work it generated is done — it is never set by hand here on its own authority. This phase implements the Notion leg of that derivation, per the `prd-lifecycle-rollup` rule (cite it by slug; do not restate its taxonomy or terminal-state semantics here). It is behaviorally identical to `lisa:github-prd-intake`'s Phase 3f — only the vendor surface (a Notion status property via `lisa:notion-access` + the documented generated-work section) differs from GitHub's (issue close + labels via `gh`).
249
238
 
250
239
  Rollup runs over PRD pages that are already `$TICKETED` (the only state from which a PRD can ship): the freshly-ticketed PRD from Phase 3c, and — because rollup also catches PRDs whose children finished in a *later* cycle — every page currently in `$STATUS_PROP = $TICKETED` (re-query the database with operation `query-database` filtered on the ticketed status). Process each independently; one PRD never blocks another's rollup.
251
240
 
252
- ##### 3f.0 Resolve closure config
241
+ ##### 3f.0 Shipped remains active for verification
253
242
 
254
- Closure is gated on `notion.rollup.closeOnShipped` (default `false`), resolved via `read_rollup_flag` (defined in the Workflow resolution block, same local-overrides-global precedence the status values use):
255
-
256
- ```bash
257
- CLOSE_ON_SHIPPED=$(read_rollup_flag closeOnShipped false)
258
- ```
259
-
260
- When `false` (the default), rollup sets `$STATUS_PROP = $SHIPPED` but leaves the page **active** for a human to archive. When `true`, rollup also archives the page (where Notion supports archival) after the `shipped` transition. Closure NEVER happens before all generated top-level work is terminal (`prd-lifecycle-rollup` rule; PRD #525 non-goal).
243
+ There is no archive configuration at the shipped hop. Rollup sets `$STATUS_PROP = $SHIPPED` and leaves the PRD page **active** so Phase 3g can dispatch `/lisa:verify-prd`. Provider-native archival is owned by `/lisa:verify-prd` after it transitions `$SHIPPED → verified` on a PASS.
261
244
 
262
245
  ##### 3f.1 Idempotency guard (no-op if already shipped)
263
246
 
264
- Rollup is keyed by the PRD's current state. If the PRD already has `$STATUS_PROP = $SHIPPED` (and is already archived, when `$CLOSE_ON_SHIPPED` is `true`), it is a **no-op** — do not re-transition, do not re-archive, do not re-comment. Record it as `already shipped (no-op)` in the cycle summary and move on. This is what makes re-running intake safe.
247
+ Rollup is keyed by the PRD's current state. If the PRD already has `$STATUS_PROP = $SHIPPED`, it is a **no-op** — do not re-transition, do not archive, do not re-comment. Record it as `already shipped (no-op)` in the cycle summary and move on. This is what makes re-running intake safe.
265
248
 
266
249
  ##### 3f.2 Read the generated top-level child set
267
250
 
@@ -286,7 +269,7 @@ The set of **required** children for the all-terminal check is the top-level chi
286
269
  **All required children terminal** (every required top-level child is terminal; at least one required child exists):
287
270
 
288
271
  1. Set `$STATUS_PROP = $SHIPPED` by invoking `lisa:notion-access` operation `write-page` with payload `{ "id": "<PRD-page-id>", "properties": { "<STATUS_PROP>": { "status": { "name": "<SHIPPED>" } } } }` (use `"select"` instead of `"status"` if the property is a select).
289
- 2. **If `$CLOSE_ON_SHIPPED` is `true`**, archive the PRD page via `lisa:notion-access` (set `archived: true` where supported). When `false`, leave it active.
272
+ 2. Leave the PRD active for `/lisa:verify-prd`; do not archive at the shipped hop.
290
273
  3. Post a short rollup Notion comment naming the terminal child set and (when dropped children exist) the dropped set, so the audit trail records *why* the PRD shipped. Lead with `"Shipped by Claude — all generated top-level work is complete."`
291
274
 
292
275
  **Any required child incomplete / blocked**:
@@ -296,7 +279,7 @@ The set of **required** children for the all-terminal check is the top-level chi
296
279
 
297
280
  ##### 3f.5 Rollup cites the rule
298
281
 
299
- This phase implements exactly one PRD-lifecycle hop — `$TICKETED → $SHIPPED` — and the optional config-gated archive that follows it. All terminal-state semantics, the generated-top-level-work boundary, and the dedupe-by-child-ref idempotency come from the `prd-lifecycle-rollup` rule; this skill is its Notion implementation, not a second source of truth.
282
+ This phase implements exactly one PRD-lifecycle hop — `$TICKETED → $SHIPPED` — and deliberately leaves native archival to `/lisa:verify-prd` after `$SHIPPED verified`. All terminal-state semantics, the generated-top-level-work boundary, and the dedupe-by-child-ref idempotency come from the `prd-lifecycle-rollup` rule; this skill is its Notion implementation, not a second source of truth.
300
283
 
301
284
  #### 3g. PRD verification dispatch (close the loop on shipped PRDs)
302
285
 
@@ -306,7 +289,7 @@ Re-query the PRDs currently in the `$SHIPPED` status via `lisa:notion-access` `o
306
289
 
307
290
  **Per-cycle combined bound:** each scheduler cycle dispatches at most one ready PRD (the Phase 3 single-ready-PRD claim) **and** at most one shipped PRD for verification (this Phase 3g dispatch), for a maximum of two PRD operations per cycle. Ready intake runs first (Phase 3), then shipped verify (Phase 3g).
308
291
 
309
- `lisa:verify-prd` owns the outcome: on a CONFORMS verdict with all empirical checks passing it transitions `$SHIPPED → verified` and posts evidence; on a conformance miss or a failing/unavailable check it **re-opens the PRD `$SHIPPED → ticketed`** (never `blocked`) and creates **build-ready** fix tickets registered as the PRD's generated work, then posts a failure report — the fix tickets auto-build, rollup (3f) re-ships the PRD once they are terminal, and a later cycle re-verifies (the self-healing loop). Either branch moves the PRD out of `$SHIPPED`, so it is not re-picked this cycle; a PRD whose generated work is not actually terminal is guard-stopped by `lisa:verify-prd` (left `$SHIPPED`) — that is verify-prd's gate, not this skill's. A PRD archived on ship (`notion.rollup.closeOnShipped = true`) is out of the open verification queue. This phase, like 3f, is **behaviorally identical across all four intake skills** (`github-prd-intake`, `linear-prd-intake`, `notion-prd-intake`, `confluence-prd-intake`) — only the `$SHIPPED` query surface differs; keep them aligned. Record the dispatched PRD + verify-prd's verdict in the summary.
292
+ `lisa:verify-prd` owns the outcome: on a CONFORMS verdict with all empirical checks passing it transitions `$SHIPPED → verified` and posts evidence; on a conformance miss or a failing/unavailable check it **re-opens the PRD `$SHIPPED → ticketed`** (never `blocked`) and creates **build-ready** fix tickets registered as the PRD's generated work, then posts a failure report — the fix tickets auto-build, rollup (3f) re-ships the PRD once they are terminal, and a later cycle re-verifies (the self-healing loop). Either branch moves the PRD out of `$SHIPPED`, so it is not re-picked this cycle; a PRD whose generated work is not actually terminal is guard-stopped by `lisa:verify-prd` (left `$SHIPPED`) — that is verify-prd's gate, not this skill's. This phase, like 3f, is **behaviorally identical across all four intake skills** (`github-prd-intake`, `linear-prd-intake`, `notion-prd-intake`, `confluence-prd-intake`) — only the `$SHIPPED` query surface differs; keep them aligned. Record the dispatched PRD + verify-prd's verdict in the summary.
310
293
 
311
294
  ### Phase 4 — Summary report
312
295
 
@@ -336,10 +319,10 @@ Print to the agent's output. Do not write this summary to Notion or the destinat
336
319
  ## Idempotency & safety
337
320
 
338
321
  - **One item per cycle**: this skill processes the first eligible ready PRD from Phase 2, then exits. New or remaining ready PRDs are picked up by later scheduler invocations.
339
- - **No writes outside the lifecycle**: this skill only ever writes to the destination tracker via `lisa:notion-to-tracker` (which delegates to `lisa:tracker-write`), and only ever changes the Notion status property to `$IN_REVIEW`, `$BLOCKED`, `$TICKETED`, or `$SHIPPED` (the last via the rollup phase 3f only). It never edits PRD content, never touches `$DRAFT`, never deletes pages. It sets `$SHIPPED` and may archive the PRD page **only** through the config-gated rollup phase (3f).
322
+ - **No writes outside the lifecycle**: this skill only ever writes to the destination tracker via `lisa:notion-to-tracker` (which delegates to `lisa:tracker-write`), and only ever changes the Notion status property to `$IN_REVIEW`, `$BLOCKED`, `$TICKETED`, or `$SHIPPED` (the last via the rollup phase 3f only). It never edits PRD content, never touches `$DRAFT`, never archives pages at the shipped hop, and never deletes pages.
340
323
  - **Claim-first ordering**: the status flip to `$IN_REVIEW` is set BEFORE validation runs, so a re-entrant call won't double-process.
341
324
  - **Failure handling**: an exception processing the selected PRD is caught and recorded under "Errors" in the summary, then the cycle exits. The PRD that errored is left in `$IN_REVIEW` — the human investigates from there.
342
- - **Rollup idempotency**: rollup (Phase 3f) is a no-op on a PRD already in `$STATUS_PROP = $SHIPPED` (and already archived when `closeOnShipped` is `true`) — no duplicate transition, no duplicate archive, no duplicate comment. The all-terminal condition is a pure function of the children's current states (deduped by child-ref identity), so recomputing it is safe to re-run. Archival NEVER precedes the all-terminal condition.
325
+ - **Rollup idempotency**: rollup (Phase 3f) is a no-op on a PRD already in `$STATUS_PROP = $SHIPPED` — no duplicate transition, no shipped-time archive, no duplicate comment. The all-terminal condition is a pure function of the children's current states (deduped by child-ref identity), so recomputing it is safe to re-run. Native archival only follows verified PASS in `/lisa:verify-prd`.
343
326
 
344
327
  ## Configuration
345
328
 
@@ -357,8 +340,6 @@ This skill reads project configuration from `.lisa.config.json` (with `.lisa.con
357
340
  | `notion.values.blocked` | `Blocked` | Value the agent sets on validation failure |
358
341
  | `notion.values.ticketed` | `Ticketed` | Value the agent sets on success |
359
342
  | `notion.values.shipped` | `Shipped` | Value the rollup phase (3f) sets when all generated top-level work is terminal; product may also set it by hand |
360
- | `notion.rollup.closeOnShipped` | `false` | When `true`, rollup archives the PRD page after the `$SHIPPED` transition; when `false`, sets `$SHIPPED` and leaves the page active |
361
-
362
343
  ### From environment variables
363
344
 
364
345
  | Variable | Purpose |
@@ -371,7 +352,7 @@ This skill reads project configuration from `.lisa.config.json` (with `.lisa.con
371
352
 
372
353
  - Never write to the destination tracker outside of `lisa:notion-to-tracker` → `lisa:tracker-write`. The validator's verdict gates progress; bypassing it produces broken tickets.
373
354
  - Never set the Notion status to a value this skill doesn't own (`$IN_REVIEW`, `$BLOCKED`, `$TICKETED`, and `$SHIPPED` via the rollup phase only). Product owns `$DRAFT` and `$READY`; product and the rollup phase (3f) both set `$SHIPPED`.
374
- - Set `$SHIPPED` (and archive the PRD page when `closeOnShipped` is configured) only from the rollup phase, and only when all generated top-level children are terminal per the `prd-lifecycle-rollup` rule. Never ship or archive on partial completion.
355
+ - Set `$SHIPPED` only from the rollup phase, and only when all generated top-level children are terminal per the `prd-lifecycle-rollup` rule. Never ship on partial completion and never archive at shipped.
375
356
  - Never edit the PRD's body. Communication with product happens only through Notion comments.
376
357
  - Never post a single page-level dump of all gate failures. One comment per `prd_anchor` group (or one page-level summary for unanchored failures only). The audience is product, not engineers — comments must be block-anchored, categorized, plain-language, and contain a concrete recommendation. See Phase 3c.3 for the required template and Phase 3c.5 for forbidden language.
377
358
  - Never include a gate ID, internal skill name, or engineering shorthand in a Notion comment body. If the validator's `what` or `recommendation` field uses one, paraphrase before posting.
@@ -35,7 +35,7 @@ If neither arg is supplied, ask which mode (or both). Setting only `parentPageId
35
35
 
36
36
  ### Step 3 — Create lifecycle parent pages
37
37
 
38
- Confluence PRD lifecycle is **parent-page-based**, not label-based (see the `config-resolution` rule for why — Atlassian's scoped API tokens cannot write labels). Each lifecycle role gets its own parent page; a PRD's state = which parent it's a child of. The full PRD lifecycle is `draft → ready → in_review → (blocked | ticketed) → shipped → verified` (the `prd-lifecycle-rollup` rule, slug `prd-lifecycle-rollup`): rollup performs the `ticketed → shipped` hop, then `/lisa:verify-prd` performs the terminal `shipped → verified` (pass) / `shipped → blocked` (fail) hop. `verified` is the terminal lifecycle state after `shipped` (the `verified` role from the `config-resolution` rule, #591).
38
+ Confluence PRD lifecycle is **parent-page-based**, not label-based (see the `config-resolution` rule for why — Atlassian's scoped API tokens cannot write labels). Each lifecycle role gets its own parent page; a PRD's state = which parent it's a child of. The full PRD lifecycle is `draft → ready → in_review → (blocked | ticketed) → shipped → verified` (the `prd-lifecycle-rollup` rule, slug `prd-lifecycle-rollup`): rollup performs the `ticketed → shipped` hop, then `/lisa:verify-prd` performs the terminal `shipped → verified` (pass) / `shipped → ticketed` (fail) hop. `verified` is the terminal lifecycle state after `shipped` (the `verified` role from the `config-resolution` rule, #591).
39
39
 
40
40
  #### 3a. Decide where the parents live
41
41