@codyswann/lisa 2.126.1 → 2.126.2

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 (84) hide show
  1. package/package.json +1 -1
  2. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  3. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  4. package/plugins/lisa/commands/repair-intake.md +1 -1
  5. package/plugins/lisa/rules/eager/leaf-only-lifecycle.md +5 -3
  6. package/plugins/lisa/rules/reference/leaf-only-lifecycle.md +13 -8
  7. package/plugins/lisa/skills/github-sync/SKILL.md +7 -6
  8. package/plugins/lisa/skills/jira-sync/SKILL.md +7 -6
  9. package/plugins/lisa/skills/linear-sync/SKILL.md +6 -5
  10. package/plugins/lisa/skills/repair-intake/SKILL.md +63 -29
  11. package/plugins/lisa/skills/tracker-sync/SKILL.md +5 -4
  12. package/plugins/lisa-agy/commands/repair-intake.md +1 -1
  13. package/plugins/lisa-agy/plugin.json +1 -1
  14. package/plugins/lisa-agy/skills/github-sync/SKILL.md +7 -6
  15. package/plugins/lisa-agy/skills/jira-sync/SKILL.md +7 -6
  16. package/plugins/lisa-agy/skills/linear-sync/SKILL.md +6 -5
  17. package/plugins/lisa-agy/skills/repair-intake/SKILL.md +63 -29
  18. package/plugins/lisa-agy/skills/tracker-sync/SKILL.md +5 -4
  19. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  21. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  22. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-copilot/commands/repair-intake.md +1 -1
  26. package/plugins/lisa-copilot/rules/eager/leaf-only-lifecycle.md +5 -3
  27. package/plugins/lisa-copilot/rules/reference/leaf-only-lifecycle.md +13 -8
  28. package/plugins/lisa-copilot/skills/github-sync/SKILL.md +7 -6
  29. package/plugins/lisa-copilot/skills/jira-sync/SKILL.md +7 -6
  30. package/plugins/lisa-copilot/skills/linear-sync/SKILL.md +6 -5
  31. package/plugins/lisa-copilot/skills/repair-intake/SKILL.md +63 -29
  32. package/plugins/lisa-copilot/skills/tracker-sync/SKILL.md +5 -4
  33. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-cursor/commands/repair-intake.md +1 -1
  35. package/plugins/lisa-cursor/rules/leaf-only-lifecycle-reference.mdc +13 -8
  36. package/plugins/lisa-cursor/rules/leaf-only-lifecycle.mdc +5 -3
  37. package/plugins/lisa-cursor/skills/github-sync/SKILL.md +7 -6
  38. package/plugins/lisa-cursor/skills/jira-sync/SKILL.md +7 -6
  39. package/plugins/lisa-cursor/skills/linear-sync/SKILL.md +6 -5
  40. package/plugins/lisa-cursor/skills/repair-intake/SKILL.md +63 -29
  41. package/plugins/lisa-cursor/skills/tracker-sync/SKILL.md +5 -4
  42. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  44. package/plugins/lisa-expo-agy/plugin.json +1 -1
  45. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  49. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  50. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  54. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  55. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  59. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  60. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  64. package/plugins/lisa-rails-agy/plugin.json +1 -1
  65. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  69. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  70. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  74. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  75. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  77. package/plugins/src/base/commands/repair-intake.md +1 -1
  78. package/plugins/src/base/rules/eager/leaf-only-lifecycle.md +5 -3
  79. package/plugins/src/base/rules/reference/leaf-only-lifecycle.md +13 -8
  80. package/plugins/src/base/skills/github-sync/SKILL.md +7 -6
  81. package/plugins/src/base/skills/jira-sync/SKILL.md +7 -6
  82. package/plugins/src/base/skills/linear-sync/SKILL.md +6 -5
  83. package/plugins/src/base/skills/repair-intake/SKILL.md +63 -29
  84. package/plugins/src/base/skills/tracker-sync/SKILL.md +5 -4
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: repair-intake
3
- description: "Vendor-agnostic repair scanner — the recovery counterpart to lisa:intake. Where intake claims `ready` work, repair-intake finds work that got stuck or was left half-closed: items left in `blocked`, stalled in an in-progress role (build `claimed`, PRD `in_review`), terminal-labeled items that are still natively open, and rollup/container items whose children are all terminal but whose parent is not closed out. Scans the same queues lisa:intake serves (Notion / Confluence / Linear / GitHub PRD databases; JIRA / GitHub / Linear build queues), enumerates candidates up to `max_candidates`, and repairs every materially actionable one in that bounded set: resumes stalled in-progress work IN PLACE (build → the vendor agent + the scanner's post-agent transition; PRD → the source `*-to-tracker` dry-run validate→route pipeline) — but for a stalled build it first diagnoses the PR/deploy state and, if the PR cannot merge (conflict, rebase-required, failing checks, unaddressed CodeRabbit/changes-requested) or a deploy failed, files a build-ready leaf fix ticket and moves the item to `blocked` (blocked by that ticket) rather than re-dispatching, re-validates blocked PRDs when new clarifying answers exist, re-dispatches blocked build items whose `is blocked by` dependencies have since closed, performs terminal native closure for terminal-labeled items, and closes rollups whose associated child work is fully terminal. Idempotent, loop-protected via a [lisa-repair-intake] marker + state fingerprint + backoff. Never mutates product-owned states (`draft`, `verified`) and never touches `ready` items. Designed as a /schedule cron target running alongside lisa:intake."
3
+ description: "Vendor-agnostic repair scanner — the recovery counterpart to lisa:intake. Where intake claims `ready` work, repair-intake finds work that got stuck or was left half-closed: items left in `blocked`, stalled in an in-progress role (build `claimed`, PRD `in_review`), terminal-labeled items that are still natively open, and rollup/container items whose children are all terminal but whose parent is not closed out. Scans the same queues lisa:intake serves (Notion / Confluence / Linear / GitHub PRD databases; JIRA / GitHub / Linear build queues), enumerates candidates up to `max_candidates`, and repairs every materially actionable one in that bounded set: resumes stalled in-progress work IN PLACE (build → the vendor agent + the scanner's post-agent transition; PRD → the source `*-to-tracker` dry-run validate→route pipeline) — but for a stalled build it first diagnoses the PR/deploy state and, if the PR cannot merge (conflict, rebase-required, failing checks, unaddressed CodeRabbit/changes-requested) or a deploy failed, files a build-ready leaf fix ticket and moves the item to `blocked` (blocked by that ticket) rather than re-dispatching, re-validates blocked PRDs when new clarifying answers exist, re-dispatches blocked build items whose `is blocked by` dependencies have since closed, performs terminal native closure for terminal-labeled items, reconciles parent rollups to their derived state per leaf-only-lifecycle — including the intermediate-env case (e.g. all children at `On Stg` → parent `On Stg`) and a container wrongly stuck in `ready` — and closes out rollups whose associated child work is fully terminal. Idempotent, loop-protected via a [lisa-repair-intake] marker + state fingerprint + backoff. Never mutates product-owned states (`draft`, `verified`) and never touches `ready` leaves (a container wrongly carrying `ready` is the one exception — it is rolled up from its children, since `ready` on a parent is an invariant violation, not intake's claim signal). Designed as a /schedule cron target running alongside lisa:intake."
4
4
  allowed-tools: ["Skill", "Bash", "Read", "Write", "Edit", "mcp__linear-server__list_teams", "mcp__linear-server__list_projects", "mcp__linear-server__get_project", "mcp__linear-server__save_project", "mcp__linear-server__list_project_labels", "mcp__linear-server__list_issues", "mcp__linear-server__get_issue", "mcp__linear-server__save_issue", "mcp__linear-server__list_comments", "mcp__linear-server__save_comment", "mcp__linear-server__list_issue_labels", "mcp__linear-server__create_issue_label"]
