@codyswann/lisa 2.256.0 → 2.257.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/package.json +1 -1
  2. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  3. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  4. package/plugins/lisa/.codex-plugin/skills/lisa-exploratory-qa/SKILL.md +12 -4
  5. package/plugins/lisa/.codex-plugin/skills/lisa-github-validate-issue/SKILL.md +1 -1
  6. package/plugins/lisa/.codex-plugin/skills/lisa-github-write-issue/SKILL.md +9 -3
  7. package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +6 -2
  8. package/plugins/lisa/.codex-plugin/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
  9. package/plugins/lisa/.codex-plugin/skills/lisa-jira-write-ticket/SKILL.md +9 -6
  10. package/plugins/lisa/.codex-plugin/skills/lisa-learnings-audit/SKILL.md +9 -0
  11. package/plugins/lisa/.codex-plugin/skills/lisa-linear-validate-issue/SKILL.md +1 -1
  12. package/plugins/lisa/.codex-plugin/skills/lisa-linear-write-issue/SKILL.md +9 -3
  13. package/plugins/lisa/.codex-plugin/skills/lisa-monitor/SKILL.md +6 -4
  14. package/plugins/lisa/.codex-plugin/skills/lisa-project-ideation/SKILL.md +21 -4
  15. package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +17 -7
  16. package/plugins/lisa/agents/github-agent.md +2 -2
  17. package/plugins/lisa/agents/jira-agent.md +2 -2
  18. package/plugins/lisa/agents/linear-agent.md +2 -2
  19. package/plugins/lisa/rules/eager/config-resolution.md +27 -8
  20. package/plugins/lisa/rules/eager/pre-flight-autofill.md +21 -7
  21. package/plugins/lisa/rules/eager/rejection-detection.md +12 -1
  22. package/plugins/lisa/rules/reference/config-resolution.md +55 -16
  23. package/plugins/lisa/rules/reference/observability-audit.md +5 -1
  24. package/plugins/lisa/rules/reference/pre-flight-autofill.md +23 -8
  25. package/plugins/lisa/rules/reference/rejection-detection.md +61 -0
  26. package/plugins/lisa/skills/lisa-exploratory-qa/SKILL.md +12 -4
  27. package/plugins/lisa/skills/lisa-github-validate-issue/SKILL.md +1 -1
  28. package/plugins/lisa/skills/lisa-github-write-issue/SKILL.md +9 -3
  29. package/plugins/lisa/skills/lisa-implement/SKILL.md +6 -2
  30. package/plugins/lisa/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
  31. package/plugins/lisa/skills/lisa-jira-write-ticket/SKILL.md +9 -6
  32. package/plugins/lisa/skills/lisa-learnings-audit/SKILL.md +9 -0
  33. package/plugins/lisa/skills/lisa-linear-validate-issue/SKILL.md +1 -1
  34. package/plugins/lisa/skills/lisa-linear-write-issue/SKILL.md +9 -3
  35. package/plugins/lisa/skills/lisa-monitor/SKILL.md +6 -4
  36. package/plugins/lisa/skills/lisa-project-ideation/SKILL.md +21 -4
  37. package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +17 -7
  38. package/plugins/lisa-agy/agents/github-agent.md +2 -2
  39. package/plugins/lisa-agy/agents/jira-agent.md +2 -2
  40. package/plugins/lisa-agy/agents/linear-agent.md +2 -2
  41. package/plugins/lisa-agy/plugin.json +1 -1
  42. package/plugins/lisa-agy/skills/lisa-exploratory-qa/SKILL.md +12 -4
  43. package/plugins/lisa-agy/skills/lisa-github-validate-issue/SKILL.md +1 -1
  44. package/plugins/lisa-agy/skills/lisa-github-write-issue/SKILL.md +9 -3
  45. package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +6 -2
  46. package/plugins/lisa-agy/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
  47. package/plugins/lisa-agy/skills/lisa-jira-write-ticket/SKILL.md +9 -6
  48. package/plugins/lisa-agy/skills/lisa-learnings-audit/SKILL.md +9 -0
  49. package/plugins/lisa-agy/skills/lisa-linear-validate-issue/SKILL.md +1 -1
  50. package/plugins/lisa-agy/skills/lisa-linear-write-issue/SKILL.md +9 -3
  51. package/plugins/lisa-agy/skills/lisa-monitor/SKILL.md +6 -4
  52. package/plugins/lisa-agy/skills/lisa-project-ideation/SKILL.md +21 -4
  53. package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +17 -7
  54. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  56. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  57. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-copilot/agents/github-agent.agent.md +2 -2
  61. package/plugins/lisa-copilot/agents/jira-agent.agent.md +2 -2
  62. package/plugins/lisa-copilot/agents/linear-agent.agent.md +2 -2
  63. package/plugins/lisa-copilot/rules/eager/config-resolution.md +27 -8
  64. package/plugins/lisa-copilot/rules/eager/pre-flight-autofill.md +21 -7
  65. package/plugins/lisa-copilot/rules/eager/rejection-detection.md +12 -1
  66. package/plugins/lisa-copilot/rules/reference/config-resolution.md +55 -16
  67. package/plugins/lisa-copilot/rules/reference/observability-audit.md +5 -1
  68. package/plugins/lisa-copilot/rules/reference/pre-flight-autofill.md +23 -8
  69. package/plugins/lisa-copilot/rules/reference/rejection-detection.md +61 -0
  70. package/plugins/lisa-copilot/skills/lisa-exploratory-qa/SKILL.md +12 -4
  71. package/plugins/lisa-copilot/skills/lisa-github-validate-issue/SKILL.md +1 -1
  72. package/plugins/lisa-copilot/skills/lisa-github-write-issue/SKILL.md +9 -3
  73. package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +6 -2
  74. package/plugins/lisa-copilot/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
  75. package/plugins/lisa-copilot/skills/lisa-jira-write-ticket/SKILL.md +9 -6
  76. package/plugins/lisa-copilot/skills/lisa-learnings-audit/SKILL.md +9 -0
  77. package/plugins/lisa-copilot/skills/lisa-linear-validate-issue/SKILL.md +1 -1
  78. package/plugins/lisa-copilot/skills/lisa-linear-write-issue/SKILL.md +9 -3
  79. package/plugins/lisa-copilot/skills/lisa-monitor/SKILL.md +6 -4
  80. package/plugins/lisa-copilot/skills/lisa-project-ideation/SKILL.md +21 -4
  81. package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +17 -7
  82. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-cursor/agents/github-agent.md +2 -2
  84. package/plugins/lisa-cursor/agents/jira-agent.md +2 -2
  85. package/plugins/lisa-cursor/agents/linear-agent.md +2 -2
  86. package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +55 -16
  87. package/plugins/lisa-cursor/rules/config-resolution.mdc +27 -8
  88. package/plugins/lisa-cursor/rules/observability-audit-reference.mdc +5 -1
  89. package/plugins/lisa-cursor/rules/pre-flight-autofill-reference.mdc +23 -8
  90. package/plugins/lisa-cursor/rules/pre-flight-autofill.mdc +21 -7
  91. package/plugins/lisa-cursor/rules/rejection-detection-reference.mdc +61 -0
  92. package/plugins/lisa-cursor/rules/rejection-detection.mdc +12 -1
  93. package/plugins/lisa-cursor/skills/lisa-exploratory-qa/SKILL.md +12 -4
  94. package/plugins/lisa-cursor/skills/lisa-github-validate-issue/SKILL.md +1 -1
  95. package/plugins/lisa-cursor/skills/lisa-github-write-issue/SKILL.md +9 -3
  96. package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +6 -2
  97. package/plugins/lisa-cursor/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
  98. package/plugins/lisa-cursor/skills/lisa-jira-write-ticket/SKILL.md +9 -6
  99. package/plugins/lisa-cursor/skills/lisa-learnings-audit/SKILL.md +9 -0
  100. package/plugins/lisa-cursor/skills/lisa-linear-validate-issue/SKILL.md +1 -1
  101. package/plugins/lisa-cursor/skills/lisa-linear-write-issue/SKILL.md +9 -3
  102. package/plugins/lisa-cursor/skills/lisa-monitor/SKILL.md +6 -4
  103. package/plugins/lisa-cursor/skills/lisa-project-ideation/SKILL.md +21 -4
  104. package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +17 -7
  105. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  106. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  107. package/plugins/lisa-expo-agy/plugin.json +1 -1
  108. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  109. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  110. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  111. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  112. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  113. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  114. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  115. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  116. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  117. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  118. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  119. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  120. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  121. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  122. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  123. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  124. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  125. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  126. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  127. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  128. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  129. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  130. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  131. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  132. package/plugins/lisa-rails-agy/plugin.json +1 -1
  133. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  134. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  135. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  136. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  137. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  138. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  139. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  140. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  141. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  142. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  143. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  144. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  145. package/plugins/src/base/agents/github-agent.md +2 -2
  146. package/plugins/src/base/agents/jira-agent.md +2 -2
  147. package/plugins/src/base/agents/linear-agent.md +2 -2
  148. package/plugins/src/base/rules/eager/config-resolution.md +27 -8
  149. package/plugins/src/base/rules/eager/pre-flight-autofill.md +21 -7
  150. package/plugins/src/base/rules/eager/rejection-detection.md +12 -1
  151. package/plugins/src/base/rules/reference/config-resolution.md +55 -16
  152. package/plugins/src/base/rules/reference/observability-audit.md +5 -1
  153. package/plugins/src/base/rules/reference/pre-flight-autofill.md +23 -8
  154. package/plugins/src/base/rules/reference/rejection-detection.md +61 -0
  155. package/plugins/src/base/skills/lisa-exploratory-qa/SKILL.md +12 -4
  156. package/plugins/src/base/skills/lisa-github-validate-issue/SKILL.md +1 -1
  157. package/plugins/src/base/skills/lisa-github-write-issue/SKILL.md +9 -3
  158. package/plugins/src/base/skills/lisa-implement/SKILL.md +6 -2
  159. package/plugins/src/base/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
  160. package/plugins/src/base/skills/lisa-jira-write-ticket/SKILL.md +9 -6
  161. package/plugins/src/base/skills/lisa-learnings-audit/SKILL.md +9 -0
  162. package/plugins/src/base/skills/lisa-linear-validate-issue/SKILL.md +1 -1
  163. package/plugins/src/base/skills/lisa-linear-write-issue/SKILL.md +9 -3
  164. package/plugins/src/base/skills/lisa-monitor/SKILL.md +6 -4
  165. package/plugins/src/base/skills/lisa-project-ideation/SKILL.md +21 -4
  166. package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +17 -7
