@codyswann/lisa 2.288.1 → 2.289.1

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 (83) hide show
  1. package/dist/core/upstream-evidence-manifest.js +6 -6
  2. package/package.json +1 -1
  3. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  4. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  5. package/plugins/lisa/.codex-plugin/skills/lisa-codify-verification/SKILL.md +8 -0
  6. package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +2 -0
  7. package/plugins/lisa/.codex-plugin/skills/lisa-jira-sync/SKILL.md +4 -2
  8. package/plugins/lisa/agents/jira-agent.md +1 -1
  9. package/plugins/lisa/rules/eager/config-resolution.md +10 -0
  10. package/plugins/lisa/rules/reference/verification.md +4 -0
  11. package/plugins/lisa/skills/lisa-codify-verification/SKILL.md +8 -0
  12. package/plugins/lisa/skills/lisa-implement/SKILL.md +2 -0
  13. package/plugins/lisa/skills/lisa-jira-sync/SKILL.md +4 -2
  14. package/plugins/lisa-agy/agents/jira-agent.md +1 -1
  15. package/plugins/lisa-agy/plugin.json +1 -1
  16. package/plugins/lisa-agy/skills/lisa-codify-verification/SKILL.md +8 -0
  17. package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +2 -0
  18. package/plugins/lisa-agy/skills/lisa-jira-sync/SKILL.md +4 -2
  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/agents/jira-agent.agent.md +1 -1
  26. package/plugins/lisa-copilot/rules/eager/config-resolution.md +10 -0
  27. package/plugins/lisa-copilot/rules/reference/verification.md +4 -0
  28. package/plugins/lisa-copilot/skills/lisa-codify-verification/SKILL.md +8 -0
  29. package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +2 -0
  30. package/plugins/lisa-copilot/skills/lisa-jira-sync/SKILL.md +4 -2
  31. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-cursor/agents/jira-agent.md +1 -1
  33. package/plugins/lisa-cursor/rules/config-resolution.mdc +10 -0
  34. package/plugins/lisa-cursor/rules/verification-reference.mdc +4 -0
  35. package/plugins/lisa-cursor/skills/lisa-codify-verification/SKILL.md +8 -0
  36. package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +2 -0
  37. package/plugins/lisa-cursor/skills/lisa-jira-sync/SKILL.md +4 -2
  38. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  40. package/plugins/lisa-expo-agy/plugin.json +1 -1
  41. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  45. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  46. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  50. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  51. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  55. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  56. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  60. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  61. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  65. package/plugins/lisa-rails-agy/plugin.json +1 -1
  66. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  70. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  71. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  75. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  76. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  78. package/plugins/src/base/agents/jira-agent.md +1 -1
  79. package/plugins/src/base/rules/eager/config-resolution.md +10 -0
  80. package/plugins/src/base/rules/reference/verification.md +4 -0
  81. package/plugins/src/base/skills/lisa-codify-verification/SKILL.md +8 -0
  82. package/plugins/src/base/skills/lisa-implement/SKILL.md +2 -0
  83. package/plugins/src/base/skills/lisa-jira-sync/SKILL.md +4 -2
@@ -195,7 +195,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
195
195
  "plugins/src/base/agents/github-agent.md": "05454419d3ea18dbbf45e45e0ca5782a6925c97816c6705eead9fcf597d776bc",
196
196
  "plugins/src/base/agents/github-build-intake.md": "5d948d04d39f864bae354c18f56735282e3f37127356e4942f57a10e99c09456",
197
197
  "plugins/src/base/agents/github-prd-intake.md": "d8d4cb8d246b0da7b70c98adb6305451be35f3ba4e3ea384aa086e8ed3d15b46",
198
- "plugins/src/base/agents/jira-agent.md": "0aff33624ae535692c278f5649dbe47e98d70e91d9764f7b0fa8277d77202c32",
198
+ "plugins/src/base/agents/jira-agent.md": "954faadefb231c3db6b51a50bc0320d5d49d1533eac05e12c60468156cbe6f40",
199
199
  "plugins/src/base/agents/jira-build-intake.md": "51397c08fe09380f53bd630fb81ff28905a532ea71336a424e944c28a0c2db55",
200
200
  "plugins/src/base/agents/learner.md": "50582e72b11eeb6b085845f2e32c31a6dcedd0439ca566bb1cca228dd1a45fee",
201
201
  "plugins/src/base/agents/learning-judge.md": "28618c3e20a0f790e4d254a9c8118645774233f19e3042b3cfeddf4ffbaf783a",
@@ -308,7 +308,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
308
308
  "plugins/src/base/rules/eager/claim-archaeology.md": "96afa034075593dfb7433c5c990b472a6b6f7320332da42ef54b1f01fa45664b",
309
309
  "plugins/src/base/rules/eager/claim-evidence-mapping.md": "d12a6153b8c22db2826153c479d107c7a885e22cbcdd49e4fd8193e0cbbe8ae3",
310
310
  "plugins/src/base/rules/eager/coding-philosophy.md": "cf2c52032e0368d81f17f002fed5c957ab350d01fc4a43f66b5f366516bac54a",
311
- "plugins/src/base/rules/eager/config-resolution.md": "2689c1f47903a5f6c84677fbfd2f1f148096faf122b7498b21d3b0f2345c6c87",
311
+ "plugins/src/base/rules/eager/config-resolution.md": "8d292784056d0cc62d78cc079286a2fdd6381e14452615b7aa8db0d31c3ff2ca",
312
312
  "plugins/src/base/rules/eager/convergent-review.md": "ba4ba53863ef99be353c07c01195fa4ae2923ef2b2a5ad4427072802c260d208",
313
313
  "plugins/src/base/rules/eager/dependency-decision-records.md": "e22888f107906992e863fca50f26c2c4b124da7132535cacfac71e4f3085728f",
314
314
  "plugins/src/base/rules/eager/dependency-internalization-kit.md": "9e2cc78afffc477c14718390ed88c42f781911c51fb7c13dada497f9e956b1a3",
@@ -365,7 +365,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
365
365
  "plugins/src/base/rules/reference/tracked-work.md": "cc956e7a61d8f65bfc4e0e3bc4c3da1b5a9e541683aa17dc1850979d04abac24",
366
366
  "plugins/src/base/rules/reference/upstream-to-lisa.md": "dcf07f8eba66aaf1d132bfaeff73cbf7576279822893235a3c3f8cbc4a4a3323",
367
367
  "plugins/src/base/rules/reference/usage-accounting.md": "d2a24f8f176dbd900beb6e396fc669008b0be0c9033fac5c1c1ecc19002bd7c2",
368
- "plugins/src/base/rules/reference/verification.md": "9aa9ec95a739268181b74d6952fa7cda16c96d633ece6a3e889d3b28a8f8ffb7",
368
+ "plugins/src/base/rules/reference/verification.md": "0a4424d79fae5ce028d08b98523a01f51cbe07c1bcc0a094048d7a25adc075d8",
369
369
  "plugins/src/base/rules/reference/wiki-knowledge-source.md": "305d38e13984c2a64144f302336405d0ccbec493a6ed3ec67d210fed44940717",
370
370
  "plugins/src/base/scripts/automation-run-record.mjs": "89143e06975d8333b137fd2bdb5f12bcd703403752337f00c25d18fefba6a4c8",
371
371
  "plugins/src/base/scripts/automation-status-claude-adapter.mjs": "b1054acf4a5cbbe5354bd62a22b96533bcbc69b6cb9245976ceb8af638a04494",
@@ -394,7 +394,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
394
394
  "plugins/src/base/skills/lisa-automation-status/SKILL.md": "a283afab506d8e52970c6df566b4504a2ed015493cee4de6debe5b62a09782eb",
395
395
  "plugins/src/base/skills/lisa-bug-triage/SKILL.md": "90b0f1388717f81c4e187ab714be01d02a9f41592a4c26487aeb9c26a0959493",