5
5
  ---
6
6
 
@@ -24,9 +24,16 @@ close-out** roles and moves work *unstuck* or *fully closed*:
24
24
  research/waiting resolves the ambiguity that stopped it.
25
25
  - **Terminal-open drift** — an item already carrying its true terminal lifecycle role (for
26
26
  example GitHub `status:done`) but still open/active in the provider's native state.
27
- - **Completed rollup drift** — a parent/container item (Epic, Story, PRD, Linear Project, or
28
- equivalent) whose associated child set is fully terminal but whose own lifecycle/native state has
29
- not been closed out.
27
+ - **Rollup drift** — a parent/container item (Epic, Story, PRD, Linear Project, or equivalent)
28
+ whose own lifecycle state does not match the roll-up of its children's states per
29
+ `leaf-only-lifecycle`. This covers the *completed* case (all children terminal → close the parent
30
+ out) **and** the *intermediate-env* case (all children shipped to an env like `On Stg`, but the
31
+ parent never advanced — including a parent left stranded in a status it should never carry).
32
+ - **Stale-`ready` container** — a parent/container (open child work, or a childless
33
+ Epic/Story/Spike) wrongly carrying the build-ready role. This is a leaf-only-invariant violation
34
+ the build-intake claim gate deliberately leaves for a human; repair-intake reconciles it by
35
+ rolling the parent up from its children (with an audit note), so a container never sits in `ready`
36
+ indefinitely.
30
37
 