@@ -53,7 +53,7 @@ Resolve build labels from `.lisa.config.json` `github.labels.build.*` (defaults:
53
53
 
54
54
  If `github-verify` returns `FAIL` on any of the above, do NOT continue to build. **Draft the missing spec content first, then block for confirmation** — never bounce a raw "go write all this" checklist back to the author:
55
55
 
56
- 1. **Best-effort autofill (before blocking).** Run the **draft-then-block procedure** in the `pre-flight-autofill` rule: draft every *authorable* missing sectionTechnical Approach, Out of Scope, Gherkin acceptance criteria, expected-vs-actual, Repository, Relationship Search (run the git + `gh`/tracker search, don't fabricate it), a Validation Journey **draft** via `github-add-journey`, and Target Backend Environment from the issue's own content (title, body, screenshots, design links, repro steps) plus the codebase. For bugs, parse the reported environment from bare env names and env-bearing URLs before recommending any default; the reported environment wins. Write it into the body via `github-write-issue` as clearly-labeled assumptions/recommendations (never overwrite the author's prose), then re-run `github-verify`. Whatever the agent could author is now structured spec; only genuinely human-only inputs remain.
56
+ 1. **Best-effort autofill (before blocking).** Run `pre-flight-autofill` for every work item. Preserve a human bare configured key or `Confirmed: <env>`; automation writes `Inferred: <env>evidence: <title|body|reproduction|hostname>`, `Assumption: <env> remote default branch <branch>` for a unique reverse-map, or `Assumption: remote default branch <branch>` otherwise. Human confirmation replaces the annotation with the bare key or `Confirmed: <env>`. For a legacy bare value, use managed draft markers and current ticket content only; provider edit history is not required. A marker proves automation and requires re-annotation; otherwise unknown provenance plus conflicting evidence stops for confirmation. Resolve one exact `deploy.branches` key from the human-authored title, body, and reproduction steps or URL hostname; exclude the complete `Target Backend Environment` section and other machine-authored metadata/draft blocks so annotations cannot become evidence. A reported bug environment is an example, not a restriction. Evidence supersedes only `Assumption:`. Normalize `prod` ↔ `production` only when exactly one is configured; no other aliases exist. Conflicts stop; never infer from arbitrary branch text, URL paths/query strings, or substrings. Write through `github-write-issue`, never overwrite human prose, then re-run `github-verify`.
57
57
  2. Relabel: remove the `claimed` label, add the `blocked` label **and** the `human_needed` marker label. Even after the agent drafted what it could, a pre-flight gate failure bounces the issue back to its author because it still needs a human to **confirm the drafted assumptions** or supply something no agent can invent — real missing credentials, access, or an irreducible product/scoping decision — so the marker tells a human scanning the board which blocked issues are waiting on them. The marker is additive to `blocked`, not a replacement. (See the `config-resolution` rule's "Build markers" for when the marker applies and when it must NOT.)
58
58
  ```bash
59
59
  _read_cfg() { local lv gv; lv=$(jq -r "$1 // empty" .lisa.config.local.json 2>/dev/null); gv=$(jq -r "$1 // empty" .lisa.config.json 2>/dev/null); echo "${lv:-${gv}}"; }
@@ -152,4 +152,4 @@ Note: `done` may be a string or an env-keyed map (`{ dev, staging, production }`
152
152
  - Never create or materially edit an issue by calling `gh issue create` / `gh issue edit` directly — always delegate to `github-write-issue` (or, from a vendor-neutral caller, `tracker-write`) so relationships, Gherkin criteria, and metadata gates are enforced.
153
153
  - If sign-in credentials are in the issue body, extract and pass them to the flow. If the issue touches an authenticated surface and credentials are missing, that is a Step 2 failure — block and reassign rather than guessing.
154
154
  - If the issue has a `## Validation Journey` section, pass it to the verifier agent. The Validation Journey's local-verification step must point at the target backend environment named in the body.
155
- - For bug issues, the reported environment named in the issue body or reproduction steps drives the implementation base branch via `deploy.branches`. If no environment can be found anywhere in the ticket, fall back to the configured default branch and record that assumption. If the reported environment is present but missing from `deploy.branches`, or its mapped branch is absent on the remote, stop and report the missing environment/branch mapping instead of defaulting. A non-integration environment fix must be merged and verified on that environment branch, then forward cherry-picked down to the integration branch through a linked follow-up.
155
+ - The environment handoff for every work item uses the same durable grammar: human bare configured key or `Confirmed: <env>`; automated `Inferred: <env> — evidence: <title|body|reproduction|hostname>`, `Assumption: <env> remote default branch <branch>` for a unique reverse-map, or `Assumption: remote default branch <branch>` otherwise. Human confirmation replaces an automated annotation with the bare key or `Confirmed: <env>`. For legacy bare values, managed draft markers and current ticket content decide provenance; provider edit history is not required. A marker proves automation; otherwise unknown provenance plus conflicting evidence stops for confirmation. Human-confirmed wins, then validated `Inferred:`; otherwise one exact `deploy.branches` key from the human-authored title, body, and reproduction steps or URL hostname drives the implementation base branch. Exclude the complete `Target Backend Environment` section and other machine-authored metadata/draft blocks so annotations cannot become evidence. Evidence supersedes only `Assumption:`. Normalize `prod` ↔ `production` only when exactly one is configured; no other aliases exist. Conflicts stop. Never infer from arbitrary branch text, URL paths/query strings, or substrings. With no signal, use the remote default and record the applicable assumption without blocking on a non-unique reverse-map. Require any selected mapping and remote branch. A reported bug environment is an example of the all-work-type rule. Non-integration fixes still require the linked forward cherry-pick.
@@ -48,7 +48,7 @@ Use the `jira-verify` skill to check the ticket against organizational standards
48
48
  **Gating behavior — this is the one place auto-transitioning is allowed:**
49
49
 
50
50
  If `jira-verify` returns `FAIL` on any of the above, do NOT continue to build. **Draft the missing spec content first, then block for confirmation** — never bounce a raw "go write all this" checklist back to the reporter:
51
- 1. **Best-effort autofill (before blocking).** Run the **draft-then-block procedure** in the `pre-flight-autofill` rule: draft every *authorable* missing sectionTechnical Approach, Out of Scope, Gherkin acceptance criteria, expected-vs-actual, Repository, Relationship Search (run the git + JQL search, don't fabricate it), a Validation Journey **draft** via `jira-add-journey`, and Target Backend Environment from the ticket's own content (title, description, screenshots, design links, repro steps) plus the codebase. For bugs, parse the reported environment from bare env names and env-bearing URLs before recommending any default; the reported environment wins. Write it into the description via `jira-write-ticket` as clearly-labeled assumptions/recommendations (never overwrite the reporter's prose), then re-run `jira-verify`. Whatever the agent could author is now structured spec; only genuinely human-only inputs remain.
51
+ 1. **Best-effort autofill (before blocking).** Run `pre-flight-autofill` for every work item. Preserve a human bare configured key or `Confirmed: <env>`; automation writes `Inferred: <env>evidence: <title|body|reproduction|hostname>`, `Assumption: <env> remote default branch <branch>` for a unique reverse-map, or `Assumption: remote default branch <branch>` otherwise. Human confirmation replaces the annotation with the bare key or `Confirmed: <env>`. For a legacy bare value, use managed draft markers and current ticket content only; provider edit history is not required. A marker proves automation and requires re-annotation; otherwise unknown provenance plus conflicting evidence stops for confirmation. Resolve one exact `deploy.branches` key from the human-authored title, body, and reproduction steps or URL hostname; exclude the complete `Target Backend Environment` section and other machine-authored metadata/draft blocks so annotations cannot become evidence. A reported bug environment is an example, not a restriction. Evidence supersedes only `Assumption:`. Normalize `prod` `production` only when exactly one is configured; no other aliases exist. Conflicts stop; never infer from arbitrary branch text, URL paths/query strings, or substrings. Write through `jira-write-ticket`, never overwrite human prose, then re-run `jira-verify`.
52
52
  2. Transition the ticket status to the configured `blocked` status (typically `Blocked` — read from `.lisa.config.json` `jira.workflow.blocked` if present, otherwise the project's standard blocked status). Use `mcp__atlassian__transitionJiraIssue` or equivalent.
53
53
  3. **Add the `human_needed` marker label.** Even after the agent drafted what it could, a pre-flight gate failure bounces the ticket back to its reporter because the ticket still needs a human to **confirm the drafted assumptions** or supply something no agent can invent — real missing credentials, access, or an irreducible product/scoping decision. Add the configured label (`jira.labels.human_needed`, default `Human Needed`) to the ticket's `labels` field via `mcp__atlassian__editJiraIssue` — a lightweight metadata update permitted under this same gate exception. This is additive to (not a replacement for) the `blocked` status, so a human scanning the board sees at a glance which blocked tickets are waiting on them. If the label does not exist in the project, record that and proceed — the marker is best-effort. (See the `config-resolution` rule's "Build markers" for when the marker applies and when it must NOT.)
54
54
  4. Reassign the ticket to the **Reporter** (the human who filed it — not the Creator field, which may be a bot/integration).
@@ -132,4 +132,4 @@ Note: `done` may be a string or an env-keyed map (`{ dev, staging, production }`
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.
134
134
  - If the ticket has a Validation Journey section, pass it to the verifier agent. The Validation Journey's local-verification step must point at the target backend environment named in the description (for FE work, that's the deployed backend QA reported against).
135
- - For bug tickets, the reported environment named in the description or reproduction steps drives the implementation base branch via `deploy.branches`. If no environment can be found anywhere in the ticket, fall back to the configured default branch and record that assumption. If the reported environment is present but missing from `deploy.branches`, or its mapped branch is absent on the remote, stop and report the missing environment/branch mapping instead of defaulting. A non-integration environment fix must be merged and verified on that environment branch, then forward cherry-picked down to the integration branch through a linked follow-up.
135
+ - The environment handoff for every work item uses the same durable grammar: human bare configured key or `Confirmed: <env>`; automated `Inferred: <env> — evidence: <title|body|reproduction|hostname>`, `Assumption: <env> remote default branch <branch>` for a unique reverse-map, or `Assumption: remote default branch <branch>` otherwise. Human confirmation replaces an automated annotation with the bare key or `Confirmed: <env>`. For legacy bare values, managed draft markers and current ticket content decide provenance; provider edit history is not required. A marker proves automation; otherwise unknown provenance plus conflicting evidence stops for confirmation. Human-confirmed wins, then validated `Inferred:`; otherwise one exact `deploy.branches` key from the human-authored title, body, and reproduction steps or URL hostname drives the implementation base branch. Exclude the complete `Target Backend Environment` section and other machine-authored metadata/draft blocks so annotations cannot become evidence. Evidence supersedes only `Assumption:`. Normalize `prod` ↔ `production` only when exactly one is configured; no other aliases exist. Conflicts stop. Never infer from arbitrary branch text, URL paths/query strings, or substrings. With no signal, use the remote default and record the applicable assumption without blocking on a non-unique reverse-map. Require any selected mapping and remote branch. A reported bug environment is an example of the all-work-type rule. Non-integration fixes still require the linked forward cherry-pick.
@@ -50,7 +50,7 @@ Use the `linear-verify` skill to check the item against organizational standards
50
50
  Resolve build labels from `.lisa.config.json` `linear.labels.build.*` (defaults: `status:ready` / `status:in-progress` / `status:code-review`); resolve the `blocked` label from the same section (`linear.labels.build.blocked`, default `status:blocked`) and the `human_needed` marker label from the same section (`linear.labels.build.human_needed`, default `human-needed`).
51
51
 
52
52
  If `linear-verify` returns `FAIL` on any of the above, do NOT continue to build. **Draft the missing spec content first, then block for confirmation** — never bounce a raw "go write all this" checklist back to the creator:
53
- 1. **Best-effort autofill (before blocking).** Run the **draft-then-block procedure** in the `pre-flight-autofill` rule: draft every *authorable* missing sectionTechnical Approach, Out of Scope, Gherkin acceptance criteria, expected-vs-actual, Repository, Relationship Search (run the git + Linear search, don't fabricate it), a Validation Journey **draft** via `linear-add-journey`, and Target Backend Environment from the item's own content (title, description, screenshots, design links, repro steps) plus the codebase. For bugs, parse the reported environment from bare env names and env-bearing URLs before recommending any default; the reported environment wins. Write it into the description via `linear-write-issue` as clearly-labeled assumptions/recommendations (never overwrite the creator's prose), then re-run `linear-verify`. Whatever the agent could author is now structured spec; only genuinely human-only inputs remain.
53
+ 1. **Best-effort autofill (before blocking).** Run `pre-flight-autofill` for every work item. Preserve a human bare configured key or `Confirmed: <env>`; automation writes `Inferred: <env>evidence: <title|body|reproduction|hostname>`, `Assumption: <env> remote default branch <branch>` for a unique reverse-map, or `Assumption: remote default branch <branch>` otherwise. Human confirmation replaces the annotation with the bare key or `Confirmed: <env>`. For a legacy bare value, use managed draft markers and current ticket content only; provider edit history is not required. A marker proves automation and requires re-annotation; otherwise unknown provenance plus conflicting evidence stops for confirmation. Resolve one exact `deploy.branches` key from the human-authored title, body, and reproduction steps or URL hostname; exclude the complete `Target Backend Environment` section and other machine-authored metadata/draft blocks so annotations cannot become evidence. A reported bug environment is an example, not a restriction. Evidence supersedes only `Assumption:`. Normalize `prod` `production` only when exactly one is configured; no other aliases exist. Conflicts stop; never infer from arbitrary branch text, URL paths/query strings, or substrings. Write through `linear-write-issue`, never overwrite human prose, then re-run `linear-verify`.
54
54
  2. Update labels via `lisa-linear-access operation: save-issue`: remove the current build label, add the configured `blocked` label **and** the configured `human_needed` marker label. (Create either label via `create_issue_label` if needed.) Even after the agent drafted what it could, a pre-flight gate failure bounces the item back to its creator because it still needs a human to **confirm the drafted assumptions** or supply something no agent can invent — real missing credentials, access, or an irreducible product/scoping decision — so the marker tells a human scanning the board which blocked items are waiting on them. The marker is additive to `blocked`, not a replacement. (See the `config-resolution` rule's "Build markers" for when the marker applies and when it must NOT.)
55
55
  3. Reassign the item to the **Issue creator** (the human who filed it — Linear's `creator` field).
56
56
  4. Post the **confirmation comment** from the `pre-flight-autofill` rule via `lisa-linear-access operation: save-comment`, **not** a bare remediation checklist: disclose it is a Claude draft, give one line per drafted section naming the key assumption made, list any remaining human-only item as a specific question with a recommended default, and close with *"review the drafted sections, correct anything wrong, then flip back to Ready and it builds — or reply with corrections."* Prefix with `[{repo}]`.
@@ -135,4 +135,4 @@ The label transitions ARE the canonical signal. The native `state` field stays a
135
135
  - Never create or materially edit an item by calling MCP write tools directly — always delegate to `linear-write-issue` so relationships, Gherkin criteria, and metadata gates are enforced. Two explicit exceptions are permitted: (1) the Step 2 pre-flight failure path (when `linear-verify` returns `FAIL`) may call `lisa-linear-access operation: save-issue` and `lisa-linear-access operation: save-comment` directly to set `status:blocked`, add the configured `human_needed` marker label, and reassign to the creator — this narrow exception is already granted by the rule above; (2) the Step 3 triage path may call `lisa-linear-access operation: save-comment` to post triage findings and `lisa-linear-access operation: save-issue` to add the `claude-triaged-{repo}` label — these are lightweight metadata updates that do not create or materially edit ticket content and therefore do not need to route through `linear-write-issue`.
136
136
  - If sign-in credentials are in the item, extract and pass them to the flow. If the item touches an authenticated surface and credentials are missing, that is a Step 2 failure — block and reassign rather than guessing.
137
137
  - If the item has a Validation Journey section, pass it to the verifier agent. The Validation Journey's local-verification step must point at the target backend environment named in the description.
138
- - For bug items, the reported environment named in the description or reproduction steps drives the implementation base branch via `deploy.branches`. If no environment can be found anywhere in the item, fall back to the configured default branch and record that assumption. If the reported environment is present but missing from `deploy.branches`, or its mapped branch is absent on the remote, stop and report the missing environment/branch mapping instead of defaulting. A non-integration environment fix must be merged and verified on that environment branch, then forward cherry-picked down to the integration branch through a linked follow-up.
138
+ - The environment handoff for every work item uses the same durable grammar: human bare configured key or `Confirmed: <env>`; automated `Inferred: <env> — evidence: <title|body|reproduction|hostname>`, `Assumption: <env> remote default branch <branch>` for a unique reverse-map, or `Assumption: remote default branch <branch>` otherwise. Human confirmation replaces an automated annotation with the bare key or `Confirmed: <env>`. For legacy bare values, managed draft markers and current ticket content decide provenance; provider edit history is not required. A marker proves automation; otherwise unknown provenance plus conflicting evidence stops for confirmation. Human-confirmed wins, then validated `Inferred:`; otherwise one exact `deploy.branches` key from the human-authored title, body, and reproduction steps or URL hostname drives the implementation base branch. Exclude the complete `Target Backend Environment` section and other machine-authored metadata/draft blocks so annotations cannot become evidence. Evidence supersedes only `Assumption:`. Normalize `prod` ↔ `production` only when exactly one is configured; no other aliases exist. Conflicts stop. Never infer from arbitrary branch text, URL paths/query strings, or substrings. With no signal, use the remote default and record the applicable assumption without blocking on a non-unique reverse-map. Require any selected mapping and remote branch. A reported bug environment is an example of the all-work-type rule. Non-integration fixes still require the linked forward cherry-pick.
@@ -48,13 +48,32 @@ empirical evidence only—native Playwright/Cypress/Maestro remains the regressi
48
48
 
49
49
  ## Env → base branch
50
50
 
51
- For implementation work, map the work item's `## Target Backend Environment` to
52
- the PR base branch through `.lisa.config.json` `deploy.branches`. For bugs, a
53
- reported environment extracted from the description/reproduction steps wins over
54
- an autofill default. If a reported environment is absent from `deploy.branches`,
55
- stop and report the missing mapping instead of silently falling back to the
56
- default or integration branch. A non-integration environment bug is fixed,
57
- merged, and verified on that environment branch first, then forward
58
- cherry-picked down to the integration branch via a linked follow-up.
51
+ The `## Target Backend Environment` grammar is durable: human-confirmed values
52
+ are a bare configured key or `Confirmed: <env>`; automation writes either
53
+ `Inferred: <env> evidence: <title|body|reproduction|hostname>` or
54
+ `Assumption: <env> remote default branch <branch>`. When no unique environment
55
+ maps to the default branch, use `Assumption: remote default branch <branch>`.
56
+ Human confirmation replaces an automated annotation with a bare key or
57
+ `Confirmed: <env>`. For legacy bare values, use managed draft markers and current
58
+ ticket content only; provider edit history is not required. A marker proves
59
+ automation and requires re-annotation; otherwise unknown provenance with
60
+ conflicting evidence stops for confirmation.
61
+
62
+ Resolution order is human-confirmed value; validated `Inferred:` evidence; then
63
+ one unambiguous signal from the human-authored title, body, and reproduction
64
+ steps or a URL hostname. Exclude the complete `Target Backend Environment`
65
+ section and other machine-authored metadata/draft blocks from the scan so an
66
+ annotation cannot validate or conflict with itself. Evidence supersedes only an
67
+ `Assumption:`. A signal must be an exact
68
+ `deploy.branches` key as a complete token/hostname label. The sole normalization
69
+ is `prod` ↔ `production` when exactly one is configured; no other aliases exist.
70
+ Conflicting signals stop. Never infer from arbitrary branch text, URL paths or
71
+ query strings, or substrings. With no signals, use the remote default branch and
72
+ record an assumption: include `<env>` only for a unique reverse-map, otherwise
73
+ use the branch-only form without inventing an environment or blocking. Require
74
+ any selected environment mapping and its remote branch to exist.
75
+ A non-integration environment bug is fixed, merged, and verified on that
76
+ environment branch first, then
77
+ forward cherry-picked down to the integration branch via a linked follow-up.
59
78
 
60
79
  Full reference: [reference/config-resolution.md](../reference/config-resolution.md).
@@ -21,13 +21,27 @@ information was already on the ticket; only the structure was missing).
21
21
  Gherkin Acceptance Criteria (one scenario per fix), expected-vs-actual +
22
22
  environment, Repository, Relationship Search (actually run the git+tracker
23
23
  search — don't fabricate "none found"), Validation Journey **draft** (via the
24
- vendor `*-add-journey` skill), Target Backend Environment. For bugs, parse the
25
- reported environment from the item body/reproduction steps before recommending
26
- any default: bare environment names (`dev`, `staging`, `prod`, `production`)
27
- and environment-bearing URLs (for example `staging.<domain>`, `gql.staging.*`,
28
- `dev.<domain>`) are authoritative. Only recommend the repo's remote default branch when
29
- no environment is discoverable anywhere in the work item, and record that as
30
- an assumption.
24
+ vendor `*-add-journey` skill), Target Backend Environment. Preserve a bare
25
+ configured key or `Confirmed: <env>` as human-confirmed. Automation writes
26
+ `Inferred: <env> evidence: <title|body|reproduction|hostname>` or
27
+ `Assumption: <env> remote default branch <branch>`. Without a unique
28
+ reverse-map use `Assumption: remote default branch <branch>`; human confirmation
29
+ replaces the annotation with a bare key or `Confirmed: <env>`. For legacy bare
30
+ values, use managed draft markers and current ticket content only; provider
31
+ edit history is not required. A marker proves automation and requires
32
+ re-annotation; otherwise unknown provenance plus conflicting evidence stops.
33
+ Human-confirmed wins, then validated `Inferred:`
34
+ evidence. Otherwise use one unambiguous exact `deploy.branches` key from the
35
+ title, body, and reproduction steps or a URL hostname, excluding the complete
36
+ `Target Backend Environment` section and other machine-authored metadata/draft
37
+ blocks so annotations cannot become evidence. Evidence supersedes only
38
+ `Assumption:`. Normalize only built-in
39
+ `prod` ↔ `production` when exactly one is configured; no other aliases exist.
40
+ Never infer from arbitrary branch text, URL paths/query strings, or substrings.
41
+ Conflicting signals **stop** autofill. With no environment signal, use the
42
+ remote default and record the applicable `Assumption:` form; a non-unique
43
+ reverse-map alone never blocks. Require any selected mapping and remote branch.
44
+ Never overwrite human prose.
31
45
  - **Tier B — irreducibly human:** real credentials/access that exist nowhere on
32
46
  the item or in repo test-user docs; a genuine product/scoping decision with no
33
47
  defensible default. Still propose a recommended default where one exists; ask
@@ -37,4 +37,15 @@ An artifact this flow produced is **never** a rejection-reflection trigger, no m
37
37
 
38
38
  On `rejection-reclaim` only, before re-implementing: read the rejection evidence (comments after the backward transition, review threads on the rejected PR) through the access layers, assemble **one** candidate learning with the rejection linked as provenance, and route it to the `lisa-persist-learning` skill. If that skill is absent, record the candidate as a comment that carries a **visible prose line** plus the marker (a bare marker renders as an empty comment bubble) — `Recorded a candidate learning from this rejection (queued for the judgment gate): <one-line candidate rule>.` followed by `<!-- [lisa-rejection-candidate] key=<issue>-<transition-ts> -->` — and proceed. **Marker-dedupe** on `<issue>-<backward-transition-timestamp>`: re-claiming twice produces no duplicate. Unreadable/absent evidence → proceed without a candidate, never block.
39
39
 
40
- Full contract (classification table, per-vendor bindings, reflection & evidence handoff): [reference/rejection-detection.md](../reference/rejection-detection.md).
40
+ ## Proposal rejection memory (proposal-side orthogonal to the reclaim path above)
41
+
42
+ A **loop-proposed** item that a human **closed as _not planned_** is a durable decline. Every *proposing* loop (`lisa-exploratory-qa`, `lisa-project-ideation`, `lisa-monitor`, `lisa-repair-intake`; `lisa-learnings-audit` is the shipped precedent) MUST consult it **before filing a candidate**. This is orthogonal to the `rejection-reclaim` path above — that classification and its reflection are untouched. The memory lives in the **tracker, not a new state file**.
43
+
44
+ - **Signal:** the prior item is closed *not planned* (GitHub `stateReason == "not_planned"`; the JIRA/Linear equivalent resolved via `config-resolution` — never hardcode). The GitHub compare is **case-insensitive** — raw `gh --json stateReason` returns `NOT_PLANNED` UPPERCASE, so normalize to lowercase (or read via `lisa-github-read-issue`) before comparing, never string-match raw `gh` JSON. Closed as **completed** is NOT a decline — a recurrence after a completed fix is a regression and may file.
45
+ - **Marker:** `<!-- [<loop-marker>] key=<candidate-key> -->`, key computed deterministically `printf '%s' "$normalized" | shasum -a 256 | cut -c1-12`. Search **open AND closed** items for the marker before filing (body-enumeration fallback on search-index lag); **match on the marker, never the title.**
46
+ - **Rule:** a hit on a closed-**not-planned** item **suppresses** the proposal. Re-file **only** with evidence postdating the decline, carrying BOTH the machine token (`declined <date>; recurred <date> in <ref>`) and a human acknowledgment sentence (`You declined this on <date>. It has recurred (<date>, <ref>), so we're raising it once more for your review.`).
47
+ - **Operator footer:** every loop-filed proposal ticket MUST carry, as visible prose, `To stop this from being raised again, close it as **Not planned**. Close it as **Completed** if it was fixed — a later recurrence may be re-filed as a regression.` — so the operator knows which close-reason produces which outcome.
48
+ - **Outcomes:** an all-suppressed cycle ends `nothing-needed` naming the **suppression count**; a memory check that cannot read the tracker ends `recovery-required`, never a silent `nothing-needed` (e.g. `Tracker unreachable during the decline check — restore credentials; nothing was filed this run.`).
49
+ - **Concurrency:** search-then-write = convergence, not mutual exclusion — a transient duplicate is closed by the next run; no cross-run lock.
50
+
51
+ Full contract (classification table, per-vendor bindings, reflection & evidence handoff, Proposal rejection memory): [reference/rejection-detection.md](../reference/rejection-detection.md).
@@ -217,23 +217,47 @@ Declares **where this repo's LLM Wiki lives** so the query/ingest skills can res
217
217
 
218
218
  ### Env → base branch
219
219
 
220
- Implementation flows resolve their PR base from the work item's
221
- `## Target Backend Environment` in the forward direction of `deploy.branches`.
220
+ Implementation flows resolve their PR base from the work item's environment
221
+ evidence in the forward direction of `deploy.branches`.
222
222
  For example, `{ "staging": "staging", "production": "main" }` means a staging
223
223
  work item starts from `origin/staging` and opens its PR against `staging`. This
224
224
  is the reverse/inverse of the env-keyed `done` inference that derives an
225
225
  environment from a merged PR's base branch.
226
226
 
227
- For bug work, the reported environment is authoritative. `pre-flight-autofill`
228
- must parse environment mentions from the description/body and reproduction
229
- steps, including bare names (`dev`, `staging`, `prod`, `production`) and
230
- environment-bearing URLs (`staging.<domain>`, `gql.staging.*`,
231
- `dev.<domain>`). A parsed reported environment wins over any generic autofill
232
- default. If no environment is named anywhere, the flow may fall back to the
233
- remote default branch and record that assumption on the work item.
234
-
235
- If the reported environment is not present in `deploy.branches`, stop and report
236
- the missing mapping. Do not silently default to the integration branch.
227
+ The field grammar records provenance durably: human-confirmed values are a bare
228
+ configured key or `Confirmed: <env>`; automated evidence is
229
+ `Inferred: <env> evidence: <title|body|reproduction|hostname>`; an automated
230
+ fallback is `Assumption: <env> — remote default branch <branch>`. Human
231
+ fallback without a unique reverse-map is
232
+ `Assumption: remote default branch <branch>`. Human
233
+ confirmation replaces an automated annotation with a bare key or
234
+ `Confirmed: <env>`.
235
+
236
+ For legacy bare values created before this grammar, use managed draft markers
237
+ and current ticket content only; provider edit history is neither required nor
238
+ assumed. A managed marker proves automation and requires rewriting to
239
+ `Inferred:` or `Assumption:`. Without one, provenance remains unknown, so the
240
+ bare value is usable only if no conflicting evidence exists; a conflict stops
241
+ for confirmation.
242
+
243
+ Resolve it in this order: human-confirmed wins; validated `Inferred:` evidence
244
+ is next; otherwise accept one unambiguous exact `deploy.branches` key from the
245
+ human-authored title, body, and reproduction steps or a URL hostname. Exclude
246
+ the entire `Target Backend Environment` section and all other machine-authored
247
+ metadata/draft blocks from the evidence scan, so annotations never validate or
248
+ conflict with themselves. Evidence supersedes only
249
+ an `Assumption:`. Treat the reported bug environment as an example of this
250
+ all-work-type evidence rule, not a special case. Normalize only built-in
251
+ `prod` ↔ `production` when exactly one is configured; no other aliases exist.
252
+ Never infer from arbitrary branch text, URL paths/query strings, or substrings.
253
+ Multiple conflicting signals stop. With no signals, use the remote default
254
+ branch and record an assumption: include the environment only for a unique
255
+ reverse-map; otherwise use the branch-only form without inventing an environment
256
+ or blocking solely on the reverse-map.
257
+
258
+ Every selected environment must have a unique `deploy.branches` mapping and its
259
+ mapped branch must exist on the remote. If either validation fails, stop and
260
+ report it. Do not silently default to the integration branch.
237
261
 
238
262
  For non-integration environment bugs, definition of done is two-step:
239
263
 
@@ -504,10 +528,25 @@ If a project's terminal state is the same regardless of env, set `done` to a str
504
528
 
505
529
  `deploy.branches` is also read in the **forward** direction by the build flow (`lisa-implement`): the environment a work item targets determines the branch the work is built on and the branch the PR opens against.
506
530
 
507
- 1. **Resolve the work item's target environment** its `## Target Backend Environment` field.
508
- 2. **If no environment is named**, use the **remote default branch** (`gh repo view --json defaultBranchRef`, or `origin/HEAD`) and record that default-branch assumption.
509
- 3. **If a reported environment exists**, map env → base branch via `deploy.branches` (e.g. `staging → staging`, `production → main`). A reported env absent from `deploy.branches`, or a mapped branch missing from the remote, must stop and report the exact missing environment-to-branch mapping; never guess and never silently fall back.
510
- 4. **Before any code is written**, `lisa-implement` fetches and **rebases the working branch onto `origin/<base>`, resolving conflicts**, so implementation builds on the latest target-environment code. **The PR then opens against that same base branch** (`target_branch=<base>` to `lisa-git-submit-pr`).
531
+ The durable field forms are: bare configured key or `Confirmed: <env>` for a
532
+ human-confirmed value; `Inferred: <env> evidence: <title|body|reproduction|hostname>`
533
+ for automation-backed evidence; and
534
+ `Assumption: <env> remote default branch <branch>` for a generic fallback.
535
+ When the remote default has no unique environment reverse-map, the valid form is
536
+ `Assumption: remote default branch <branch>`.
537
+ Human confirmation replaces the automated annotation with a bare key or
538
+ `Confirmed: <env>`.
539
+
540
+ For a legacy bare value, use managed draft markers and current ticket content
541
+ only; do not require provider edit history. A marker proves automation and
542
+ requires re-annotation; otherwise unknown provenance plus conflicting evidence
543
+ stops for confirmation.
544
+
545
+ 1. **Resolve provenance first.** Human-confirmed wins, then validated `Inferred:` evidence. Otherwise search the human-authored title, body, and reproduction steps or URL hostname for one unambiguous exact `deploy.branches` key. Exclude the complete `Target Backend Environment` section and other machine-authored metadata/draft blocks from the scan so annotations cannot become evidence. Evidence supersedes only an `Assumption:`.
546
+ 2. **Normalize narrowly.** Normalize built-in `prod` ↔ `production` only when exactly one of those keys is configured. No other aliases exist. Never infer from arbitrary branch text, URL paths/query strings, or substrings.
547
+ 3. **Handle absence and conflict explicitly.** Multiple conflicting signals stop. With no signals, use the remote default branch (`gh repo view --json defaultBranchRef`, or `origin/HEAD`) and record the env-bearing assumption only for a unique reverse-map; otherwise use the branch-only assumption without inventing an environment or blocking.
548
+ 4. **Validate the destination.** The selected exact configured key must map uniquely and the mapped remote branch must exist; otherwise stop without guessing or falling back.
549
+ 5. **Before any code is written**, `lisa-implement` fetches and **rebases the working branch onto `origin/<base>`, resolving conflicts**, then opens the PR against that same base (`target_branch=<base>`).
511
550
 
512
551
  This is the exact inverse of the env-keyed `done` "Branch inference" above: `done` derives the env *from* the PR base branch (reverse); the build flow derives the base branch *from* the env (forward). Both use the one `deploy.branches` map, so the branch a PR targets and the `done` status it earns always agree.
513
552
 
@@ -94,7 +94,11 @@ A manual re-run next week must not duplicate last week's tickets. Mirror the `re
94
94
  - Anomaly: `sha1("<source>:<stable-signature>:<CURRENT_REPO>")` (12 hex chars). `stable-signature` is the Sentry issue short-id (or culprit), the CloudWatch alarm name, or `errorType@location` — something that survives between runs, **never** the human title or occurrence count.
95
95
  - Gap: the literal `gap:<dimension>:<CURRENT_REPO>` (a dimension is missing-or-not; no hash needed).
96
96
  2. **Sentinel in the body.** Embed `<!-- lisa:monitor-finding: <fingerprint> -->` in every filed ticket.
97
- 3. **Search before create** (this IS gate S13). Before filing, search the tracker for the fingerprint string. The search **MUST include closed/resolved tickets** (`gh issue list --search <fp> --state all` for GitHub; JQL with no status filter for JIRA; all states for Linear) — otherwise a just-closed match is invisible and the backoff below can't fire. If an **open** ticket carries the fingerprint → skip (optionally link). If a ticket carrying it was closed **within the recently-resolved backoff window** (`monitor.backoffHours`, default **24h** matching the 24h Sentry event window; this is **not** the 2h `intake.repair.staleAfterHours`) → skip, to avoid re-filing a just-fixed regression before its signal has drained. Only file when no live or recently-resolved match exists.
97
+ 3. **Search before create** (this IS gate S13). Before filing, search the tracker for the fingerprint string. The search **MUST include closed/resolved tickets** (`gh issue list --search <fp> --state all` for GitHub; JQL with no status filter for JIRA; all states for Linear) — otherwise a just-closed match is invisible and the backoff and decline checks below can't fire. If an **open** ticket carries the fingerprint → skip (optionally link). Otherwise classify a closed match by **how** it closed:
98
+ - **Closed as _not planned_ — a permanent decline** (`rejection-detection` **Proposal rejection memory**). GitHub `stateReason == "not_planned"`; the config-resolved won't-do/canceled equivalent on JIRA/Linear (never a hardcoded lane string). This is a durable human "no", not a time-boxed guard: **suppress the finding regardless of age**, and re-file only with evidence that **postdates the decline**. The new ticket MUST carry BOTH the machine token (`declined <date>; recurred <date> in <ref>`) and the human acknowledgment sentence (`You declined this on <date>. It has recurred (<date>, <ref>), so we're raising it once more for your review.`). This layers *on top of* the backoff below — a not_planned close outlives any window.
99
+ - **Closed as _completed_ within the recently-resolved backoff window** (`monitor.backoffHours`, default **24h** — matching the 24h Sentry event window; this is **not** the 2h `intake.repair.staleAfterHours`) → skip, to avoid re-filing a just-fixed regression before its signal has drained. A completed close **older** than the window is not a decline — a genuine recurrence is a regression and may file.
100
+
101
+ Only file when no live match, no recently-resolved completed match, and no prior not_planned decline exists.
98
102
 
99
103
  ## The cap
100
104
 
@@ -49,14 +49,29 @@ spec.
49
49
  - **Validation Journey (draft)** — run the vendor `*-add-journey` skill to draft
50
50
  the click-path, markers, and viewports from the reproduction steps. This is a
51
51
  draft for human approval, not the final ratified contract.
52
- - **Target Backend Environment** — for bugs, first parse the reported
53
- environment from the title, description/body, screenshots captions, links, and
54
- reproduction steps. Bare words such as `dev`, `staging`, `prod`, and
55
- `production` count, as do environment-bearing URLs such as
56
- `staging.<domain>`, `gql.staging.*`, and `dev.<domain>`. That reported
57
- environment is authoritative for the draft. Only recommend the repo's
58
- remote default branch when no environment is discoverable anywhere in the
59
- work item, and record the default as an explicit assumption.
52
+ - **Target Backend Environment** — preserve a bare configured key or
53
+ `Confirmed: <env>` as human-confirmed. Automated evidence must write
54
+ `Inferred: <env> evidence: <title|body|reproduction|hostname>`; a generic
55
+ fallback must write `Assumption: <env> remote default branch <branch>`.
56
+ If the default branch has no unique environment reverse-map, instead write
57
+ `Assumption: remote default branch <branch>` without inventing an environment.
58
+ Human confirmation replaces an automated annotation with a bare key or
59
+ `Confirmed: <env>`. For legacy bare values, use managed draft markers and
60
+ current ticket content only; provider edit history is not required. A marker
61
+ proves automation and requires re-annotation; otherwise unknown provenance
62
+ plus conflicting evidence stops for confirmation. A human-confirmed value wins, followed by validated
63
+ `Inferred:` evidence. Otherwise inspect the title, body, and reproduction
64
+ steps or a URL hostname for one unambiguous exact `deploy.branches` key,
65
+ excluding the complete `Target Backend Environment` section and all other
66
+ machine-authored metadata/draft blocks so annotations cannot become evidence.
67
+ Clear evidence supersedes only an `Assumption:` value. The sole normalization
68
+ is `prod` ↔ `production` when exactly one key is configured; no other aliases
69
+ exist. Never infer from arbitrary branch text, URL paths or query strings, or
70
+ substrings. Multiple conflicting signals **stop** autofill. With no
71
+ environment signal, use the remote default and record the applicable
72
+ `Assumption:` form; a missing/ambiguous reverse-map alone never blocks.
73
+ Require any selected environment mapping and remote branch. Never overwrite
74
+ human prose.
60
75
 
61
76
  **Tier B — irreducibly human (cannot invent — but still propose a default):**
62
77
 
@@ -101,3 +101,64 @@ Mining a learning is not enough — if the agent then rebuilds the same rejected
101
101
  - **The evidence summary** names: what was rejected, why (the defect the QA comment named), and the specific approach the rejection named as wrong.
102
102
  - **The plan must reckon with it.** On a `rejection-reclaim`, the re-implementation plan MUST explicitly address the rejection evidence and MUST NOT re-propose the specific approach the rejection named as wrong.
103
103
  - **Absence never blocks.** If the rejection evidence is unreadable or absent, the agent still implements the item — degraded, not stopped.
104
+
105
+ ## Proposal rejection memory (a loop-proposed item closed as *not planned*)
106
+
107
+ Everything above is **claim-time** memory — a work item that was bounced *backward* through the lanes. This section is its orthogonal twin: **proposal-time** memory — an item a **loop itself proposed** that a human then **closed as _not planned_**. The two never touch. The `rejection-reclaim` classification, its reflection path, and its evidence handoff above are **unchanged**; this section adds a second, independent contract that every *proposing* loop consults **before it files a candidate**.
108
+
109
+ The most corrosive failure of an unattended fleet is nagging: a human declines a proposal and the loop cheerfully files it again next cycle, until operators stop reading the tracker. The cure is to make a decline durable. The memory lives in the **tracker, not a new state file** — a closed-as-not-planned proposal *is* the record of the human's "no", matched by a stable marker key. This generalizes `lisa-learnings-audit`'s already-shipped idempotency discipline to every proposing loop: `lisa-exploratory-qa`, `lisa-project-ideation`, `lisa-monitor`, and `lisa-repair-intake` cite this section; the gardener (`lisa-learnings-audit`) is the shipped precedent it was modeled on, not a second implementation.
110
+
111
+ ### Rejection signal — "not planned", resolved from config
112
+
113
+ A proposal is **declined** when its prior item is **closed as _not planned_**:
114
+
115
+ - **GitHub** — `stateReason == "not_planned"` (surfaced by `lisa-github-read-issue`, which renders `State: closed (not_planned)`). **The comparison is case-insensitive:** raw `gh issue view --json stateReason` returns the value UPPERCASE (`NOT_PLANNED` / `COMPLETED`), so a literal string-compare against `not_planned` on raw `gh` output would false-negative a genuine decline. Normalize the value to lowercase before comparing, or consume it through `lisa-github-read-issue`'s already-lowercased rendering — never string-match raw `gh` JSON directly.
116
+ - **JIRA / Linear** — the configured *not-planned* equivalent resolved per the `config-resolution` rule (a JIRA won't-do resolution, a Linear canceled state), **never a hardcoded lane string** — exactly as the claim-time lane names above always come from `.lisa.config.json`, never a literal.
117
+
118
+ **Closed as _completed_ is NOT a decline.** A completed fix whose underlying problem later recurs is a **regression**, and the loop **may file** it — the recurrence is genuinely new work, not a re-proposal of the declined thing. Only *not planned* is the durable "no".
119
+
120
+ ### Marker discipline — deterministic key, open AND closed search
121
+
122
+ Every loop-proposed item carries a **visible prose line** plus a marker (a bare HTML marker renders as an empty comment bubble):
123
+
124
+ ```
125
+ <!-- [<loop-marker>] key=<candidate-key> -->
126
+ ```
127
+
128
+ `<loop-marker>` is the proposing loop's own marker (`[lisa-exploratory-qa]`, `[lisa-project-ideation]`, `lisa:monitor-finding`, `[lisa-repair-intake]`, `[lisa-gardener]`). `<candidate-key>` is computed **deterministically — never estimated by the model** (the gardener's exact formula):
129
+
130
+ 1. **Normalize** the candidate's stable identity (surface + symptom, idea key, or finding signature): trim, collapse every internal whitespace run to a single space, lowercase.
131
+ 2. **Hash** in Bash: `printf '%s' "$normalized" | shasum -a 256 | cut -c1-12`.
132
+
133
+ The same candidate therefore always produces the same key across runs, regardless of which session computes it. **Before filing anything, every loop searches the tracker for that marker across open AND closed items** — keyed on the stable prefix first, the hash as disambiguation only — plus a **body-enumeration fallback for search-index lag** (`gh issue list --state all --json number,body` and grep the bodies; `gh search issues` already covers open and closed by default — `--state all` is NOT a valid `gh search` flag). **Match on the marker, never the title.**
134
+
135
+ ### Operator footer — teach the close-reason where the operator reads it
136
+
137
+ The whole mechanism hinges on a distinction the operator cannot see unless we say it: closing a proposal **Not planned** silences it for good, while closing it **Completed** leaves the door open to a regression re-file. So every loop-filed proposal ticket MUST carry this footer verbatim as its own visible prose line (not only the HTML marker), so the human at the gate knows exactly which close-reason produces which outcome:
138
+
139
+ > To stop this from being raised again, close it as **Not planned**. Close it as **Completed** if it was fixed — a later recurrence may be re-filed as a regression.
140
+
141
+ This footer is **required on every proposing loop's filed ticket** (`lisa-exploratory-qa`, `lisa-monitor`, `lisa-project-ideation`, `lisa-learnings-audit`, and any other loop that files a proposal). It is what makes the tracker-as-memory legible to a non-technical operator — the close-button becomes a documented control, not a guess.
142
+
143
+ ### The rule
144
+
145
+ A marker hit on a **closed-as-not-planned** item **suppresses the proposal** — regardless of title similarity. Re-proposal is permitted **only** with evidence that **postdates the decline**, and the re-filed item MUST carry BOTH of the following:
146
+
147
+ 1. **A machine token** for the dedupe/audit trail — generalizing the gardener's wording:
148
+
149
+ > declined `<decline-date>`; recurred `<recurrence-date>` in `<recurrence-ref>`
150
+
151
+ 2. **A human acknowledgment sentence** in plain prose, so re-raising reads as a respectful return to an answered question rather than a machine nagging:
152
+
153
+ > You declined this on `<decline-date>`. It has recurred (`<recurrence-date>`, `<recurrence-ref>`), so we're raising it once more for your review.
154
+
155
+ Naming the decline date, the recurrence date, and the recurrence reference in both forms is what turns "raising it again" into an auditable, evidence-backed, operator-legible act rather than nagging. A marker hit on a closed-as-**completed** item is not a decline — it falls under the regression path above.
156
+
157
+ ### Interaction with run outcomes
158
+
159
+ - **Every candidate suppressed** — a cycle whose only candidates were each suppressed by a prior decline terminates **`nothing-needed`**, and its one-line summary **names the suppression count** (e.g. `Explored 4 personas; 2 candidates suppressed by a prior decline — nothing new to propose.`). Respecting a decline is thereby *visible* in the run record — never indistinguishable from finding nothing.
160
+ - **Tracker unreadable during the memory check** — if the open-and-closed marker search cannot run (tracker unreachable, credentials revoked, the substrate broken), the loop terminates **`recovery-required`**, **never** a silent `nothing-needed`. A memory check that could not run is a broken loop, not a quiet one — this is the exact failure mode the contract exists to exclude, so "I saw no candidates" must never be conflated with "I could not look". The one-line summary names the broken check and the fix in operator language, e.g. `Tracker unreachable during the decline check — restore credentials; nothing was filed this run.`
161
+
162
+ ### Concurrency honesty
163
+
164
+ The search-then-write here is **not** an atomic claim: two truly concurrent runs can each miss the other's in-flight proposal and file a transient duplicate. It therefore guarantees **convergence, not mutual exclusion** — the duplicate is found and closed by the next run's marker search, and because the key is a stable content hash, a duplicate never multiplies. State this rather than implying a lock; a cross-run locking protocol would be disproportionate to the risk.
@@ -74,7 +74,15 @@ Each finding is a flat leaf, so `build_ready` applies directly — pass it expli
74
74
 
75
75
  ### Idempotency — don't spam duplicates
76
76
 
77
- Re-running a pass must not refile the same finding. Before creating a ticket, search the tracker for an **open** ticket carrying a stable marker `[lisa-exploratory-qa] <finding-key>` in its body (the `<finding-key>` is a stable slug of surface + symptom, e.g. `settings-modal/horizontal-overflow@tablet`). If one exists, reference/update it instead; only create when none exists. **Match by the marker, never by title.** A *closed* prior ticket does not suppress a new one a recurrence after a fix is a genuine regression.
77
+ Re-running a pass must not refile the same finding. Before creating a ticket, search the tracker for a ticket carrying a stable marker `[lisa-exploratory-qa] <finding-key>` in its body (the `<finding-key>` is a stable slug of surface + symptom, e.g. `settings-modal/horizontal-overflow@tablet`). Per the `rejection-detection` rule's **Proposal rejection memory** section, that marker search MUST cover **open AND closed** tickets (with a body-enumeration fallback on search-index lag), and **match by the marker, never by title.** Then split on how any prior ticket closed:
78
+
79
+ - **Open** ticket carrying the marker → reference/update it instead; do not create a second.
80
+ - **Closed as _completed_** → does **not** suppress. A recurrence after a fix is a genuine **regression**, so file the finding.
81
+ - **Closed as _not planned_** (GitHub `stateReason == "not_planned"`; the config-resolved won't-do/canceled equivalent on JIRA/Linear) → a human **declined** this finding, so **suppress it**. Re-file only with evidence that **postdates the decline**, carrying BOTH the machine token (`declined <date>; recurred <date> in <ref>`) and a human acknowledgment sentence (`You declined this on <date>. It has recurred (<date>, <ref>), so we're raising it once more for your review.`).
82
+
83
+ Every filed finding ticket MUST end with the `rejection-detection` **operator footer** as a visible prose line so the operator knows which close-reason silences it:
84
+
85
+ > To stop this from being raised again, close it as **Not planned**. Close it as **Completed** if it was fixed — a later recurrence may be re-filed as a regression.
78
86
 
79
87
  ## Output
80
88
 
@@ -94,13 +102,13 @@ and records it, so a quiet run and a broken run are never mistaken for each othe
94
102
  | This cycle's exit path | Run outcome |
95
103
  |---|---|
96
104
  | Findings filed — one or more `Bug` / `Improvement` tickets created or referenced (§6) | `candidate-proposed` |
97
- | Clean pass — explored the personas and surfaces, nothing worth filing | `nothing-needed` |
98
- | Tracker unconfigured — the §1 stop path; findings cannot be filed | `recovery-required` |
105
+ | Clean pass — explored the personas and surfaces, nothing worth filing — **or** every candidate was suppressed by a prior decline (`rejection-detection` **Proposal rejection memory**): the summary MUST name the suppression count | `nothing-needed` |
106
+ | Tracker unconfigured — the §1 stop path; findings cannot be filed — **or** the open-and-closed rejection-memory marker search could not run (tracker unreachable / credentials revoked): a memory check that could not run is a broken loop, never a silent `nothing-needed` | `recovery-required` |
99
107
  | A degradation that still let the pass explore (e.g. Kane unavailable, one persona unreachable) | the outcome it actually reached above, with the summary **leading with the degradation** — degradation never mints a seventh token |
100
108
 
101
109
  Record **exactly one** outcome per invocation through the run-record CLI, naming this loop's runbook
102
110
  (the `--summary` is the operator-readable one-liner in the contract's exemplar voice — plain,
103
- specific, actionable, e.g. `Explored 4 personas; nothing confusing to file.` for `nothing-needed`):
111
+ specific, actionable, e.g. `Explored 4 personas; nothing confusing to file.` — or, when a decline suppressed the only candidates, `Explored 4 personas; 2 candidates suppressed by a prior decline — nothing new to propose.` — for `nothing-needed`; and for a `recovery-required` from an unreadable decline check, `Tracker unreachable during the decline check — restore credentials; nothing was filed this run.`):
104
112
 
105
113
  ```bash
106
114
  node "${CLAUDE_PLUGIN_ROOT}/scripts/automation-run-record.mjs" \
@@ -154,7 +154,7 @@ When `issue_type ∉ {Bug, Epic}`, `parent_ref` must be set — **except for a b
154
154
 
155
155
  #### S8 — Target Backend Environment
156
156
 
157
- When `runtime_behavior_change = true`, body must contain `## Target Backend Environment` with one of `dev`, `staging`, `prod`. Skipped for doc-only / config-only / type-only / Epic.
157
+ When `runtime_behavior_change = true`, the body must contain `## Target Backend Environment`. Read accepted environments from the exact configured keys of `.lisa.config.json` `deploy.branches`, never from a hardcoded list. Accept a human-confirmed bare exact configured key or `Confirmed: <env>`, automated `Inferred: <env> — evidence: <title|body|reproduction|hostname>`, automated `Assumption: <env> — remote default branch <branch>` for a unique reverse-map, or `Assumption: remote default branch <branch>` when no unique reverse-map exists. Human confirmation replaces an automated annotation with the bare key or `Confirmed: <env>`. For legacy bare values, use managed draft markers and current ticket content only; provider edit history is not required. A marker proves automation and requires re-annotation; otherwise unknown provenance plus conflicting evidence fails for confirmation. Validate the annotation shape/source and remote-default branch; validate `<env>` as an exact configured key whenever present. A valid branch-only assumption must not fail solely because its reverse-map is absent or ambiguous. Normalize built-in `prod` ↔ `production` only when exactly one of those keys is configured. No other aliases are valid. Skipped for doc-only / config-only / type-only / Epic.
158
158
 
159
159
  #### S9 — Sign-in Required
160
160
 
@@ -38,7 +38,7 @@ Resolve `<ORG>` and `<REPO>` from the ref or from `.lisa.config.json`.
38
38
  | Priority | CREATE | Label `priority:<low|medium|high|critical>`. |
39
39
  | Acceptance criteria | Story, Task, Bug, Sub-task, Improvement | Gherkin in `## Acceptance Criteria` — see Phase 3. |
40
40
  | Validation Journey | Runtime-behavior changes | Delegate to `/github-add-journey`. |
41
- | Target backend environment | Runtime-behavior changes | Recorded under `## Target Backend Environment`. Skip only for doc / config / type-only. |
41
+ | Target backend environment | Runtime-behavior changes | For every work type, use an exact `deploy.branches` key when an environment is known. Human: bare key or `Confirmed: <env>`. Automation: `Inferred: <env> — evidence: <title\|body\|reproduction\|hostname>`, `Assumption: <env> — remote default branch <branch>` for a unique reverse-map, or `Assumption: remote default branch <branch>` otherwise. Human confirmation replaces an automated annotation with the bare key or `Confirmed: <env>`. |
42
42
  | Sign-in account / credentials | Authenticated-surface tickets | Recorded under `## Sign-in Required`. |
43
43
  | Repository | Bug, Task, Sub-task | GitHub Issues live in exactly one repo by definition — record the repo name under `## Repository`, and reject any AC bullet that references a different repo. |
44
44
  | Source Requirement | PRD-sourced issues (`prd_source` provided) | `## Source Requirement` with PRD link + verbatim requirement quote(s) — see Phase 3; enforced at every level, sub-issues included. |
@@ -91,8 +91,14 @@ Scenario: <name>
91
91
  [Explicit list of what this issue does NOT cover. Forces scope discipline.]
92
92
 
93
93
  ## Target Backend Environment
94
- [Required when the issue changes runtime behavior. One of: dev / staging / prod.
95
- Skip section entirely for doc-only, config-only, or type-only issues.]
94
+ [Required when the issue changes runtime behavior. Use an exact
95
+ `deploy.branches` key. A human-confirmed value is a bare key or
96
+ `Confirmed: <env>`. An automated evidence write is
97
+ `Inferred: <env> — evidence: <title|body|reproduction|hostname>`; an automated
98
+ generic default is `Assumption: <env> — remote default branch <branch>`.
99
+ Without a unique reverse-map use `Assumption: remote default branch <branch>`.
100
+ Human confirmation replaces the automated annotation with a bare key or
101
+ `Confirmed: <env>`. Skip only for doc/config/type-only issues.]
96
102
 
97
103
  ## Sign-in Required
98
104
  [Include this section ONLY if the work touches authenticated surfaces.
@@ -84,8 +84,12 @@ Using the general-purpose agent in Team Lead session, Determine the name of this
84
84
 
85
85
  Using the general-purpose agent in Team Lead session, **determine the base branch from the ticket's target environment, then sync the working branch onto the latest of it before any work** — so implementation always builds on current target-environment code:
86
86
 
87
- 1. **Resolve the target environment** from the resolved work item — its `## Target Backend Environment` section (the field the `*-write-*` / `*-add-journey` skills record). For bug work, the environment named in the report is authoritative: if the title/body/reproduction steps mention bare env names (`dev`, `staging`, `prod`, `production`) or env-bearing URLs (`staging.<domain>`, `gql.staging.*`, `dev.<domain>`), that reported environment wins over a generic autofill default.
88
- 2. **Map the environment to a base branch** via `.lisa.config.json` `deploy.branches` (e.g. `staging → staging`, `production → main`) — the forward direction of the same map the env-keyed `done` resolution uses in reverse (see the `config-resolution` rule). If the work item names **no** environment, the base branch is the **remote default branch** (`gh repo view --json defaultBranchRef -q .defaultBranchRef.name`, or `git remote set-head origin -a` then read `origin/HEAD`), and record that fallback assumption in the plan/tracker artifact before proceeding. If the reported environment is absent from `deploy.branches`, or its branch does not exist on the remote, **stop and report** — never guess a base and never silently fall back to the default/integration branch.
87
+ 1. **Resolve the target environment with durable provenance.** The `## Target Backend Environment` value has this exact grammar: a human-confirmed value is either a bare configured key or `Confirmed: <env>`; automated evidence writes `Inferred: <env> evidence: <title|body|reproduction|hostname>`; an automated fallback writes `Assumption: <env> remote default branch <branch>` when the branch maps uniquely, or `Assumption: remote default branch <branch>` when it does not. Human confirmation replaces an automated annotation with the bare configured key or `Confirmed: <env>`. For a legacy bare value created before this grammar, use managed draft markers and current ticket content only — provider edit history is not required or assumed. A managed marker proves automation and requires rewriting to `Inferred:` or `Assumption:`; without a marker provenance is unknown, so the value may be used only when no conflicting evidence exists, and a conflict **stops for confirmation**.
88
+ - A human-confirmed value wins. Otherwise a validated `Inferred:` value is next.
89
+ - Otherwise inspect the human-authored title, body, and reproduction steps for exactly one unambiguous signal: an exact `deploy.branches` key as a complete token, or that key as a complete label in a URL hostname (`staging.<domain>`, `gql.staging.*`). Exclude the entire `Target Backend Environment` section and all other machine-authored metadata/draft blocks from this evidence scan so an `Inferred:` or `Assumption:` annotation can never validate or conflict with itself. Clear evidence may supersede only an `Assumption:` value, never a human-confirmed value.
90
+ - The only normalization is built-in `prod` ↔ `production`, and only when exactly one of those keys exists in `deploy.branches`; normalize to that configured key. No other aliases exist.
91
+ - Never infer from arbitrary branch text, URL paths or query strings, or substrings inside other words or hostname labels. Multiple conflicting signals after normalization **stop** the flow. If there are no signals, resolve the remote default branch (`gh repo view --json defaultBranchRef -q .defaultBranchRef.name`, or `git remote set-head origin -a` then `origin/HEAD`). When it reverse-maps uniquely, write the env-bearing `Assumption:` form; when the reverse-map is not unique, write the branch-only form and continue on the remote default without inventing an environment or blocking solely for that ambiguity. Record the fallback assumption in the plan/tracker artifact.
92
+ 2. **Map the resolved environment to a base branch** through `.lisa.config.json` `deploy.branches` — the forward direction of the env-keyed `done` resolution. The selected exact configured key must map uniquely, and the mapped branch must exist on the remote. A missing/ambiguous mapping or remote branch **stops** the flow; never guess or silently fall back.
89
93
  3. **Establish the feature branch off the latest base, conflict-free:**
90
94
  - `git fetch origin`.
91
95
  - Already on a feature branch with an **open PR** → reuse it. If the PR's base ≠ the resolved base branch, surface the mismatch and re-target only with confirmation — the ticket's environment is the source of truth.
@@ -155,7 +155,7 @@ When `issue_type ∉ {Bug, Epic}`, `parent_key` must be set — **except for a b
155
155
 
156
156
  #### S8 — Target Backend Environment
157
157
 
158
- When `runtime_behavior_change = true`, description must contain a `Target Backend Environment` section (`h2.` / `##` in proposed text, or an ADF heading in live JIRA) with one of `dev`, `staging`, `prod`. Skipped for doc-only / config-only / type-only / Epic.
158
+ When `runtime_behavior_change = true`, the description must contain a `Target Backend Environment` section (`h2.` / `##` in proposed text, or an ADF heading in live JIRA). Read accepted environments from the exact configured keys of `.lisa.config.json` `deploy.branches`, never from a hardcoded list. Accept a human-confirmed bare exact configured key or `Confirmed: <env>`, automated `Inferred: <env> — evidence: <title|body|reproduction|hostname>`, automated `Assumption: <env> — remote default branch <branch>` for a unique reverse-map, or `Assumption: remote default branch <branch>` when no unique reverse-map exists. Human confirmation replaces an automated annotation with the bare key or `Confirmed: <env>`. For legacy bare values, use managed draft markers and current ticket content only; provider edit history is not required. A marker proves automation and requires re-annotation; otherwise unknown provenance plus conflicting evidence fails for confirmation. Validate the annotation shape/source and remote-default branch; validate `<env>` as an exact configured key whenever present. A valid branch-only assumption must not fail solely because its reverse-map is absent or ambiguous. Normalize built-in `prod` ↔ `production` only when exactly one of those keys is configured. No other aliases are valid. Skipped for doc-only / config-only / type-only / Epic.
159
159
 
160
160
  #### S9 — Sign-in Required
161
161