@codyswann/lisa 4.11.2 → 4.11.3

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 (108) hide show
  1. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  2. package/dist/core/upstream-evidence-manifest.js +16 -8
  3. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  4. package/dist/sync/lifecycle-defaults.d.ts +1 -0
  5. package/dist/sync/lifecycle-defaults.d.ts.map +1 -1
  6. package/dist/sync/lifecycle-defaults.js +1 -0
  7. package/dist/sync/lifecycle-defaults.js.map +1 -1
  8. package/dist/sync/registry.d.ts.map +1 -1
  9. package/dist/sync/registry.js +5 -2
  10. package/dist/sync/registry.js.map +1 -1
  11. package/package.json +1 -1
  12. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  13. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  14. package/plugins/lisa/.codex-plugin/skills/lisa-github-sync/SKILL.md +8 -2
  15. package/plugins/lisa/.codex-plugin/skills/lisa-jira-sync/SKILL.md +1 -1
  16. package/plugins/lisa/.codex-plugin/skills/lisa-linear-sync/SKILL.md +1 -1
  17. package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +31 -1
  18. package/plugins/lisa/.codex-plugin/skills/lisa-tracker-sync/SKILL.md +1 -1
  19. package/plugins/lisa/rules/eager/leaf-only-lifecycle.md +11 -0
  20. package/plugins/lisa/rules/reference/config-resolution.md +7 -1
  21. package/plugins/lisa/rules/reference/leaf-only-lifecycle.md +21 -0
  22. package/plugins/lisa/scripts/rollup-blocker-classification.mjs +592 -0
  23. package/plugins/lisa/skills/lisa-github-sync/SKILL.md +8 -2
  24. package/plugins/lisa/skills/lisa-jira-sync/SKILL.md +1 -1
  25. package/plugins/lisa/skills/lisa-linear-sync/SKILL.md +1 -1
  26. package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +31 -1
  27. package/plugins/lisa/skills/lisa-tracker-sync/SKILL.md +1 -1
  28. package/plugins/lisa-agy/plugin.json +1 -1
  29. package/plugins/lisa-agy/scripts/rollup-blocker-classification.mjs +592 -0
  30. package/plugins/lisa-agy/skills/lisa-github-sync/SKILL.md +8 -2
  31. package/plugins/lisa-agy/skills/lisa-jira-sync/SKILL.md +1 -1
  32. package/plugins/lisa-agy/skills/lisa-linear-sync/SKILL.md +1 -1
  33. package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +31 -1
  34. package/plugins/lisa-agy/skills/lisa-tracker-sync/SKILL.md +1 -1
  35. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  37. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  38. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-copilot/rules/eager/leaf-only-lifecycle.md +11 -0
  42. package/plugins/lisa-copilot/rules/reference/config-resolution.md +7 -1
  43. package/plugins/lisa-copilot/rules/reference/leaf-only-lifecycle.md +21 -0
  44. package/plugins/lisa-copilot/scripts/rollup-blocker-classification.mjs +592 -0
  45. package/plugins/lisa-copilot/skills/lisa-github-sync/SKILL.md +8 -2
  46. package/plugins/lisa-copilot/skills/lisa-jira-sync/SKILL.md +1 -1
  47. package/plugins/lisa-copilot/skills/lisa-linear-sync/SKILL.md +1 -1
  48. package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +31 -1
  49. package/plugins/lisa-copilot/skills/lisa-tracker-sync/SKILL.md +1 -1
  50. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +7 -1
  52. package/plugins/lisa-cursor/rules/leaf-only-lifecycle-reference.mdc +21 -0
  53. package/plugins/lisa-cursor/rules/leaf-only-lifecycle.mdc +11 -0
  54. package/plugins/lisa-cursor/scripts/rollup-blocker-classification.mjs +592 -0
  55. package/plugins/lisa-cursor/skills/lisa-github-sync/SKILL.md +8 -2
  56. package/plugins/lisa-cursor/skills/lisa-jira-sync/SKILL.md +1 -1
  57. package/plugins/lisa-cursor/skills/lisa-linear-sync/SKILL.md +1 -1
  58. package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +31 -1
  59. package/plugins/lisa-cursor/skills/lisa-tracker-sync/SKILL.md +1 -1
  60. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  62. package/plugins/lisa-expo-agy/plugin.json +1 -1
  63. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  67. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  68. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  72. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  73. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  77. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  78. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  82. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  83. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  84. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  87. package/plugins/lisa-rails-agy/plugin.json +1 -1
  88. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  89. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  90. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  91. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  92. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  93. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  94. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  95. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  96. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  97. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  98. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  99. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  100. package/plugins/src/base/rules/eager/leaf-only-lifecycle.md +11 -0
  101. package/plugins/src/base/rules/reference/config-resolution.md +7 -1
  102. package/plugins/src/base/rules/reference/leaf-only-lifecycle.md +21 -0
  103. package/plugins/src/base/scripts/rollup-blocker-classification.mjs +592 -0
  104. package/plugins/src/base/skills/lisa-github-sync/SKILL.md +8 -2
  105. package/plugins/src/base/skills/lisa-jira-sync/SKILL.md +1 -1
  106. package/plugins/src/base/skills/lisa-linear-sync/SKILL.md +1 -1
  107. package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +31 -1
  108. package/plugins/src/base/skills/lisa-tracker-sync/SKILL.md +1 -1