31
38
  This skill is the symmetric counterpart to `lisa:intake`. It reuses the same queue-detection,
32
39
  the same agent-team orchestration, the same "don't ask, just run" confirmation policy, and the
@@ -131,9 +138,9 @@ claim-and-advance). The essentials, inlined here so this skill is self-complete:
131
138
  | Confluence **parent page** URL/ID | PRD (Confluence, narrowed) | source=confluence | `in_review`, `blocked`, terminal/open PRDs, all-terminal generated-work rollups |
132
139
  | Linear **workspace** URL, **team** URL/key, or literal `linear` | PRD (Linear) | source=linear | `in_review`, `blocked`, terminal/open PRDs, all-terminal generated-work rollups |
133
140
  | GitHub **repo** URL / `org/repo` (PRD namespace) | PRD (GitHub) | source=github | `in_review`, `blocked`, terminal/open PRDs, all-terminal generated-work rollups |
134
- | GitHub **repo** URL / `org/repo` with `tracker = github` (build namespace) | Build (GitHub) | tracker=github | `claimed`, `blocked`, terminal/open issues, all-terminal parent rollups |
141
+ | GitHub **repo** URL / `org/repo` with `tracker = github` (build namespace) | Build (GitHub) | tracker=github | `claimed`, `blocked`, terminal/open issues, parent rollups (intermediate-env + all-terminal), stale-`ready` containers |
135
142
  | Literal `github` | GitHub; route by `intake_mode` (`prd` / `build` / `both`) | per lifecycle | per lifecycle above |
136
- | JIRA project key or full JQL | Build (JIRA) | tracker=jira | `claimed`, `blocked`, terminal/closure verification, all-terminal parent rollups |
143
+ | JIRA project key or full JQL | Build (JIRA) | tracker=jira | `claimed`, `blocked`, terminal/closure verification, parent rollups (intermediate-env + all-terminal), stale-`ready` containers |
137
144
 
138
145
  Disambiguation (same as `lisa:intake`): a `notion.so`/`notion.site` URL → Notion; an Atlassian
139
146
  `/wiki/spaces/<KEY>` URL → Confluence (with `/pages/<id>` → parent-page narrowing); a
@@ -355,24 +362,37 @@ native-open / active / unresolved:
355
362
  4. Post a compact `[lisa-repair-intake]` note only when the native close-out changed state or when
356
363
  an actionable setup error must be surfaced. Do not spam already-closed terminal items.
357
364
 
358
- ### Build rollup with all children terminal close out parent/container
365
+ ### Build parent rollup reconciliation (intermediate-env or terminal close-out)
359
366
 
360
- For each parent/container item (Epic, Story, Spike, Project, or any item with child work) whose
361
- required child set is fully terminal:
367
+ For each parent/container item (Epic, Story, Spike, Project, or any item with child work),
368
+ reconcile its lifecycle state with the roll-up of its children — **including the intermediate-env
369
+ case**, not only fully-terminal close-out. This is the recovery-side complement to the forward
370
+ rollup the `*-sync --rollup` skills perform; it catches a parent that was never rolled up (or was
371
+ left in a status it should not carry, including a stale build-ready `ready`).
362
372
 