396
396
  "plugins/src/base/skills/lisa-codebase-research/SKILL.md": "77dbc2d7e86e5027df486294de315bb539a2ece84bd4b38e47ccc108f8c2875e",
397
- "plugins/src/base/skills/lisa-codify-verification/SKILL.md": "fc15f1f64766c5e40dbffb160080df519e375a9727ed3e8841df3d1b23fb0ffe",
397
+ "plugins/src/base/skills/lisa-codify-verification/SKILL.md": "45cf7e74697fcc0b8769b31c674dbf0b18e19eb1ceab6a77f608b568512def15",
398
398
  "plugins/src/base/skills/lisa-confluence-prd-intake/SKILL.md": "a6a099abeb32940d44da7e9a6a62c3519f64efa85294c4b996789fa4fba97461",
399
399
  "plugins/src/base/skills/lisa-confluence-to-tracker/SKILL.md": "71ab183ba9f14b83d2e940f4b5ec0e2282b75e30d9d452689d330b5345132bba",
400
400
  "plugins/src/base/skills/lisa-confluence-write-prd/SKILL.md": "548c7f7da38372e3b39bc051d5f09417f5008c880caddb59bc6a8b6e05b0aa7b",
@@ -426,7 +426,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
426
426
  "plugins/src/base/skills/lisa-github-write-issue/SKILL.md": "ee54b3d14cc5dd3a68a8c36590102dd02f49334c9493ad52fa8c7f35157073b1",
427
427
  "plugins/src/base/skills/lisa-github-write-prd/SKILL.md": "bc919c52e2f42129d41a3f40279d2def99486ec58bed2dab51ca7166b427a947",
428
428
  "plugins/src/base/skills/lisa-health/SKILL.md": "dfdb08a863e78bff42671793dcec29cfae0654db18ebf66a4aa77aeb56ddb775",
429
- "plugins/src/base/skills/lisa-implement/SKILL.md": "634f09dbd2654af070be393f5fd41e8d7fedee7437be2890e54d47ec59258539",
429
+ "plugins/src/base/skills/lisa-implement/SKILL.md": "6271b8c4dd34efb630020a63e03d8df813d4faccb81517dfb3637ef2433d968d",
430
430
  "plugins/src/base/skills/lisa-improve-code-complexity/SKILL.md": "24ab5b193b409db6ee6bee981a1c0a48d08991782d7846116ad01658c8bc1ae8",
431
431
  "plugins/src/base/skills/lisa-improve-harness/SKILL.md": "bafda5d2f9b86c48cd16bf0015528fdf5891675221d662fdc533aaad66aad669",
432
432
  "plugins/src/base/skills/lisa-improve-max-lines-per-function/SKILL.md": "95c875950c9848fdaf520a18b9bbb264e33d7347be10170add768e01d9cd8e52",
@@ -447,7 +447,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
447
447
  "plugins/src/base/skills/lisa-jira-journey/scripts/parse-plan.py": "0c1921c0996e5d82c2c833e23afdab82a0b2e506f1b8783f87bd7ac0edd789e6",
448
448
  "plugins/src/base/skills/lisa-jira-read-ticket/SKILL.md": "1b7cd9a56bae1108c9814b8f8365411dad1e7f3cd294a28baeab6321d0b636b4",
449
449
  "plugins/src/base/skills/lisa-jira-read-ticket/scripts/download-attachment.sh": "f0a9b3c5bd82f0f86edb0ad86db5a9501cced9ec4a2a3bfa644bdff01c8eb460",
450
- "plugins/src/base/skills/lisa-jira-sync/SKILL.md": "51f640adce2fc6f2d8ddbf6edcd05f3d0ab86e4848fd54cb566c64c2692f2faf",
450
+ "plugins/src/base/skills/lisa-jira-sync/SKILL.md": "9f2e6709c2ac9279e510b99e53acd2075c915619dec69446029715b5045c1bf1",
451
451
  "plugins/src/base/skills/lisa-jira-validate-ticket/SKILL.md": "7a318a0ef623430c40f462ae1181c88f44ec0ee945c200dcb2fa73c13c451880",
452
452
  "plugins/src/base/skills/lisa-jira-verify/SKILL.md": "4e48dcd9e1144837890359e75cc405280bf5f52cf497e44f294b608ad681580c",
453
453
  "plugins/src/base/skills/lisa-jira-write-ticket/SKILL.md": "7328f4d8df5b20002ddcf0af6eb59d32a3e1cd6ec3c10521a3e828e6c09f6722",
package/package.json CHANGED
@@ -113,7 +113,7 @@
113
113
  "brace-expansion": ">=5.0.6"
114
114
  },
115
115
  "name": "@codyswann/lisa",
116
- "version": "2.288.1",
116
+ "version": "2.289.1",
117
117
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
118
118
  "main": "dist/index.js",
119
119
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -115,6 +115,14 @@ step frames) with deterministic rendering. CI's `verification-coverage` check
115
115
  requires a verification-spec delta on every behavioral change. See the
116
116
  `reference/verification.md` "Making verification concrete (UAT)" section.
117
117
 
118
+ ### 3a. Drift-aware live-environment assertions
119
+
120
+ When the codified test — or the remote re-verification it encodes — runs against a **live, deployed environment**, the environment will not hold still between the original verification and any later run: deploys, out-of-band infra applies, and data churn are normal, not exceptional. Encode the verification accordingly:
121
+
122
+ - **Assert invariants, not snapshot equality.** Pin the properties that define correctness — document shape, exact paths, forbidden values/hosts, internal coherence (e.g. every URL in a discovery document uses the same host) — never a byte-for-byte diff against a captured baseline. A snapshot diff false-fails the moment the environment legitimately moves.
123
+ - **Classify drift, don't just detect it.** When observed state differs from the baseline evidence, treat that as a classification problem, and record the classification in the verdict's canonical `drift` field (`none | progress | regression | unrelated_churn`, defined by the `verdict.json` contract in `reference/verification.md`): **progress** (the change being verified, or a related fix, landed), **regression** (an invariant broke), or **unrelated churn**. Drift classified as progress or unrelated churn passes, with the environment change surfaced as evidence; only a broken invariant fails.
124
+ - **Never encode "the environment will hold still" as an implicit assumption.** Evidence capture that only makes sense if nothing changed between baseline and re-check has that assumption baked in even when no assertion states it — e.g. an OAuth discovery document whose host legitimately flipped from a provider-prefix domain to the canonical vanity host between a local baseline and a remote re-check ~30 minutes later would false-fail a snapshot verifier, while an invariant-asserting verifier passes correctly and records the drift as progress.
125
+
118
126
  ### 4. Run the test in isolation
119
127
 
120
128
  Run only the new test, using whatever per-test invocation the project supports:
@@ -314,3 +314,5 @@ Before shutting down the team, execute the Verify flow:
314
314
  13. `ops-specialist`: post-deploy health check, monitor for errors in first minutes
315
315
  14. If remote verification fails, create a task for the agent team to find out why it failed, fix it and return to step 5. **Bound this loop**: after a small number of full fix→deploy→reverify cycles without reaching a passing remote verdict (treat ~3 as the ceiling unless the work item states otherwise), stop retrying — file a build-ready fix ticket, write the verdict with `status: "blocked"` and the diagnosis, and move the work item to blocked rather than looping indefinitely. The completion gate releases on a `blocked` verdict, so the flow ends with a recorded outcome instead of a silent spin or a self-declared success.
316
316
  15. After true terminal completion — required merge/deploy/verification passed, usage/evidence and two-way PR linkage are recorded, and the work item is terminal — run `node scripts/lisa-work-item.mjs clear` and verify the worktree has no current binding. Do not clear on an interruption or blocked outcome; preserving the binding is what keeps resumed work attributable.