@@ -38,7 +38,7 @@ The state machine (first match wins, evaluated over the **required** leaves only
38
38
  | else any leaf has **started** (claimed or in review, or shipped while a sibling has not) | active / in-progress | `claimed` (or `review` where supported) |
39
39
  | else (leaves exist, none started) | unchanged | — |
40
40
 
41
- - **Blocked dominates** — one blocked leaf surfaces blocked on the parent even while others progress.
41
+ - **Blocked dominates** — one blocked leaf surfaces blocked on the parent even while others progress. It never says *which* child or *which kind* of hold; run `scripts/rollup-blocker-classification.mjs` over the resolved child graph and carry its per-class report — blocking leaf, path, and who must act — into the rollup note. A non-zero exit means it classified nothing; that is a failure to report, never an all-clear. See `leaf-only-lifecycle` → **Classifying a hold**.
42
42
  - **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.
43
43
  - **The parent never carries `ready`** — `ready` is a human "claim this leaf" signal; rollup only moves a parent between non-ready container states.
44
44
  - **Rollup is recursive** — an Epic rolls up from its Stories, each of which rolls up from its own leaves. Evaluate bottom-up.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.11.2",
3
+ "version": "4.11.3",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -467,11 +467,12 @@ Every lifecycle skill operates on a fixed set of **roles** (`ready`, `claimed`,
467
467
 
468
468
  #### Build markers (additive labels, not lifecycle roles)
469
469
 
470
- A **marker** is an additive label applied *alongside* a lifecycle role, not a state the item transitions *to*. Markers carry no rollup or transition semantics — they annotate an item that is already in some role. The build lifecycle defines one marker:
470
+ A **marker** is an additive label applied *alongside* a lifecycle role, not a state the item transitions *to*. Markers carry no rollup or transition semantics — they annotate an item that is already in some role, and the rollup reads them to say *which kind* of hold a `blocked` item is (`rollup-blocker-classification`). The build lifecycle defines two markers:
471
471
 
472
472
  | Marker | What it means | JIRA default | GitHub/Linear default |
473
473
  |---|---|---|---|
474
474
  | `human_needed` | Applied with `blocked` when — **after the agent has drafted every authorable missing section via the `pre-flight-autofill` procedure** — the block still requires a human to confirm the drafted assumptions or supply something no agent can invent: real missing credentials, access/permissions, or an irreducible product/scoping decision. | `Human Needed` (label) | `human-needed` (label) |
475
+ | `spec_defect` | Applied with `blocked` when the thing holding the item is the item's **own specification** — an acceptance criterion that cannot be satisfied as written, a field naming an environment or surface the project does not have, a validation journey demanding something the project cannot produce. **Human-applied only.** No agent sets it, because judging a criterion unbuildable is a product call, and the agent that wrote a bad criterion is the least likely to know it did. | `Spec Defect` (label) | `blocked:spec-defect` (label) |
475
476
 
476
477
  Markers are labels on **every** vendor, Linear included — that is the one place the Linear build lane still touches `linear.labels`.
477
478
 
@@ -480,9 +481,14 @@ Resolution keys:
480
481
  - JIRA: `jira.labels.human_needed` (default `Human Needed`). Applied as a JIRA **label** — not a workflow status — because an item holds exactly one status but any number of labels. The `blocked` status still drives the lifecycle; `human_needed` is the additive marker on top of it.
481
482
  - GitHub: `github.labels.build.human_needed` (default `human-needed`). Added next to the `blocked` label.
482
483
  - Linear: `linear.labels.build.human_needed` (default `human-needed`). Applied as a Linear **label**, for the same reason as JIRA — an Issue holds exactly one workflow state but any number of labels, so an additive marker cannot be a state. The `blocked` **state** still drives the lifecycle; `human_needed` is the marker on top of it. This is the only build-lane key left in `linear.labels`.
484
+ - `spec_defect` resolves the same way on each vendor — `jira.labels.spec_defect` (default `Spec Defect`), `github.labels.build.spec_defect` and `linear.labels.build.spec_defect` (default `blocked:spec-defect`).
483
485
 
484
486
  **When to apply it.** Apply `human_needed` only when a human must act before the item can move — the pre-flight gate failures that bounce a ticket back to its reporter are exactly this case, but **only after** the agent has run the `pre-flight-autofill` draft-then-block procedure (drafting the authorable gaps — acceptance criteria, validation journey, repository, relationship search, etc. — into the ticket as labeled assumptions). What then remains for the human is to **confirm those assumptions** or supply a genuinely human-only input (real missing credentials, an irreducible product/scoping decision). The marker means "a human must confirm or decide," not "a human must author from scratch."
485
487
 
488
+ **Why `spec_defect` is separate from `human_needed`.** Both name a hold a person must clear, but they are different asks and the rollup must not merge them. `human_needed` waits on an input from *outside* the item — a credential, an access grant, a product decision — and the item's own text is fine. `spec_defect` waits on the item's text being *rewritten*, and no external event will ever supply that. An item carrying `spec_defect` will sit forever until somebody edits it; that is exactly the class that accumulated silently when the rollup rendered both as plain `blocked` (issue #3045: 32 identical hold comments over six weeks on one Epic). Where both markers are present, `spec_defect` wins — it is the more specific record, and the only one carrying a judgment nothing else can supply.
489
+
490
+ **Nothing infers `spec_defect`.** It is never derived from prose, a title, or a failed gate. A `blocked` item carrying neither marker and no open `is blocked by` link classifies as **`unknown`**, and the rollup says so and asks a person to decide — an honest `unknown` beats a confident wrong answer, and auto-reclassifying would turn a human product call into a guess.
491
+
486
492
  **When NOT to apply it.** Do **not** apply `human_needed` to a block that an automated cycle can clear on its own: a block whose `is blocked by` dependency is another tracked ticket that will build and close (for example a `repair-intake`-filed build-ready fix ticket for an unmergeable PR or a failed deploy), or any block waiting only on a retry. Those self-heal; flagging them for a human is noise. If such an item already carries a stale `human_needed` marker, clear it when the block becomes auto-recoverable.
487
493
 
488
494
  The marker is **best-effort and additive**: it never replaces the `blocked` role and never gates a transition. A project that does not define the label name inherits the defaults above; a project that does not want the marker at all can leave the label absent in its tracker, in which case the add is a no-op the agent records and moves on.
@@ -79,12 +79,33 @@ The middle two rungs are the same idea seen at two resolutions: a parent reaches
79
79
  Notes:
80
80
 
81
81
  - **Blocked dominates.** A single blocked leaf surfaces blocked/attention on the parent even if other leaves are progressing, so a human sees the parent needs attention.
82
+ - **Blocked must name its leaf and its class.** "Blocked" alone is a single bit, and it is lossy in the one dimension that decides what the operator does next. Two holds that render identically are not the same problem: one waits on an external event and may clear with nobody touching it; the other waits on a person rewriting an acceptance criterion and will never clear on its own. Rendered the same, the second class accumulates silently — measured on one Epic at two occurrences, 32 identical hold comments and six weeks, while the initiative was two-thirds complete both times (#3045). See **Classifying a hold** below.
82
83
  - **"Required" leaves.** Optional or won't-do children do not hold a parent open; only the leaves that must ship for the parent to be complete are counted toward the env-rollup check.
83
84
  - **Least-advanced env wins.** The parent reflects the env the whole required set has collectively reached — never an env ahead of its laggard leaf. Native closure (below) fires only when the resolved env is the production/terminal value, never at an intermediate env (`On Dev`/`On Stg`).
84
85
  - **Rollup is recursive.** An Epic rolls up from its Stories, each of which rolls up from its own leaves. Evaluate bottom-up: a Story reaches an env only when its leaves have all reached at least that env; an Epic reaches it only when its Stories have.
85
86
  - **Vendor support varies.** Apply the rollup state the vendor can express. Where a vendor has no native intermediate state, use the nearest configured role or a metadata/comment signal rather than forcing a non-existent status (PRD #522 non-goal: vendors need not expose identical states).
86
87
  - **The parent never carries `ready`.** `ready` is a *human* "this is buildable, claim it" signal and only ever lives on leaves. Rollup moves a parent between non-ready container states (in-progress / per-env / blocked / terminal); it never sets the parent to `ready`. A container found carrying `ready` is a leaf-only-invariant violation — recompute its rolled state from its children and apply that (see `repair-intake`).
87
88
 
89
+ ### Classifying a hold
90
+
91
+ `rollup-blocker-classification` (`plugins/src/base/scripts/rollup-blocker-classification.mjs`) is the single implementation. It takes the child graph the vendor reader already produced and returns, per held leaf, a class and the actor who must clear it:
92
+
93
+ | Class | Recorded signal on the leaf | Who must act | Clears on its own? |
94
+ |---|---|---|---|
95
+ | `spec-defect` | the `spec_defect` marker (`config-resolution` → Build markers) | a person rewrites the acceptance criteria | never |
96
+ | `human-input` | the `human_needed` marker | a person supplies the input — access, a credential, a product decision | no |
97
+ | `hard-blocker` | at least one **open** `is blocked by` link | nobody | yes, when that work closes |
98
+ | `unknown` | none of the above | a person says which kind it is, then records it | no |
99
+
100
+ Four properties are load-bearing:
101
+
102
+ 1. **Recorded signals only.** A class comes from a marker or a link somebody wrote, never from reading the item's prose. There is no heuristic to drift.
103
+ 2. **It never reclassifies.** Deciding an acceptance criterion is unbuildable is a human product call. The tool makes the distinction *recordable and visible*; it does not make it. `unknown` is the honest answer, and it names the person who must resolve it rather than guessing.
104
+ 3. **A transparent parent is not the blocker.** A held item whose own children include a held one is reported *through*: the rollup names the leaf at the bottom of the chain and the path to it (`#1495 -> #1515 -> #1547`), which is what turns a five-level descent into one read.
105
+ 4. **It fails rather than reporting all-clear.** An unreadable tracker, a container with no children, and children none of which could be read each return a refusal, not `not-blocked`. A rollup that examined nothing and reported clean would be the same defect one level up.
106
+
107
+ The report is **composed per class**: a class with nothing in it produces no text, so the summary and the per-item lines cannot disagree (the `#3101` shape). It also carries a fingerprint of `container + held refs + classes`, so a cycle whose verdict is unchanged has nothing new to post and stays quiet — the 32 identical hold comments were one verdict restated on a schedule.
108
+
88
109
  ### The rollup env states are the configured "done" map — multi-env capable
89
110
 
90
111
  The env rungs are whatever the project configures for `done` — which is **env-keyed** (`config-resolution` "Env-keyed `done`"): a `done` map keyed by environment (`dev`, `staging`, `production`), each leaf's env resolved from its merged PR's base branch. This rule does **not** hardcode a `dev → staging → prod` promotion chain as required — that is a project-specific deploy topology; the ladder is simply the ordered keys of the project's `done` map. A downstream project with dev/staging/prod environments rolls a parent up to the least-advanced env value its required leaves have collectively reached (an intermediate-env parent state, e.g. `On Stg`), and only to the production `done` value once every required leaf is at production. The rule stays generic and multi-env capable.
@@ -31,6 +31,17 @@ Evaluate over the env ladder `in-progress < dev < staging < production` (the ord
31
31
  3. Else any leaf has **started** (claimed/in review, or shipped while a sibling has not) → parent is **in-progress** (`claimed`).
32
32
  4. Else (leaves exist but none started) → parent unchanged.
33
33
 
34
+ **Blocked dominates — but it must say which leaf and which kind.** A parent that rolls up to `blocked` names the blocking leaf (with the path to it) and the **class** of the hold, derived by `rollup-blocker-classification` from recorded signals only:
35
+
36
+ | Class | Recorded signal on the leaf | Who must act |
37
+ |---|---|---|
38
+ | `spec-defect` | the `spec_defect` marker (human-applied only) | a person rewrites the acceptance criteria — nothing external will ever clear it |
39
+ | `human-input` | the `human_needed` marker | a person supplies the input (access, credential, product decision) |
40
+ | `hard-blocker` | an open `is blocked by` link | nobody — it clears when that work closes |
41
+ | `unknown` | none of the above | a person says which kind it is, and records it |
42
+
43
+ Never infer a class from prose, and never auto-apply `spec_defect`: judging a criterion unbuildable is a human call, and `unknown` is the honest answer. A rollup that examined nothing — unreadable tracker, no children, no readable child — **fails**; it never reports not-blocked.
44
+
34
45
  **Blocked dominates.** A parent reaches an env only once all required leaves have reached at least that env. Intermediate-env rollup (`On Dev`/`On Stg`) happens, but native closure fires only at production `done`. Optional/won't-do children do not hold a parent open. Rollup is recursive — bottom-up. The parent never carries `ready`; a container found in `ready` is reconciled by rolling it up from its children.
35
46
 
36
47
  ## Terminal native closure