363
373
  1. Read the child set using the vendor-native hierarchy first (GitHub sub-issues, JIRA
364
374
  Epic/parent/sub-task hierarchy, Linear project/parent/sub-issues), with the same fallbacks the
365
375
  vendor read/sync skills document.
366
- 2. Evaluate bottom-up per `leaf-only-lifecycle`: every required child must already be terminal.
376
+ 2. **Compute the derived parent state** bottom-up per the `leaf-only-lifecycle` **Parent status
377
+ rollup** state machine, evaluated over the env ladder `in-progress < dev < staging <
378
+ production` (the ordered keys of the env-keyed `done` map): any required child blocked →
379
+ `blocked`; else every required child shipped to some env → the **least-advanced** env among
380
+ them (e.g. all `On Stg` → `On Stg`); else any child started → `claimed`; else unchanged.
367
381
  Optional / won't-do / not-planned children are terminal-but-dropped and do not hold the parent
368
382
  open.
369
- 3. Apply the configured terminal rollup role to the parent/container, removing any stale build
370
- lifecycle role that conflicts.
371
- 4. Immediately perform terminal native closure where the provider supports it (GitHub close,
372
- Linear complete, JIRA resolved/closed). A completed rollup parent should not remain open in
373
- GitHub merely because no leaf agent touched it.
374
- 5. If any required child is incomplete, active, blocked, or inaccessible, leave the parent open and
375
- record it as `still_blocked` or `active` with the current child tally.
383
+ 3. **If the derived state differs from the parent's current state, apply it** via the vendor's
384
+ lifecycle write (JIRA transition, GitHub/Linear label swap keeping exactly one `status:*`),
385
+ removing any conflicting stale build lifecycle role **including a stale `ready`** the parent
386
+ should never carry. Post an idempotent `[lisa-repair-intake]` rollup note naming the derived
387
+ state and the child tally (honor the backoff window + fingerprint).
388
+ 4. **Perform native closure only at the true terminal `done`.** When and only when — the derived
389
+ env is the production/terminal value, finalize through the provider-native mechanism (GitHub
390
+ `gh issue close --reason completed`, Linear move to Done state, JIRA resolved/closed verified at
391
+ `statusCategory = Done`). An intermediate-env rollup (`On Dev`/`On Stg`) advances the parent's
392
+ status but **must not** close it — it is still open per `leaf-only-lifecycle`.
393
+ 5. If the derived state is `unchanged` (children exist but none started) or the required set is
394
+ ambiguous / inaccessible, leave the parent as-is and record it as `active` or `still_blocked`
395
+ with the current child tally; never guess a transition.
376
396
 
377
397
  ### PRD `in_review` (stalled in-progress) → re-run validate→route
378
398
 
@@ -483,8 +503,9 @@ cron tick.
483
503
  ## Lifecycle ownership guard
484
504
 
485
505
  repair-intake owns the repair surfaces needed to recover stuck work and close-out drift:
486
- build `claimed` / `blocked`, PRD `in_review` / `blocked`, terminal-labeled native-open items, and
487
- parent/container rollups whose child sets are already terminal. It MAY:
506
+ build `claimed` / `blocked`, PRD `in_review` / `blocked`, terminal-labeled native-open items,
507
+ parent/container rollups (intermediate-env *and* fully-terminal), and stale-`ready` containers.
508
+ It MAY:
488
509
 
489
510
  - Apply the build scanner's post-agent `claimed → done` on a successful resume (it is finishing
490
511
  the scanner's interrupted job), and move a dependency-cleared build item `blocked → claimed`.
@@ -492,8 +513,14 @@ parent/container rollups whose child sets are already terminal. It MAY:
492
513
  as the PRD intake does.
493
514
  - Close / complete / resolve build items that already carry the true terminal `done` role but are
494
515
  still natively open, per `leaf-only-lifecycle`.