317
+
318
+ **Ticket status transitions throughout this flow are config-bound** per the **Tracker status vocabulary** section of the `config-resolution` rule: whoever performs the tracker write — the lead included, in runtimes where the tracker MCP is lead-only — may only target statuses named in the configured workflow map (`claimed`, `blocked`, env-keyed `done`, and `review`/`qa` when configured). Never adopt a status discovered from the tracker's live workflow; a lifecycle stage with no configured status gets a comment, not a transition.
@@ -66,9 +66,11 @@ Based on the milestone, suggest (but don't automatically perform) a status trans
66
66
 
67
67
  | Milestone | Suggested Status |
68
68
  |-----------|-----------------|
69
- | Plan created | "In Progress" |
69
+ | Plan created | configured `jira.workflow.claimed` status |
70
70
  | PR ready | configured `jira.workflow.review` status, or no transition when unconfigured |
71
- | PR merged | "Done" |
71
+ | PR merged | configured `jira.workflow.done` status for the PR's target environment (env-keyed `done` resolved via `deploy.branches`), or no transition when unconfigured |
72
+
73
+ Every suggested or performed transition is bound by the **Tracker status vocabulary** section of the `config-resolution` rule: only statuses named in the configured workflow map, never statuses discovered from the tracker's live workflow (transition lists, board columns, other tickets) — and this binds the lead performing tracker writes exactly as it binds a subagent. A milestone with no configured status gets a comment, not a transition.
72
74
 
73
75
  ### Step 5: Parent Status Rollup (`--rollup`)
74
76
 
@@ -127,7 +127,7 @@ Note: `done` may be a string or an env-keyed map (`{ dev, staging, production }`
127
127
  ## Rules
128
128
 
129
129
  - Never auto-transition ticket status, with one explicit exception: when `jira-verify` returns `FAIL` for the pre-flight gate (Step 2), first run the `pre-flight-autofill` draft-then-block procedure (draft the authorable missing sections into the ticket as labeled assumptions), then transition to the configured `blocked` status, add the configured `human_needed` marker label (`jira.labels.human_needed`, default `Human Needed`), and reassign to the Reporter with a confirmation comment. Every other status change remains a suggestion the human confirms.
130
- - Any transition is config-bound: never invent transitions; a transition may target only a status named in `config.jira.workflow`. Don't guess from the live workflow. The evidence-time review hop (Step 7) follows this rule too — it is config-bound, optional, and skipped when `jira.workflow.review` is absent (the ticket stays in `claimed`).
130
+ - Any transition is config-bound per the **Tracker status vocabulary** section of the `config-resolution` rule: never invent transitions; a transition may target only a status named in `config.jira.workflow`. Don't guess from the live workflow. The evidence-time review hop (Step 7) follows this rule too — it is config-bound, optional, and skipped when `jira.workflow.review` is absent (the ticket stays in `claimed`).
131
131
  - Always read the full ticket graph via `jira-read-ticket` before determining intent — don't rely on ticket type alone
132
132
  - Never create or materially edit a ticket by calling MCP write tools directly — always delegate to `jira-write-ticket` so relationships, Gherkin criteria, and metadata gates are enforced
133
133
  - If sign-in credentials are in the ticket, extract and pass them to the flow. If the ticket touches an authenticated surface and credentials are missing, that is a Step 2 failure — block and reassign rather than guessing.
@@ -21,6 +21,16 @@ This applies before declaring connection state, before running any `acli jira *`
21
21
 
22
22
  Project tracker (`jira` / `github` / `linear`) is read from `.lisa.config.json` `tracker`. Vendor-neutral skills MUST dispatch through the configured tracker, never infer it from arguments. Missing `tracker` → stop and instruct the user to run the matching `/lisa:setup:*` skill.
23
23
 
24
+ ## Tracker status vocabulary
25
+
26
+ **A status transition may target only a status named in the project's configured workflow map** (`jira.workflow.*` for JIRA; the equivalent label/state map for GitHub and Linear). The configured map is the COMPLETE authorized vocabulary — not a starting point.
27
+
28
+ - **Never adopt statuses discovered from the tracker's live workflow metadata** — transition lists (`getTransitionsForJiraIssue` targets), board columns, status descriptions, or statuses seen on other tickets. A tracker workflow usually contains more statuses than the config names; those extra statuses are not lisa's to use. The live workflow is consulted only to find the transition *id* that reaches a config-named status.
29
+ - **A lifecycle stage with no configured status gets no transition.** If the flow reaches a stage the map does not name (e.g. "PR open awaiting review" when `jira.workflow.review` is unset, or a QA-ready stage with no `qa` mapping), leave the status where it is and record the stage in a comment. Do not pick the nearest-sounding tracker status.
30
+ - **This binds every actor that writes to the tracker** — the lead as much as any subagent. In runtimes where interactively-authenticated MCPs are lead-only, the lead performs the tracker writes for the whole flow; loading an implement/sync skill without the agent definition does not relax this rule.
31
+
32
+ This is the shared slug for the config-bound-transitions policy (the `leaf-only-lifecycle` precedent: one slug, never divergent per-surface prose). Skills and agent definitions cite it rather than restating it.
33
+
24
34
  ## Repo identity
25
35
 
26
36
  `repo:<name>` is the canonical label for which repo a work item belongs to. Resolve current-repo identity in this priority order: `.lisa.config.local.json` `repo` → `.lisa.config.json` `repo` → `.lisa.config.json` `github.repo` → `basename -s .git "$(git remote get-url origin)"`. If none resolve, stop with a clear error.
@@ -164,6 +164,8 @@ The committed verdict carries the machine-readable half:
164
164
  evidence/<ticket>/verdict.json
165
165
  not_established: [] # what was NOT proved; may be empty
166
166
  not_established_reviewed: true # attests the list was reviewed; may NEVER be omitted
167
+ drift: none # live-environment baseline-vs-now drift classification:
168
+ # none | progress | regression | unrelated_churn
167
169
  artifact: { repository, base_sha, head_sha, build_id, environment, observed_at }
168
170
  evidence: [ { evidence_id, kind, locator,
169
171
  artifact_head_sha, # the head_sha in force when THIS artifact was captured
@@ -205,6 +207,8 @@ Verification happens at two stages in the workflow:
205
207
 
206
208
  Both levels use the same verification types table above. The difference is the environment, not the rigor.
207
209
 
210
+ Remote verification must be **drift-aware**: the target environment may legitimately change between the local baseline and the remote run (its own deploy, out-of-band infra changes, data churn). Assert invariants — shape, exact paths, forbidden values, internal coherence — rather than equality with the local evidence snapshot; when observed state differs from the baseline, classify the drift and record it in the verdict's canonical `drift` field (`none | progress | regression | unrelated_churn`, defined in the `verdict.json` contract above). Only a broken invariant is a failure; never encode "the environment held still" as an implicit assumption.
211
+
208
212
  ---
209
213
 
210
214
  ## Credential-Gated Verification
@@ -115,6 +115,14 @@ step frames) with deterministic rendering. CI's `verification-coverage` check
115
115
  requires a verification-spec delta on every behavioral change. See the
116
116
  `reference/verification.md` "Making verification concrete (UAT)" section.
117
117
 
118
+ ### 3a. Drift-aware live-environment assertions
119
+
120
+ When the codified test — or the remote re-verification it encodes — runs against a **live, deployed environment**, the environment will not hold still between the original verification and any later run: deploys, out-of-band infra applies, and data churn are normal, not exceptional. Encode the verification accordingly:
121
+
122
+ - **Assert invariants, not snapshot equality.** Pin the properties that define correctness — document shape, exact paths, forbidden values/hosts, internal coherence (e.g. every URL in a discovery document uses the same host) — never a byte-for-byte diff against a captured baseline. A snapshot diff false-fails the moment the environment legitimately moves.
123
+ - **Classify drift, don't just detect it.** When observed state differs from the baseline evidence, treat that as a classification problem, and record the classification in the verdict's canonical `drift` field (`none | progress | regression | unrelated_churn`, defined by the `verdict.json` contract in `reference/verification.md`): **progress** (the change being verified, or a related fix, landed), **regression** (an invariant broke), or **unrelated churn**. Drift classified as progress or unrelated churn passes, with the environment change surfaced as evidence; only a broken invariant fails.
124
+ - **Never encode "the environment will hold still" as an implicit assumption.** Evidence capture that only makes sense if nothing changed between baseline and re-check has that assumption baked in even when no assertion states it — e.g. an OAuth discovery document whose host legitimately flipped from a provider-prefix domain to the canonical vanity host between a local baseline and a remote re-check ~30 minutes later would false-fail a snapshot verifier, while an invariant-asserting verifier passes correctly and records the drift as progress.
125
+
118
126
  ### 4. Run the test in isolation
119
127
 
120
128
  Run only the new test, using whatever per-test invocation the project supports:
@@ -314,3 +314,5 @@ Before shutting down the team, execute the Verify flow:
314
314
  13. `ops-specialist`: post-deploy health check, monitor for errors in first minutes
315
315
  14. If remote verification fails, create a task for the agent team to find out why it failed, fix it and return to step 5. **Bound this loop**: after a small number of full fix→deploy→reverify cycles without reaching a passing remote verdict (treat ~3 as the ceiling unless the work item states otherwise), stop retrying — file a build-ready fix ticket, write the verdict with `status: "blocked"` and the diagnosis, and move the work item to blocked rather than looping indefinitely. The completion gate releases on a `blocked` verdict, so the flow ends with a recorded outcome instead of a silent spin or a self-declared success.
316
316
  15. After true terminal completion — required merge/deploy/verification passed, usage/evidence and two-way PR linkage are recorded, and the work item is terminal — run `node scripts/lisa-work-item.mjs clear` and verify the worktree has no current binding. Do not clear on an interruption or blocked outcome; preserving the binding is what keeps resumed work attributable.
317
+
318
+ **Ticket status transitions throughout this flow are config-bound** per the **Tracker status vocabulary** section of the `config-resolution` rule: whoever performs the tracker write — the lead included, in runtimes where the tracker MCP is lead-only — may only target statuses named in the configured workflow map (`claimed`, `blocked`, env-keyed `done`, and `review`/`qa` when configured). Never adopt a status discovered from the tracker's live workflow; a lifecycle stage with no configured status gets a comment, not a transition.
@@ -66,9 +66,11 @@ Based on the milestone, suggest (but don't automatically perform) a status trans
66
66
 
67
67
  | Milestone | Suggested Status |
68
68
  |-----------|-----------------|
69
- | Plan created | "In Progress" |
69
+ | Plan created | configured `jira.workflow.claimed` status |
70
70
  | PR ready | configured `jira.workflow.review` status, or no transition when unconfigured |
71
- | PR merged | "Done" |
71
+ | PR merged | configured `jira.workflow.done` status for the PR's target environment (env-keyed `done` resolved via `deploy.branches`), or no transition when unconfigured |
72
+
73
+ Every suggested or performed transition is bound by the **Tracker status vocabulary** section of the `config-resolution` rule: only statuses named in the configured workflow map, never statuses discovered from the tracker's live workflow (transition lists, board columns, other tickets) — and this binds the lead performing tracker writes exactly as it binds a subagent. A milestone with no configured status gets a comment, not a transition.
72
74
 
73
75
  ### Step 5: Parent Status Rollup (`--rollup`)
74
76
 
@@ -127,7 +127,7 @@ Note: `done` may be a string or an env-keyed map (`{ dev, staging, production }`
127
127
  ## Rules
128
128
 
129
129
  - Never auto-transition ticket status, with one explicit exception: when `jira-verify` returns `FAIL` for the pre-flight gate (Step 2), first run the `pre-flight-autofill` draft-then-block procedure (draft the authorable missing sections into the ticket as labeled assumptions), then transition to the configured `blocked` status, add the configured `human_needed` marker label (`jira.labels.human_needed`, default `Human Needed`), and reassign to the Reporter with a confirmation comment. Every other status change remains a suggestion the human confirms.
130
- - Any transition is config-bound: never invent transitions; a transition may target only a status named in `config.jira.workflow`. Don't guess from the live workflow. The evidence-time review hop (Step 7) follows this rule too — it is config-bound, optional, and skipped when `jira.workflow.review` is absent (the ticket stays in `claimed`).
130
+ - Any transition is config-bound per the **Tracker status vocabulary** section of the `config-resolution` rule: never invent transitions; a transition may target only a status named in `config.jira.workflow`. Don't guess from the live workflow. The evidence-time review hop (Step 7) follows this rule too — it is config-bound, optional, and skipped when `jira.workflow.review` is absent (the ticket stays in `claimed`).
131
131
  - Always read the full ticket graph via `jira-read-ticket` before determining intent — don't rely on ticket type alone
132
132
  - Never create or materially edit a ticket by calling MCP write tools directly — always delegate to `jira-write-ticket` so relationships, Gherkin criteria, and metadata gates are enforced
133
133
  - If sign-in credentials are in the ticket, extract and pass them to the flow. If the ticket touches an authenticated surface and credentials are missing, that is a Step 2 failure — block and reassign rather than guessing.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -115,6 +115,14 @@ step frames) with deterministic rendering. CI's `verification-coverage` check
115
115
  requires a verification-spec delta on every behavioral change. See the
116
116
  `reference/verification.md` "Making verification concrete (UAT)" section.
117
117
 
118
+ ### 3a. Drift-aware live-environment assertions
119
+
120
+ When the codified test — or the remote re-verification it encodes — runs against a **live, deployed environment**, the environment will not hold still between the original verification and any later run: deploys, out-of-band infra applies, and data churn are normal, not exceptional. Encode the verification accordingly:
121
+
122
+ - **Assert invariants, not snapshot equality.** Pin the properties that define correctness — document shape, exact paths, forbidden values/hosts, internal coherence (e.g. every URL in a discovery document uses the same host) — never a byte-for-byte diff against a captured baseline. A snapshot diff false-fails the moment the environment legitimately moves.
123
+ - **Classify drift, don't just detect it.** When observed state differs from the baseline evidence, treat that as a classification problem, and record the classification in the verdict's canonical `drift` field (`none | progress | regression | unrelated_churn`, defined by the `verdict.json` contract in `reference/verification.md`): **progress** (the change being verified, or a related fix, landed), **regression** (an invariant broke), or **unrelated churn**. Drift classified as progress or unrelated churn passes, with the environment change surfaced as evidence; only a broken invariant fails.
124
+ - **Never encode "the environment will hold still" as an implicit assumption.** Evidence capture that only makes sense if nothing changed between baseline and re-check has that assumption baked in even when no assertion states it — e.g. an OAuth discovery document whose host legitimately flipped from a provider-prefix domain to the canonical vanity host between a local baseline and a remote re-check ~30 minutes later would false-fail a snapshot verifier, while an invariant-asserting verifier passes correctly and records the drift as progress.
125
+
118
126
  ### 4. Run the test in isolation
119
127
 
120
128
  Run only the new test, using whatever per-test invocation the project supports:
@@ -314,3 +314,5 @@ Before shutting down the team, execute the Verify flow:
314
314
  13. `ops-specialist`: post-deploy health check, monitor for errors in first minutes
315
315
  14. If remote verification fails, create a task for the agent team to find out why it failed, fix it and return to step 5. **Bound this loop**: after a small number of full fix→deploy→reverify cycles without reaching a passing remote verdict (treat ~3 as the ceiling unless the work item states otherwise), stop retrying — file a build-ready fix ticket, write the verdict with `status: "blocked"` and the diagnosis, and move the work item to blocked rather than looping indefinitely. The completion gate releases on a `blocked` verdict, so the flow ends with a recorded outcome instead of a silent spin or a self-declared success.
316
316
  15. After true terminal completion — required merge/deploy/verification passed, usage/evidence and two-way PR linkage are recorded, and the work item is terminal — run `node scripts/lisa-work-item.mjs clear` and verify the worktree has no current binding. Do not clear on an interruption or blocked outcome; preserving the binding is what keeps resumed work attributable.
317
+
318
+ **Ticket status transitions throughout this flow are config-bound** per the **Tracker status vocabulary** section of the `config-resolution` rule: whoever performs the tracker write — the lead included, in runtimes where the tracker MCP is lead-only — may only target statuses named in the configured workflow map (`claimed`, `blocked`, env-keyed `done`, and `review`/`qa` when configured). Never adopt a status discovered from the tracker's live workflow; a lifecycle stage with no configured status gets a comment, not a transition.
@@ -66,9 +66,11 @@ Based on the milestone, suggest (but don't automatically perform) a status trans
66
66
 
67
67
  | Milestone | Suggested Status |
68
68
  |-----------|-----------------|
69
- | Plan created | "In Progress" |
69
+ | Plan created | configured `jira.workflow.claimed` status |
70
70
  | PR ready | configured `jira.workflow.review` status, or no transition when unconfigured |
71
- | PR merged | "Done" |
71
+ | PR merged | configured `jira.workflow.done` status for the PR's target environment (env-keyed `done` resolved via `deploy.branches`), or no transition when unconfigured |
72
+
73
+ Every suggested or performed transition is bound by the **Tracker status vocabulary** section of the `config-resolution` rule: only statuses named in the configured workflow map, never statuses discovered from the tracker's live workflow (transition lists, board columns, other tickets) — and this binds the lead performing tracker writes exactly as it binds a subagent. A milestone with no configured status gets a comment, not a transition.
72
74
 
73
75
  ### Step 5: Parent Status Rollup (`--rollup`)
74
76
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -127,7 +127,7 @@ Note: `done` may be a string or an env-keyed map (`{ dev, staging, production }`
127
127
  ## Rules
128
128
 
129
129
  - Never auto-transition ticket status, with one explicit exception: when `jira-verify` returns `FAIL` for the pre-flight gate (Step 2), first run the `pre-flight-autofill` draft-then-block procedure (draft the authorable missing sections into the ticket as labeled assumptions), then transition to the configured `blocked` status, add the configured `human_needed` marker label (`jira.labels.human_needed`, default `Human Needed`), and reassign to the Reporter with a confirmation comment. Every other status change remains a suggestion the human confirms.
130
- - Any transition is config-bound: never invent transitions; a transition may target only a status named in `config.jira.workflow`. Don't guess from the live workflow. The evidence-time review hop (Step 7) follows this rule too — it is config-bound, optional, and skipped when `jira.workflow.review` is absent (the ticket stays in `claimed`).
130
+ - Any transition is config-bound per the **Tracker status vocabulary** section of the `config-resolution` rule: never invent transitions; a transition may target only a status named in `config.jira.workflow`. Don't guess from the live workflow. The evidence-time review hop (Step 7) follows this rule too — it is config-bound, optional, and skipped when `jira.workflow.review` is absent (the ticket stays in `claimed`).
131
131
  - Always read the full ticket graph via `jira-read-ticket` before determining intent — don't rely on ticket type alone
132
132
  - Never create or materially edit a ticket by calling MCP write tools directly — always delegate to `jira-write-ticket` so relationships, Gherkin criteria, and metadata gates are enforced
133
133
  - If sign-in credentials are in the ticket, extract and pass them to the flow. If the ticket touches an authenticated surface and credentials are missing, that is a Step 2 failure — block and reassign rather than guessing.
@@ -21,6 +21,16 @@ This applies before declaring connection state, before running any `acli jira *`
21
21
 
22
22
  Project tracker (`jira` / `github` / `linear`) is read from `.lisa.config.json` `tracker`. Vendor-neutral skills MUST dispatch through the configured tracker, never infer it from arguments. Missing `tracker` → stop and instruct the user to run the matching `/lisa:setup:*` skill.
23
23
 
24
+ ## Tracker status vocabulary
25
+
26
+ **A status transition may target only a status named in the project's configured workflow map** (`jira.workflow.*` for JIRA; the equivalent label/state map for GitHub and Linear). The configured map is the COMPLETE authorized vocabulary — not a starting point.
27
+
28
+ - **Never adopt statuses discovered from the tracker's live workflow metadata** — transition lists (`getTransitionsForJiraIssue` targets), board columns, status descriptions, or statuses seen on other tickets. A tracker workflow usually contains more statuses than the config names; those extra statuses are not lisa's to use. The live workflow is consulted only to find the transition *id* that reaches a config-named status.
29
+ - **A lifecycle stage with no configured status gets no transition.** If the flow reaches a stage the map does not name (e.g. "PR open awaiting review" when `jira.workflow.review` is unset, or a QA-ready stage with no `qa` mapping), leave the status where it is and record the stage in a comment. Do not pick the nearest-sounding tracker status.
30
+ - **This binds every actor that writes to the tracker** — the lead as much as any subagent. In runtimes where interactively-authenticated MCPs are lead-only, the lead performs the tracker writes for the whole flow; loading an implement/sync skill without the agent definition does not relax this rule.
31
+
32
+ This is the shared slug for the config-bound-transitions policy (the `leaf-only-lifecycle` precedent: one slug, never divergent per-surface prose). Skills and agent definitions cite it rather than restating it.
33
+
24
34
  ## Repo identity
25
35
 
26
36
  `repo:<name>` is the canonical label for which repo a work item belongs to. Resolve current-repo identity in this priority order: `.lisa.config.local.json` `repo` → `.lisa.config.json` `repo` → `.lisa.config.json` `github.repo` → `basename -s .git "$(git remote get-url origin)"`. If none resolve, stop with a clear error.
@@ -164,6 +164,8 @@ The committed verdict carries the machine-readable half:
164
164
  evidence/<ticket>/verdict.json
165
165
  not_established: [] # what was NOT proved; may be empty
166
166
  not_established_reviewed: true # attests the list was reviewed; may NEVER be omitted
167
+ drift: none # live-environment baseline-vs-now drift classification:
168
+ # none | progress | regression | unrelated_churn
167
169
  artifact: { repository, base_sha, head_sha, build_id, environment, observed_at }
168
170
  evidence: [ { evidence_id, kind, locator,
169
171
  artifact_head_sha, # the head_sha in force when THIS artifact was captured
@@ -205,6 +207,8 @@ Verification happens at two stages in the workflow:
205
207
 
206
208
  Both levels use the same verification types table above. The difference is the environment, not the rigor.
207
209
 
210
+ Remote verification must be **drift-aware**: the target environment may legitimately change between the local baseline and the remote run (its own deploy, out-of-band infra changes, data churn). Assert invariants — shape, exact paths, forbidden values, internal coherence — rather than equality with the local evidence snapshot; when observed state differs from the baseline, classify the drift and record it in the verdict's canonical `drift` field (`none | progress | regression | unrelated_churn`, defined in the `verdict.json` contract above). Only a broken invariant is a failure; never encode "the environment held still" as an implicit assumption.
211
+
208
212
  ---
209
213
 
210
214
  ## Credential-Gated Verification
@@ -115,6 +115,14 @@ step frames) with deterministic rendering. CI's `verification-coverage` check
115
115
  requires a verification-spec delta on every behavioral change. See the
116
116
  `reference/verification.md` "Making verification concrete (UAT)" section.
117
117
 
118
+ ### 3a. Drift-aware live-environment assertions
119
+
120
+ When the codified test — or the remote re-verification it encodes — runs against a **live, deployed environment**, the environment will not hold still between the original verification and any later run: deploys, out-of-band infra applies, and data churn are normal, not exceptional. Encode the verification accordingly:
121
+
122
+ - **Assert invariants, not snapshot equality.** Pin the properties that define correctness — document shape, exact paths, forbidden values/hosts, internal coherence (e.g. every URL in a discovery document uses the same host) — never a byte-for-byte diff against a captured baseline. A snapshot diff false-fails the moment the environment legitimately moves.
123
+ - **Classify drift, don't just detect it.** When observed state differs from the baseline evidence, treat that as a classification problem, and record the classification in the verdict's canonical `drift` field (`none | progress | regression | unrelated_churn`, defined by the `verdict.json` contract in `reference/verification.md`): **progress** (the change being verified, or a related fix, landed), **regression** (an invariant broke), or **unrelated churn**. Drift classified as progress or unrelated churn passes, with the environment change surfaced as evidence; only a broken invariant fails.
124
+ - **Never encode "the environment will hold still" as an implicit assumption.** Evidence capture that only makes sense if nothing changed between baseline and re-check has that assumption baked in even when no assertion states it — e.g. an OAuth discovery document whose host legitimately flipped from a provider-prefix domain to the canonical vanity host between a local baseline and a remote re-check ~30 minutes later would false-fail a snapshot verifier, while an invariant-asserting verifier passes correctly and records the drift as progress.
125
+
118
126
  ### 4. Run the test in isolation
119
127
 
120
128
  Run only the new test, using whatever per-test invocation the project supports:
@@ -314,3 +314,5 @@ Before shutting down the team, execute the Verify flow:
314
314
  13. `ops-specialist`: post-deploy health check, monitor for errors in first minutes
315
315
  14. If remote verification fails, create a task for the agent team to find out why it failed, fix it and return to step 5. **Bound this loop**: after a small number of full fix→deploy→reverify cycles without reaching a passing remote verdict (treat ~3 as the ceiling unless the work item states otherwise), stop retrying — file a build-ready fix ticket, write the verdict with `status: "blocked"` and the diagnosis, and move the work item to blocked rather than looping indefinitely. The completion gate releases on a `blocked` verdict, so the flow ends with a recorded outcome instead of a silent spin or a self-declared success.
316
316
  15. After true terminal completion — required merge/deploy/verification passed, usage/evidence and two-way PR linkage are recorded, and the work item is terminal — run `node scripts/lisa-work-item.mjs clear` and verify the worktree has no current binding. Do not clear on an interruption or blocked outcome; preserving the binding is what keeps resumed work attributable.
317
+
318
+ **Ticket status transitions throughout this flow are config-bound** per the **Tracker status vocabulary** section of the `config-resolution` rule: whoever performs the tracker write — the lead included, in runtimes where the tracker MCP is lead-only — may only target statuses named in the configured workflow map (`claimed`, `blocked`, env-keyed `done`, and `review`/`qa` when configured). Never adopt a status discovered from the tracker's live workflow; a lifecycle stage with no configured status gets a comment, not a transition.
@@ -66,9 +66,11 @@ Based on the milestone, suggest (but don't automatically perform) a status trans
66
66
 
67
67
  | Milestone | Suggested Status |
68
68
  |-----------|-----------------|
69
- | Plan created | "In Progress" |
69
+ | Plan created | configured `jira.workflow.claimed` status |
70
70
  | PR ready | configured `jira.workflow.review` status, or no transition when unconfigured |
71
- | PR merged | "Done" |
71
+ | PR merged | configured `jira.workflow.done` status for the PR's target environment (env-keyed `done` resolved via `deploy.branches`), or no transition when unconfigured |
72
+
73
+ Every suggested or performed transition is bound by the **Tracker status vocabulary** section of the `config-resolution` rule: only statuses named in the configured workflow map, never statuses discovered from the tracker's live workflow (transition lists, board columns, other tickets) — and this binds the lead performing tracker writes exactly as it binds a subagent. A milestone with no configured status gets a comment, not a transition.
72
74
 
73
75
  ### Step 5: Parent Status Rollup (`--rollup`)
74
76
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -127,7 +127,7 @@ Note: `done` may be a string or an env-keyed map (`{ dev, staging, production }`
127
127
  ## Rules
128
128
 
129
129
  - Never auto-transition ticket status, with one explicit exception: when `jira-verify` returns `FAIL` for the pre-flight gate (Step 2), first run the `pre-flight-autofill` draft-then-block procedure (draft the authorable missing sections into the ticket as labeled assumptions), then transition to the configured `blocked` status, add the configured `human_needed` marker label (`jira.labels.human_needed`, default `Human Needed`), and reassign to the Reporter with a confirmation comment. Every other status change remains a suggestion the human confirms.
130
- - Any transition is config-bound: never invent transitions; a transition may target only a status named in `config.jira.workflow`. Don't guess from the live workflow. The evidence-time review hop (Step 7) follows this rule too — it is config-bound, optional, and skipped when `jira.workflow.review` is absent (the ticket stays in `claimed`).
130
+ - Any transition is config-bound per the **Tracker status vocabulary** section of the `config-resolution` rule: never invent transitions; a transition may target only a status named in `config.jira.workflow`. Don't guess from the live workflow. The evidence-time review hop (Step 7) follows this rule too — it is config-bound, optional, and skipped when `jira.workflow.review` is absent (the ticket stays in `claimed`).
131
131
  - Always read the full ticket graph via `jira-read-ticket` before determining intent — don't rely on ticket type alone
132
132
  - Never create or materially edit a ticket by calling MCP write tools directly — always delegate to `jira-write-ticket` so relationships, Gherkin criteria, and metadata gates are enforced
133
133
  - If sign-in credentials are in the ticket, extract and pass them to the flow. If the ticket touches an authenticated surface and credentials are missing, that is a Step 2 failure — block and reassign rather than guessing.
@@ -26,6 +26,16 @@ This applies before declaring connection state, before running any `acli jira *`
26
26
 
27
27
  Project tracker (`jira` / `github` / `linear`) is read from `.lisa.config.json` `tracker`. Vendor-neutral skills MUST dispatch through the configured tracker, never infer it from arguments. Missing `tracker` → stop and instruct the user to run the matching `/lisa:setup:*` skill.
28
28
 
29
+ ## Tracker status vocabulary
30
+
31
+ **A status transition may target only a status named in the project's configured workflow map** (`jira.workflow.*` for JIRA; the equivalent label/state map for GitHub and Linear). The configured map is the COMPLETE authorized vocabulary — not a starting point.
32
+
33
+ - **Never adopt statuses discovered from the tracker's live workflow metadata** — transition lists (`getTransitionsForJiraIssue` targets), board columns, status descriptions, or statuses seen on other tickets. A tracker workflow usually contains more statuses than the config names; those extra statuses are not lisa's to use. The live workflow is consulted only to find the transition *id* that reaches a config-named status.
34
+ - **A lifecycle stage with no configured status gets no transition.** If the flow reaches a stage the map does not name (e.g. "PR open awaiting review" when `jira.workflow.review` is unset, or a QA-ready stage with no `qa` mapping), leave the status where it is and record the stage in a comment. Do not pick the nearest-sounding tracker status.
35
+ - **This binds every actor that writes to the tracker** — the lead as much as any subagent. In runtimes where interactively-authenticated MCPs are lead-only, the lead performs the tracker writes for the whole flow; loading an implement/sync skill without the agent definition does not relax this rule.
36
+
37
+ This is the shared slug for the config-bound-transitions policy (the `leaf-only-lifecycle` precedent: one slug, never divergent per-surface prose). Skills and agent definitions cite it rather than restating it.
38
+
29
39
  ## Repo identity
30
40
 
31
41
  `repo:<name>` is the canonical label for which repo a work item belongs to. Resolve current-repo identity in this priority order: `.lisa.config.local.json` `repo` → `.lisa.config.json` `repo` → `.lisa.config.json` `github.repo` → `basename -s .git "$(git remote get-url origin)"`. If none resolve, stop with a clear error.
@@ -169,6 +169,8 @@ The committed verdict carries the machine-readable half:
169
169
  evidence/<ticket>/verdict.json
170
170
  not_established: [] # what was NOT proved; may be empty
171
171
  not_established_reviewed: true # attests the list was reviewed; may NEVER be omitted
172
+ drift: none # live-environment baseline-vs-now drift classification:
173
+ # none | progress | regression | unrelated_churn
172
174
  artifact: { repository, base_sha, head_sha, build_id, environment, observed_at }
173
175
  evidence: [ { evidence_id, kind, locator,
174
176
  artifact_head_sha, # the head_sha in force when THIS artifact was captured
@@ -210,6 +212,8 @@ Verification happens at two stages in the workflow:
210
212
 
211
213
  Both levels use the same verification types table above. The difference is the environment, not the rigor.
212
214
 
215
+ Remote verification must be **drift-aware**: the target environment may legitimately change between the local baseline and the remote run (its own deploy, out-of-band infra changes, data churn). Assert invariants — shape, exact paths, forbidden values, internal coherence — rather than equality with the local evidence snapshot; when observed state differs from the baseline, classify the drift and record it in the verdict's canonical `drift` field (`none | progress | regression | unrelated_churn`, defined in the `verdict.json` contract above). Only a broken invariant is a failure; never encode "the environment held still" as an implicit assumption.
216
+
213
217
  ---
214
218
 
215
219
  ## Credential-Gated Verification
@@ -115,6 +115,14 @@ step frames) with deterministic rendering. CI's `verification-coverage` check
115
115
  requires a verification-spec delta on every behavioral change. See the
116
116
  `reference/verification.md` "Making verification concrete (UAT)" section.
117
117
 
118
+ ### 3a. Drift-aware live-environment assertions
119
+
120
+ When the codified test — or the remote re-verification it encodes — runs against a **live, deployed environment**, the environment will not hold still between the original verification and any later run: deploys, out-of-band infra applies, and data churn are normal, not exceptional. Encode the verification accordingly:
121
+
122
+ - **Assert invariants, not snapshot equality.** Pin the properties that define correctness — document shape, exact paths, forbidden values/hosts, internal coherence (e.g. every URL in a discovery document uses the same host) — never a byte-for-byte diff against a captured baseline. A snapshot diff false-fails the moment the environment legitimately moves.
123
+ - **Classify drift, don't just detect it.** When observed state differs from the baseline evidence, treat that as a classification problem, and record the classification in the verdict's canonical `drift` field (`none | progress | regression | unrelated_churn`, defined by the `verdict.json` contract in `reference/verification.md`): **progress** (the change being verified, or a related fix, landed), **regression** (an invariant broke), or **unrelated churn**. Drift classified as progress or unrelated churn passes, with the environment change surfaced as evidence; only a broken invariant fails.
124
+ - **Never encode "the environment will hold still" as an implicit assumption.** Evidence capture that only makes sense if nothing changed between baseline and re-check has that assumption baked in even when no assertion states it — e.g. an OAuth discovery document whose host legitimately flipped from a provider-prefix domain to the canonical vanity host between a local baseline and a remote re-check ~30 minutes later would false-fail a snapshot verifier, while an invariant-asserting verifier passes correctly and records the drift as progress.
125
+
118
126
  ### 4. Run the test in isolation
119
127
 
120
128
  Run only the new test, using whatever per-test invocation the project supports:
@@ -314,3 +314,5 @@ Before shutting down the team, execute the Verify flow:
314
314
  13. `ops-specialist`: post-deploy health check, monitor for errors in first minutes
315
315
  14. If remote verification fails, create a task for the agent team to find out why it failed, fix it and return to step 5. **Bound this loop**: after a small number of full fix→deploy→reverify cycles without reaching a passing remote verdict (treat ~3 as the ceiling unless the work item states otherwise), stop retrying — file a build-ready fix ticket, write the verdict with `status: "blocked"` and the diagnosis, and move the work item to blocked rather than looping indefinitely. The completion gate releases on a `blocked` verdict, so the flow ends with a recorded outcome instead of a silent spin or a self-declared success.
316
316
  15. After true terminal completion — required merge/deploy/verification passed, usage/evidence and two-way PR linkage are recorded, and the work item is terminal — run `node scripts/lisa-work-item.mjs clear` and verify the worktree has no current binding. Do not clear on an interruption or blocked outcome; preserving the binding is what keeps resumed work attributable.
317
+
318
+ **Ticket status transitions throughout this flow are config-bound** per the **Tracker status vocabulary** section of the `config-resolution` rule: whoever performs the tracker write — the lead included, in runtimes where the tracker MCP is lead-only — may only target statuses named in the configured workflow map (`claimed`, `blocked`, env-keyed `done`, and `review`/`qa` when configured). Never adopt a status discovered from the tracker's live workflow; a lifecycle stage with no configured status gets a comment, not a transition.
@@ -66,9 +66,11 @@ Based on the milestone, suggest (but don't automatically perform) a status trans
66
66
 
67
67
  | Milestone | Suggested Status |
68
68
  |-----------|-----------------|
69
- | Plan created | "In Progress" |
69
+ | Plan created | configured `jira.workflow.claimed` status |
70
70
  | PR ready | configured `jira.workflow.review` status, or no transition when unconfigured |
71
- | PR merged | "Done" |
71
+ | PR merged | configured `jira.workflow.done` status for the PR's target environment (env-keyed `done` resolved via `deploy.branches`), or no transition when unconfigured |
72
+
73
+ Every suggested or performed transition is bound by the **Tracker status vocabulary** section of the `config-resolution` rule: only statuses named in the configured workflow map, never statuses discovered from the tracker's live workflow (transition lists, board columns, other tickets) — and this binds the lead performing tracker writes exactly as it binds a subagent. A milestone with no configured status gets a comment, not a transition.
72
74
 
73
75
  ### Step 5: Parent Status Rollup (`--rollup`)
74
76
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.288.1",
3
+ "version": "2.289.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -127,7 +127,7 @@ Note: `done` may be a string or an env-keyed map (`{ dev, staging, production }`
127
127
  ## Rules
128
128
 
129
129
  - Never auto-transition ticket status, with one explicit exception: when `jira-verify` returns `FAIL` for the pre-flight gate (Step 2), first run the `pre-flight-autofill` draft-then-block procedure (draft the authorable missing sections into the ticket as labeled assumptions), then transition to the configured `blocked` status, add the configured `human_needed` marker label (`jira.labels.human_needed`, default `Human Needed`), and reassign to the Reporter with a confirmation comment. Every other status change remains a suggestion the human confirms.
130
- - Any transition is config-bound: never invent transitions; a transition may target only a status named in `config.jira.workflow`. Don't guess from the live workflow. The evidence-time review hop (Step 7) follows this rule too — it is config-bound, optional, and skipped when `jira.workflow.review` is absent (the ticket stays in `claimed`).
130
+ - Any transition is config-bound per the **Tracker status vocabulary** section of the `config-resolution` rule: never invent transitions; a transition may target only a status named in `config.jira.workflow`. Don't guess from the live workflow. The evidence-time review hop (Step 7) follows this rule too — it is config-bound, optional, and skipped when `jira.workflow.review` is absent (the ticket stays in `claimed`).
131
131
  - Always read the full ticket graph via `jira-read-ticket` before determining intent — don't rely on ticket type alone
132
132
  - Never create or materially edit a ticket by calling MCP write tools directly — always delegate to `jira-write-ticket` so relationships, Gherkin criteria, and metadata gates are enforced
133
133
  - If sign-in credentials are in the ticket, extract and pass them to the flow. If the ticket touches an authenticated surface and credentials are missing, that is a Step 2 failure — block and reassign rather than guessing.
@@ -21,6 +21,16 @@ This applies before declaring connection state, before running any `acli jira *`
21
21
 
22
22
  Project tracker (`jira` / `github` / `linear`) is read from `.lisa.config.json` `tracker`. Vendor-neutral skills MUST dispatch through the configured tracker, never infer it from arguments. Missing `tracker` → stop and instruct the user to run the matching `/lisa:setup:*` skill.
23
23
 
24
+ ## Tracker status vocabulary
25
+
26
+ **A status transition may target only a status named in the project's configured workflow map** (`jira.workflow.*` for JIRA; the equivalent label/state map for GitHub and Linear). The configured map is the COMPLETE authorized vocabulary — not a starting point.
27
+
28
+ - **Never adopt statuses discovered from the tracker's live workflow metadata** — transition lists (`getTransitionsForJiraIssue` targets), board columns, status descriptions, or statuses seen on other tickets. A tracker workflow usually contains more statuses than the config names; those extra statuses are not lisa's to use. The live workflow is consulted only to find the transition *id* that reaches a config-named status.
29
+ - **A lifecycle stage with no configured status gets no transition.** If the flow reaches a stage the map does not name (e.g. "PR open awaiting review" when `jira.workflow.review` is unset, or a QA-ready stage with no `qa` mapping), leave the status where it is and record the stage in a comment. Do not pick the nearest-sounding tracker status.
30
+ - **This binds every actor that writes to the tracker** — the lead as much as any subagent. In runtimes where interactively-authenticated MCPs are lead-only, the lead performs the tracker writes for the whole flow; loading an implement/sync skill without the agent definition does not relax this rule.
31
+
32
+ This is the shared slug for the config-bound-transitions policy (the `leaf-only-lifecycle` precedent: one slug, never divergent per-surface prose). Skills and agent definitions cite it rather than restating it.
33
+
24
34
  ## Repo identity
25
35
 
26
36
  `repo:<name>` is the canonical label for which repo a work item belongs to. Resolve current-repo identity in this priority order: `.lisa.config.local.json` `repo` → `.lisa.config.json` `repo` → `.lisa.config.json` `github.repo` → `basename -s .git "$(git remote get-url origin)"`. If none resolve, stop with a clear error.
@@ -164,6 +164,8 @@ The committed verdict carries the machine-readable half:
164
164
  evidence/<ticket>/verdict.json
165
165
  not_established: [] # what was NOT proved; may be empty
166
166
  not_established_reviewed: true # attests the list was reviewed; may NEVER be omitted
167
+ drift: none # live-environment baseline-vs-now drift classification:
168
+ # none | progress | regression | unrelated_churn
167
169
  artifact: { repository, base_sha, head_sha, build_id, environment, observed_at }
168
170
  evidence: [ { evidence_id, kind, locator,
169
171
  artifact_head_sha, # the head_sha in force when THIS artifact was captured
@@ -205,6 +207,8 @@ Verification happens at two stages in the workflow:
205
207
 
206
208
  Both levels use the same verification types table above. The difference is the environment, not the rigor.
207
209
 
210
+ Remote verification must be **drift-aware**: the target environment may legitimately change between the local baseline and the remote run (its own deploy, out-of-band infra changes, data churn). Assert invariants — shape, exact paths, forbidden values, internal coherence — rather than equality with the local evidence snapshot; when observed state differs from the baseline, classify the drift and record it in the verdict's canonical `drift` field (`none | progress | regression | unrelated_churn`, defined in the `verdict.json` contract above). Only a broken invariant is a failure; never encode "the environment held still" as an implicit assumption.
211
+
208
212
  ---
209
213
 
210
214
  ## Credential-Gated Verification
@@ -115,6 +115,14 @@ step frames) with deterministic rendering. CI's `verification-coverage` check
115
115
  requires a verification-spec delta on every behavioral change. See the
116
116
  `reference/verification.md` "Making verification concrete (UAT)" section.
117
117
 
118
+ ### 3a. Drift-aware live-environment assertions
119
+
120
+ When the codified test — or the remote re-verification it encodes — runs against a **live, deployed environment**, the environment will not hold still between the original verification and any later run: deploys, out-of-band infra applies, and data churn are normal, not exceptional. Encode the verification accordingly:
121
+
122
+ - **Assert invariants, not snapshot equality.** Pin the properties that define correctness — document shape, exact paths, forbidden values/hosts, internal coherence (e.g. every URL in a discovery document uses the same host) — never a byte-for-byte diff against a captured baseline. A snapshot diff false-fails the moment the environment legitimately moves.
123
+ - **Classify drift, don't just detect it.** When observed state differs from the baseline evidence, treat that as a classification problem, and record the classification in the verdict's canonical `drift` field (`none | progress | regression | unrelated_churn`, defined by the `verdict.json` contract in `reference/verification.md`): **progress** (the change being verified, or a related fix, landed), **regression** (an invariant broke), or **unrelated churn**. Drift classified as progress or unrelated churn passes, with the environment change surfaced as evidence; only a broken invariant fails.
124
+ - **Never encode "the environment will hold still" as an implicit assumption.** Evidence capture that only makes sense if nothing changed between baseline and re-check has that assumption baked in even when no assertion states it — e.g. an OAuth discovery document whose host legitimately flipped from a provider-prefix domain to the canonical vanity host between a local baseline and a remote re-check ~30 minutes later would false-fail a snapshot verifier, while an invariant-asserting verifier passes correctly and records the drift as progress.
125
+
118
126
  ### 4. Run the test in isolation
119
127
 
120
128
  Run only the new test, using whatever per-test invocation the project supports:
@@ -314,3 +314,5 @@ Before shutting down the team, execute the Verify flow:
314
314
  13. `ops-specialist`: post-deploy health check, monitor for errors in first minutes
315
315
  14. If remote verification fails, create a task for the agent team to find out why it failed, fix it and return to step 5. **Bound this loop**: after a small number of full fix→deploy→reverify cycles without reaching a passing remote verdict (treat ~3 as the ceiling unless the work item states otherwise), stop retrying — file a build-ready fix ticket, write the verdict with `status: "blocked"` and the diagnosis, and move the work item to blocked rather than looping indefinitely. The completion gate releases on a `blocked` verdict, so the flow ends with a recorded outcome instead of a silent spin or a self-declared success.
316
316
  15. After true terminal completion — required merge/deploy/verification passed, usage/evidence and two-way PR linkage are recorded, and the work item is terminal — run `node scripts/lisa-work-item.mjs clear` and verify the worktree has no current binding. Do not clear on an interruption or blocked outcome; preserving the binding is what keeps resumed work attributable.
317
+
318
+ **Ticket status transitions throughout this flow are config-bound** per the **Tracker status vocabulary** section of the `config-resolution` rule: whoever performs the tracker write — the lead included, in runtimes where the tracker MCP is lead-only — may only target statuses named in the configured workflow map (`claimed`, `blocked`, env-keyed `done`, and `review`/`qa` when configured). Never adopt a status discovered from the tracker's live workflow; a lifecycle stage with no configured status gets a comment, not a transition.
@@ -66,9 +66,11 @@ Based on the milestone, suggest (but don't automatically perform) a status trans
66
66
 
67
67
  | Milestone | Suggested Status |
68
68
  |-----------|-----------------|
69
- | Plan created | "In Progress" |
69
+ | Plan created | configured `jira.workflow.claimed` status |
70
70
  | PR ready | configured `jira.workflow.review` status, or no transition when unconfigured |
71
- | PR merged | "Done" |
71
+ | PR merged | configured `jira.workflow.done` status for the PR's target environment (env-keyed `done` resolved via `deploy.branches`), or no transition when unconfigured |
72
+
73
+ Every suggested or performed transition is bound by the **Tracker status vocabulary** section of the `config-resolution` rule: only statuses named in the configured workflow map, never statuses discovered from the tracker's live workflow (transition lists, board columns, other tickets) — and this binds the lead performing tracker writes exactly as it binds a subagent. A milestone with no configured status gets a comment, not a transition.
72
74
 
73
75
  ### Step 5: Parent Status Rollup (`--rollup`)
74
76