495
- - Roll up a parent/container to the configured terminal state and close/complete/resolve it when
496
- all required children are terminal.
516
+ - Roll up a parent/container to its derived state per the `leaf-only-lifecycle` state machine —
517
+ **including an intermediate env value** (`On Dev`/`On Stg`) when all required children have
518
+ reached that env — and close/complete/resolve it **only** when the derived env is the true
519
+ terminal `done`.
520
+ - Reconcile a **container** wrongly carrying the build-ready `ready` role (a leaf-only-invariant
521
+ violation) by rolling it up from its children and removing the `ready`, with a
522
+ `[lisa-repair-intake]` audit note. This is the one `ready`-touching exception (see MUST NOT) and
523
+ applies only to containers, never to leaves.
497
524
  - Move a PRD with fully terminal generated work to `shipped` and close/archive the source artifact
498
525
  where the source vendor supports native close-out, per `prd-lifecycle-rollup`.
499
526
 
@@ -502,21 +529,27 @@ It MUST NOT:
502
529
  - Move a PRD out of `draft` or `verified` (those are product-owned), or set `verified` itself.
503
530
  - Apply a build `done` value other than via the env-resolution rules, or close a native item at
504
531
  any value other than the true terminal `done` (see `leaf-only-lifecycle`).
505
- - Touch `ready` items (that is `lisa:intake`'s lane).
532
+ - Touch `ready` **leaves** (that is `lisa:intake`'s lane). A container carrying `ready` is the
533
+ documented exception above — repair-intake reconciles it because `ready` on a parent is an
534
+ invariant violation, not the human "claim this leaf" signal intake owns.
506
535
 
507
536
  ## Cycle behavior
508
537
 
509
538
  1. **Resolve the queue** — detect vendor/lifecycle (Source dispatch); resolve stuck role names
510
539
  from config. For JIRA, confirm the needed transitions are reachable; stop on misconfig.
511
540
  2. **Enumerate repair candidates** — query in-progress role(s), `blocked` role(s), terminal/open
512
- items, and rollup parents/PRDs with child work for the detected lifecycle(s), up to
541
+ items, rollup parents/PRDs with child work, and **containers carrying the `ready` role** (a
542
+ leaf-only-invariant violation to reconcile), for the detected lifecycle(s), up to
513
543
  `max_candidates`, via the Access layer reads.
514
544
  3. **Order deterministically**, highest repair-confidence first:
515
545
  1. terminal-labeled items that only need native close / complete / resolve,
516
- 2. rollup parents/PRDs whose child sets are all terminal,
517
- 3. `blocked` items whose dependencies are now **cleared** (safe, high-value, one-cycle wins),
518
- 4. `blocked` items with **new clarifying answers**,
519
- 5. **stalled** in-progress items, oldest activity first.
546
+ 2. rollup parents/PRDs whose child sets are all terminal (close-out),
547
+ 3. rollup parents whose children have advanced to an intermediate env, or stale-`ready`
548
+ containers, that need their derived state applied (status-only reconciliation, no native
549
+ close),
550
+ 4. `blocked` items whose dependencies are now **cleared** (safe, high-value, one-cycle wins),
551
+ 5. `blocked` items with **new clarifying answers**,
552
+ 6. **stalled** in-progress items, oldest activity first.
520
553
  4. **Walk the ordered list**, evaluating each candidate (terminal close-out, rollup child tally,
521
554
  staleness, dependency, answer checks), and repair **every** candidate that is actionable inside
522
555
  the `max_candidates` cap. Continue after successful writes and after per-item errors.
@@ -539,8 +572,9 @@ Report outcomes in these buckets:
539
572
  `ticketed`.
540
573
  - `closed_out` — terminal-labeled items whose native open/active state was closed, completed,
541
574
  resolved, or archived.
542
- - `rolled_up` — parent/container/PRD rollups advanced because all associated children were
543
- terminal.
575
+ - `rolled_up` — parent/container/PRD rollups advanced to their derived state: an intermediate env
576
+ (e.g. all children at `On Stg` → parent `On Stg`), a fully-terminal close-out, or a stale-`ready`
577
+ container reconciled from its children.
544
578
  - `still_blocked` — examined and intentionally left `blocked`, with the active reason.
545
579
  - `active` — skipped because current work is not stale (or within backoff).
546
580
  - `errors` — items that failed evaluation, with the error.
@@ -28,19 +28,20 @@ If `$ARGUMENTS` is empty, all vendor skills auto-detect a ticket reference from
28
28
 
29
29
  When the caller passes `--rollup` after the milestone, the dispatch target additionally **derives the parent/container's lifecycle state from its children** instead of acting on the work item directly. This is the vendor-neutral implementation of the **Parent status rollup (the state machine)** section of the `leaf-only-lifecycle` rule — cite that rule, do not restate the policy here. The shim is dispatch only; the rollup mechanics live in the vendor sync skill (`lisa:github-sync`, `lisa:jira-sync`, `lisa:linear-sync`), which resolves child membership via its `*-read-*` skill and evaluates the state machine below.
30
30
 
31
- The state machine (first match wins, evaluated over the **required** leaves only):
31
+ The state machine (first match wins, evaluated over the **required** leaves only, on the env ladder `in-progress < dev < staging < production` — the ordered keys of the project's env-keyed `done` map):
32
32
 
33
33
  | If among the required leaves… | …the parent rolls up to | Role |
34
34
  |---|---|---|
35
35
  | any leaf is **blocked** | blocked / attention-needed | `blocked` |
36
- | else any leaf is **in progress** (claimed or in review) | active / in-progress | `claimed` |
37
- | else **all** required leaves are **terminal** | the configured rollup terminal | `done` (or `review` where supported) |
36
+ | else **every** required leaf has shipped to some env (each at a `done`-map value) | the **least-advanced** env among them | `done[min-env]` (terminal `done` at production) |
37
+ | else any leaf has **started** (claimed or in review, or shipped while a sibling has not) | active / in-progress | `claimed` (or `review` where supported) |
38
38
  | else (leaves exist, none started) | unchanged | — |
39
39
 
40
40
  - **Blocked dominates** — one blocked leaf surfaces blocked on the parent even while others progress.
41
+ - **Least-advanced env wins** — a parent reaches an env only once all required leaves have reached at least that env (all `On Stg` → `On Stg`; mixed dev/staging → the dev value). Native terminal closure fires only at the production `done`, never at an intermediate env.
41
42
  - **The parent never carries `ready`** — `ready` is a human "claim this leaf" signal; rollup only moves a parent between non-ready container states.
42
43
  - **Rollup is recursive** — an Epic rolls up from its Stories, each of which rolls up from its own leaves. Evaluate bottom-up.
43
- - **The terminal is the configured env-keyed `done`** — multi-env projects roll up to whichever `done` value matches the env their leaves shipped to (see `config-resolution` "Env-keyed `done`"). **Single-environment collapse (this repo):** `deploy.branches` declares only `production: main`, so `done` is a single value and the GitHub build lifecycle collapses to `ready → claimed (in-progress) → done`; the rollup terminal is simply `done` (or the PRD-side `ticketed` for PRD containers), with **no** dev/staging promotion hops and **no** env-keyed multi-entry chain to resolve.
44
+ - **The env rungs are the configured env-keyed `done`** — multi-env projects roll up to whichever `done` value (including intermediate `On Dev`/`On Stg`) their leaves have collectively reached (see `config-resolution` "Env-keyed `done`"). **Single-environment collapse (this repo):** `deploy.branches` declares only `production: main`, so `done` is a single value, the only env rung is production, and the GitHub build lifecycle collapses to `ready → claimed (in-progress) → done`; the rollup terminal is simply `done` (or the PRD-side `ticketed` for PRD containers), with **no** dev/staging promotion hops and **no** env-keyed multi-entry chain to resolve.
44
45
 
45
46
  **Safe-by-default when not yet supported.** A vendor sync path that has not implemented native rollup MUST be a documented no-op that surfaces the derived state as a suggestion/comment rather than guessing a transition — never an unsafe default. Without `--rollup`, the sync skills behave exactly as before (milestone comment on the work item; no parent derivation).
46
47