@codyswann/lisa 3.51.3 → 3.51.4

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 (66) hide show
  1. package/dist/core/upstream-evidence-manifest.js +3 -3
  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-sonarcloud-access/SKILL.md +33 -15
  6. package/plugins/lisa/rules/reference/credential-substrate-precedence.md +11 -5
  7. package/plugins/lisa/rules/reference/integration-access-layer.md +12 -9
  8. package/plugins/lisa/skills/lisa-sonarcloud-access/SKILL.md +34 -16
  9. package/plugins/lisa-agy/plugin.json +1 -1
  10. package/plugins/lisa-agy/skills/lisa-sonarcloud-access/SKILL.md +34 -16
  11. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  12. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  13. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  14. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  16. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-copilot/rules/reference/credential-substrate-precedence.md +11 -5
  18. package/plugins/lisa-copilot/rules/reference/integration-access-layer.md +12 -9
  19. package/plugins/lisa-copilot/skills/lisa-sonarcloud-access/SKILL.md +34 -16
  20. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-cursor/rules/credential-substrate-precedence-reference.mdc +11 -5
  22. package/plugins/lisa-cursor/rules/integration-access-layer-reference.mdc +12 -9
  23. package/plugins/lisa-cursor/skills/lisa-sonarcloud-access/SKILL.md +34 -16
  24. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  26. package/plugins/lisa-expo-agy/plugin.json +1 -1
  27. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  31. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  36. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  37. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  41. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  42. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  46. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  47. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  51. package/plugins/lisa-rails-agy/plugin.json +1 -1
  52. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  56. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  57. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  61. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  62. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  64. package/plugins/src/base/rules/reference/credential-substrate-precedence.md +11 -5
  65. package/plugins/src/base/rules/reference/integration-access-layer.md +12 -9
  66. package/plugins/src/base/skills/lisa-sonarcloud-access/SKILL.md +34 -16
@@ -431,7 +431,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
431
431
  "plugins/src/base/rules/reference/coding-philosophy.md": "fed8381f16a5d6793a49d84d5813d62125808cb2f4981a558b119cf63e2586d9",
432
432
  "plugins/src/base/rules/reference/config-resolution.md": "83c46e2bb8c3f84aba013196a5e6a41104136e36e37b197e4d7a4e896f7d6aa9",
433
433
  "plugins/src/base/rules/reference/convergent-review.md": "788a9d4dc2af7a928c3ccbb4d53a92856bb3544941ce512cfe38068d6b35850d",
434
- "plugins/src/base/rules/reference/credential-substrate-precedence.md": "5420156ca98fff0d26d1537fbd54781e70cb801cdb8e770a6caa3cb8acd253c7",
434
+ "plugins/src/base/rules/reference/credential-substrate-precedence.md": "2ae7833b6a0d8416d78946e5bc480384002ec71bdf9dd6b10aded9186ddddf43",
435
435
  "plugins/src/base/rules/reference/dependency-decision-records.md": "84f9fb8fa0a606307e828ec355ccbf2258beeeb88795dd113abe9bb2c37db39f",
436
436
  "plugins/src/base/rules/reference/dependency-internalization-kit.md": "8c8e9bddbe2165905c3919ae9dd3d131b557cf9c7eb370393dfa85827076c73b",
437
437
  "plugins/src/base/rules/reference/dependency-trust-classes.md": "82216b80d4807e0ad302d04924032cc6a7a95b26f72ea853e378572a5c31821c",
@@ -444,7 +444,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
444
444
  "plugins/src/base/rules/reference/factory-model.md": "b28a2ea4df7c33390111667a2807d9003cf8c9a14829f6fb0dbc929b05bfed3a",
445
445
  "plugins/src/base/rules/reference/falsifiable-checks.md": "a0d7c3be070937042d17e98bdb955b87f30be5d298be91e33c1e6883cae2635d",
446
446
  "plugins/src/base/rules/reference/history-audit.md": "20a46390f71fadda499c61193d430c3d53df49b55a4cefa50a112f82fa4b05ef",
447
- "plugins/src/base/rules/reference/integration-access-layer.md": "6d0f419b315ffcf9bdd14a556a81c05848e8245e2ba850696e72d4cff2e65600",
447
+ "plugins/src/base/rules/reference/integration-access-layer.md": "c5fc07f5f46ba1f99403b6e4fd5603d153411a9bb1838bea320b26a5bd5273d6",
448
448
  "plugins/src/base/rules/reference/intent-routing.md": "988f8f45b41056c2adaa1a3e5f6ea926ac56a2fd041c07f98a9c2b271050efdd",
449
449
  "plugins/src/base/rules/reference/leaf-only-lifecycle.md": "3d6d531fdca61a348fa1dd1bdb4c28fe66c85fb955238ef668a78cce4a36a7a1",
450
450
  "plugins/src/base/rules/reference/learnings-ladder.md": "4b6760e8ec58dea0e646cfa1b0518f468cc959ef3be55e3f87c225ec076f53c7",
@@ -687,7 +687,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
687
687
  "plugins/src/base/skills/lisa-setup-workstation/scripts/catalogue.mjs": "eb0b8ec8a5d4fd81402dcbf40e6ccb55eb5e0c960f11aa928e45b99de43fabbc",
688
688
  "plugins/src/base/skills/lisa-setup-workstation/scripts/cli.mjs": "53b369907ce168991169521f50070f9741640c0c466ece7c7c4736455903fb00",
689
689
  "plugins/src/base/skills/lisa-setup-workstation/scripts/workstation.mjs": "6ab19c08aa9db7643aa49133ba1d0febf1c1dbdc9a503026a01b1ce0a83f68ab",
690
- "plugins/src/base/skills/lisa-sonarcloud-access/SKILL.md": "b98aba73d367a671395a08433a47034fce7ea701d31ef89b6aa866efc4dd3fcb",
690
+ "plugins/src/base/skills/lisa-sonarcloud-access/SKILL.md": "94340f41e45b2e3bcf3ef99c6b60a760140f9418e50aaa90be836ce2cfc18cc1",
691
691
  "plugins/src/base/skills/lisa-spec-conformance/SKILL.md": "50e79afcfabf16d36273325aabb58571c9a0e1cafe7a2865e2da10c6d46571eb",
692
692
  "plugins/src/base/skills/lisa-sync-down/SKILL.md": "15799079e2d64ba512fa492efea6a1a2f96a19f23935d85a7e91d9e115fbd9a4",
693
693
  "plugins/src/base/skills/lisa-task-decomposition/SKILL.md": "eb78838e1f121a7a619a841333b1adfce124dad8881853d14107512ead09d30f",
package/package.json CHANGED
@@ -141,7 +141,7 @@
141
141
  "zod-validation-error": "^4.0.0"
142
142
  },
143
143
  "name": "@codyswann/lisa",
144
- "version": "3.51.3",
144
+ "version": "3.51.4",
145
145
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
146
146
  "main": "dist/index.js",
147
147
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "3.51.3",
3
+ "version": "3.51.4",
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": "3.51.3",
3
+ "version": "3.51.4",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -12,16 +12,26 @@ this skill owns the tool selection.
12
12
 
13
13
  ## Substrate
14
14
 
15
- There is exactly one substrate: the **official SonarQube MCP server**, provided by
15
+ The **preferred** substrate is the **official SonarQube MCP server**, provided by
16
16
  the `sonarqube` plugin and launched by the `sonar` CLI (`sonar run mcp`). It
17
17
  authenticates headlessly from environment variables — no browser, no OS keychain —
18
18
  so it is the same substrate on a developer machine and in a headless cloud routine.
19
-
20
- That makes this skill conformant with `credential-substrate-precedence` as a
21
- single-substrate access layer: this MCP **is** the configured-provider substrate
22
- (it is token-authenticated, not browser-OAuth), so there is no interactive tier to
23
- demote and no second REST tier to add. Identity-match against the configured org
24
- remains mandatory, as on every substrate.
19
+ Prefer it because it owns the tool selection this skill exists to centralise.
20
+
21
+ It is not the only sanctioned substrate. The **Sonar Web API**, authenticated with
22
+ the same token, is a sanctioned fallback for read-only operations when the MCP is
23
+ not wired on this surface. An earlier revision of this file said otherwise — that
24
+ the MCP was "the only sanctioned substrate" and a missing MCP was "not a reason to
25
+ curl the Web API" — and that was wrong on its face: `.github/workflows/quality.yml`
26
+ already reads `api/ce/task` with a token to turn an opaque failed scan into an
27
+ operator-readable one. A rule the shipping repository contradicts is documentation,
28
+ not a constraint.
29
+
30
+ The distinction that does hold: a token-authenticated MCP **is** the
31
+ configured-provider substrate under `credential-substrate-precedence` (it is not
32
+ browser-OAuth), so there is no interactive tier to demote here. That is a statement
33
+ about tier ORDER, not about exclusivity. Identity-match against the configured org
34
+ remains mandatory on either substrate.
25
35
 
26
36
  - `SONARQUBE_CLI_TOKEN` — required (Sonar user/analysis token).
27
37
  - `SONARQUBE_CLI_ORG` — required for SonarQube Cloud.
@@ -89,16 +99,21 @@ being on PATH is not access. Probe by searching projects (the `projects` toolset
89
99
  always enabled):
90
100
 
91
101
  - If a `mcp__sonarqube__*` project-search tool returns, access is proven.
92
- - If no `mcp__sonarqube__*` tool is present, or the call fails authentication, fail
93
- loudly and do not improvise a substitute:
102
+ - If no `mcp__sonarqube__*` tool is present on this surface, that is a **demotion,
103
+ not a blocker**. Fall back to the Sonar Web API with the same resolved token for
104
+ the read-only operation at hand.
105
+ - Only when neither substrate can prove access — no MCP tool *and* no usable token
106
+ — is this a terminal tool-access-gate failure. Say so, and do not improvise a
107
+ third route:
94
108
 
95
109
  ```text
96
110
  Error: no SonarQube access. Run /lisa:setup:sonar (or `sonar integrate <agent>`), and set SONARQUBE_CLI_TOKEN (+ SONARQUBE_CLI_ORG for Cloud / SONARQUBE_CLI_SERVER for Server).
97
111
  ```
98
112
 
99
- There is no hand-rolled REST fallback: the official MCP is headless-capable via the
100
- token env vars, so it is the only sanctioned substrate. A missing MCP is a
101
- tool-access-gate failure to surface, not a reason to curl the Web API.
113
+ The distinction matters because the two cases have different remedies. An absent
114
+ MCP on a surface that holds a valid credential is a wiring gap the agent can work
115
+ around; treating it as terminal manufactures a tool-access failure on a surface
116
+ that has access.
102
117
 
103
118
  ## Operation → toolset map
104
119
 
@@ -127,14 +142,17 @@ tool accepts them.
127
142
  Every operation in the map above is **read-only** — quality, coverage, and
128
143
  security data. So the `credential-substrate-precedence` guarded fallback for
129
144
  mutating operations (write, read back, assert the tenant from the response, roll
130
- back on mismatch) is not engaged here; with one substrate there is nothing to
131
- fall back to in any case. A future operation that mutates Sonar state marking
145
+ back on mismatch) is not engaged here, because nothing in the map writes. The
146
+ Web API fallback is sanctioned for READS only; it does not open a mutation path.
147
+ A future operation that mutates Sonar state — marking
132
148
  a hotspot safe, changing an issue's status — is a write and MUST reconcile by
133
149
  read-back before any retry.
134
150
 
135
151
  ## Invariants
136
152
 
137
- - The official SonarQube MCP is the only substrate; there is no REST fallback.
153
+ - The official SonarQube MCP is the preferred substrate, not the only one. The
154
+ Sonar Web API with the same token is a sanctioned read-only fallback, and a
155
+ missing MCP is a demotion rather than a terminal failure.
138
156
  - `SONARQUBE_CLI_*` values are resolved through `lisa-secrets-access` and
139
157
  exported in-process, with the bare environment variables as the documented
140
158
  fallback. Never write them to a dotfile or a `.env` on a local surface.
@@ -179,8 +179,14 @@ the chokepoint cannot answer for is a setup gap to fix, not a store to add.
179
179
  4. Keep MCP adapters and name the operations for which MCP is the only substrate.
180
180
  5. Make the terminal failure name the exact credential and remediation command.
181
181
 
182
- Single-substrate access skills are conformant when their one substrate is
183
- provider-credential-authenticated (`lisa-sonarcloud-access`: the official SonarQube MCP
184
- authenticates headlessly from `SONARQUBE_CLI_TOKEN`, so it *is* the tier 1 substrate and
185
- needs no separate REST tier). Reserve a multi-tier ladder for vendors whose MCP is
186
- browser-OAuth or keychain-bound and therefore dead headless.
182
+ An access skill whose MCP is provider-credential-authenticated has no interactive
183
+ tier to demote — that MCP *is* the tier 1 substrate (`lisa-sonarcloud-access`: the
184
+ official SonarQube MCP authenticates headlessly from `SONARQUBE_CLI_TOKEN`).
185
+ Reserve a browser-OAuth demotion for vendors whose MCP is keychain-bound and
186
+ therefore dead headless.
187
+
188
+ That is a claim about tier ORDER and never about exclusivity. "Tier 1 needs no
189
+ demotion" does not license "there is no other substrate": where the vendor exposes
190
+ a token-authenticated Web API, it remains a sanctioned read-only fallback for a
191
+ surface on which the MCP is not wired, and a missing MCP there is a demotion rather
192
+ than a terminal tool-access failure.
@@ -33,14 +33,17 @@ unavailable" means.
33
33
  Do not blind-retry a failed or absent substrate, and never silently no-op when no
34
34
  tier is available.
35
35
 
36
- Some MCPs authenticate headlessly from an env token and need no separate REST
37
- tier — such an MCP **is** the configured-provider substrate on both developer
38
- machines and cloud routines, so a single-substrate access skill is conformant. The
39
- official SonarQube MCP is one such case (`SONARQUBE_CLI_TOKEN`
40
- [+ `SONARQUBE_CLI_ORG`/`SONARQUBE_CLI_SERVER`]): `lisa-sonarcloud-access` resolves it as a
41
- single substrate with no hand-rolled REST fallback. Reserve the multi-tier ladder
42
- for vendors whose MCP is browser-OAuth or keychain-bound and therefore dead
43
- headless.
36
+ Some MCPs authenticate headlessly from an env token such an MCP **is** the
37
+ configured-provider substrate on both developer machines and cloud routines, so it
38
+ sits at tier 1 with nothing above it to demote. The official SonarQube MCP is one
39
+ such case (`SONARQUBE_CLI_TOKEN` [+ `SONARQUBE_CLI_ORG`/`SONARQUBE_CLI_SERVER`]):
40
+ `lisa-sonarcloud-access` prefers it and falls back to the token-authenticated Sonar
41
+ Web API for reads on a surface where it is not wired. Reserve the browser-OAuth
42
+ demotion for vendors whose MCP is keychain-bound and therefore dead headless.
43
+
44
+ Being top of the ladder is not the same as being the whole ladder. An access layer
45
+ may say "prefer this substrate"; it may not say "this is the only one" while the
46
+ vendor exposes a token-authenticated API the same credential already opens.
44
47
 
45
48
  ## Access Skills
46
49
 
@@ -66,7 +69,7 @@ Source audit date: 2026-06-23. Scope: `plugins/src/**/skills/**` and
66
69
  | Notion | setup-only references | `notion-access` | Done. |
67
70
  | Linear | Multiple base queue/read/write/verify skills | Raw Linear MCP | Access layer added; consumers still need migration to `linear-access`. |
68
71
  | Jam | None in `plugins/src` at audit time | No access layer | Access layer added for host rules that include Jam triage. |
69
- | SonarCloud | Routed through `sonarcloud-access` | Official SonarQube MCP (single substrate) | Migrated to the official token-authed SonarQube MCP; bespoke REST dispatch removed. |
72
+ | SonarCloud | Routed through `sonarcloud-access` | Official SonarQube MCP preferred; token-authed Web API as the read-only fallback | Migrated to the official token-authed SonarQube MCP; the bespoke REST *dispatch* was removed, which is not the same as forbidding a Web API read. |
70
73
  | Sentry | No Sentry MCP references in `plugins/src`; CLI/REST mentions only | CLI/REST scattered in observability docs | Access layer added for future MCP-backed consumers. |
71
74
  | PostHog | No PostHog MCP references in `plugins/src`; observability docs mention PostHog detection | No access layer | Access layer added for future MCP-backed consumers. |
72
75
  | Google Play | No MCP surface; EAS submit docs only | `play-store-access` for Expo post-submit release visibility | Done for Expo stack. |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lisa-sonarcloud-access
3
- description: "Vendor-neutral access layer for SonarQube Cloud/Server. Sonar triage skills MUST delegate through this skill rather than calling the SonarQube MCP tools directly. Single substrate: the official SonarQube MCP server (mcp__sonarqube__*), authenticated headlessly from SONARQUBE_CLI_TOKEN (+ SONARQUBE_CLI_ORG for Cloud, SONARQUBE_CLI_SERVER for Server)."
3
+ description: "Vendor-neutral access layer for SonarQube Cloud/Server. Sonar triage skills MUST delegate through this skill rather than calling the SonarQube MCP tools directly. Preferred substrate: the official SonarQube MCP server (mcp__sonarqube__*), authenticated headlessly from SONARQUBE_CLI_TOKEN (+ SONARQUBE_CLI_ORG for Cloud, SONARQUBE_CLI_SERVER for Server); the Sonar Web API, authenticated with the same token, is the sanctioned fallback when the MCP is not wired on this surface."
4
4
  allowed-tools: ["Bash", "Read", "Skill"]
5
5
  ---
6
6
 
@@ -12,16 +12,26 @@ this skill owns the tool selection.
12
12
 
13
13
  ## Substrate
14
14
 
15
- There is exactly one substrate: the **official SonarQube MCP server**, provided by
15
+ The **preferred** substrate is the **official SonarQube MCP server**, provided by
16
16
  the `sonarqube` plugin and launched by the `sonar` CLI (`sonar run mcp`). It
17
17
  authenticates headlessly from environment variables — no browser, no OS keychain —
18
18
  so it is the same substrate on a developer machine and in a headless cloud routine.
19
-
20
- That makes this skill conformant with `credential-substrate-precedence` as a
21
- single-substrate access layer: this MCP **is** the configured-provider substrate
22
- (it is token-authenticated, not browser-OAuth), so there is no interactive tier to
23
- demote and no second REST tier to add. Identity-match against the configured org
24
- remains mandatory, as on every substrate.
19
+ Prefer it because it owns the tool selection this skill exists to centralise.
20
+
21
+ It is not the only sanctioned substrate. The **Sonar Web API**, authenticated with
22
+ the same token, is a sanctioned fallback for read-only operations when the MCP is
23
+ not wired on this surface. An earlier revision of this file said otherwise — that
24
+ the MCP was "the only sanctioned substrate" and a missing MCP was "not a reason to
25
+ curl the Web API" — and that was wrong on its face: `.github/workflows/quality.yml`
26
+ already reads `api/ce/task` with a token to turn an opaque failed scan into an
27
+ operator-readable one. A rule the shipping repository contradicts is documentation,
28
+ not a constraint.
29
+
30
+ The distinction that does hold: a token-authenticated MCP **is** the
31
+ configured-provider substrate under `credential-substrate-precedence` (it is not
32
+ browser-OAuth), so there is no interactive tier to demote here. That is a statement
33
+ about tier ORDER, not about exclusivity. Identity-match against the configured org
34
+ remains mandatory on either substrate.
25
35
 
26
36
  - `SONARQUBE_CLI_TOKEN` — required (Sonar user/analysis token).
27
37
  - `SONARQUBE_CLI_ORG` — required for SonarQube Cloud.
@@ -89,16 +99,21 @@ being on PATH is not access. Probe by searching projects (the `projects` toolset
89
99
  always enabled):
90
100
 
91
101
  - If a `mcp__sonarqube__*` project-search tool returns, access is proven.
92
- - If no `mcp__sonarqube__*` tool is present, or the call fails authentication, fail
93
- loudly and do not improvise a substitute:
102
+ - If no `mcp__sonarqube__*` tool is present on this surface, that is a **demotion,
103
+ not a blocker**. Fall back to the Sonar Web API with the same resolved token for
104
+ the read-only operation at hand.
105
+ - Only when neither substrate can prove access — no MCP tool *and* no usable token
106
+ — is this a terminal tool-access-gate failure. Say so, and do not improvise a
107
+ third route:
94
108
 
95
109
  ```text
96
110
  Error: no SonarQube access. Run /lisa:setup:sonar (or `sonar integrate <agent>`), and set SONARQUBE_CLI_TOKEN (+ SONARQUBE_CLI_ORG for Cloud / SONARQUBE_CLI_SERVER for Server).
97
111
  ```
98
112
 
99
- There is no hand-rolled REST fallback: the official MCP is headless-capable via the
100
- token env vars, so it is the only sanctioned substrate. A missing MCP is a
101
- tool-access-gate failure to surface, not a reason to curl the Web API.
113
+ The distinction matters because the two cases have different remedies. An absent
114
+ MCP on a surface that holds a valid credential is a wiring gap the agent can work
115
+ around; treating it as terminal manufactures a tool-access failure on a surface
116
+ that has access.
102
117
 
103
118
  ## Operation → toolset map
104
119
 
@@ -127,14 +142,17 @@ tool accepts them.
127
142
  Every operation in the map above is **read-only** — quality, coverage, and
128
143
  security data. So the `credential-substrate-precedence` guarded fallback for
129
144
  mutating operations (write, read back, assert the tenant from the response, roll
130
- back on mismatch) is not engaged here; with one substrate there is nothing to
131
- fall back to in any case. A future operation that mutates Sonar state marking
145
+ back on mismatch) is not engaged here, because nothing in the map writes. The
146
+ Web API fallback is sanctioned for READS only; it does not open a mutation path.
147
+ A future operation that mutates Sonar state — marking
132
148
  a hotspot safe, changing an issue's status — is a write and MUST reconcile by
133
149
  read-back before any retry.
134
150
 
135
151
  ## Invariants
136
152
 
137
- - The official SonarQube MCP is the only substrate; there is no REST fallback.
153
+ - The official SonarQube MCP is the preferred substrate, not the only one. The
154
+ Sonar Web API with the same token is a sanctioned read-only fallback, and a
155
+ missing MCP is a demotion rather than a terminal failure.
138
156
  - `SONARQUBE_CLI_*` values are resolved through `lisa-secrets-access` and
139
157
  exported in-process, with the bare environment variables as the documented
140
158
  fallback. Never write them to a dotfile or a `.env` on a local surface.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "3.51.3",
3
+ "version": "3.51.4",
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-sonarcloud-access
3
- description: "Vendor-neutral access layer for SonarQube Cloud/Server. Sonar triage skills MUST delegate through this skill rather than calling the SonarQube MCP tools directly. Single substrate: the official SonarQube MCP server (mcp__sonarqube__*), authenticated headlessly from SONARQUBE_CLI_TOKEN (+ SONARQUBE_CLI_ORG for Cloud, SONARQUBE_CLI_SERVER for Server)."
3
+ description: "Vendor-neutral access layer for SonarQube Cloud/Server. Sonar triage skills MUST delegate through this skill rather than calling the SonarQube MCP tools directly. Preferred substrate: the official SonarQube MCP server (mcp__sonarqube__*), authenticated headlessly from SONARQUBE_CLI_TOKEN (+ SONARQUBE_CLI_ORG for Cloud, SONARQUBE_CLI_SERVER for Server); the Sonar Web API, authenticated with the same token, is the sanctioned fallback when the MCP is not wired on this surface."
4
4
  allowed-tools: ["Bash", "Read", "Skill"]
5
5
  ---
6
6
 
@@ -12,16 +12,26 @@ this skill owns the tool selection.
12
12
 
13
13
  ## Substrate
14
14
 
15
- There is exactly one substrate: the **official SonarQube MCP server**, provided by
15
+ The **preferred** substrate is the **official SonarQube MCP server**, provided by
16
16
  the `sonarqube` plugin and launched by the `sonar` CLI (`sonar run mcp`). It
17
17
  authenticates headlessly from environment variables — no browser, no OS keychain —
18
18
  so it is the same substrate on a developer machine and in a headless cloud routine.
19
-
20
- That makes this skill conformant with `credential-substrate-precedence` as a
21
- single-substrate access layer: this MCP **is** the configured-provider substrate
22
- (it is token-authenticated, not browser-OAuth), so there is no interactive tier to
23
- demote and no second REST tier to add. Identity-match against the configured org
24
- remains mandatory, as on every substrate.
19
+ Prefer it because it owns the tool selection this skill exists to centralise.
20
+
21
+ It is not the only sanctioned substrate. The **Sonar Web API**, authenticated with
22
+ the same token, is a sanctioned fallback for read-only operations when the MCP is
23
+ not wired on this surface. An earlier revision of this file said otherwise — that
24
+ the MCP was "the only sanctioned substrate" and a missing MCP was "not a reason to
25
+ curl the Web API" — and that was wrong on its face: `.github/workflows/quality.yml`
26
+ already reads `api/ce/task` with a token to turn an opaque failed scan into an
27
+ operator-readable one. A rule the shipping repository contradicts is documentation,
28
+ not a constraint.
29
+
30
+ The distinction that does hold: a token-authenticated MCP **is** the
31
+ configured-provider substrate under `credential-substrate-precedence` (it is not
32
+ browser-OAuth), so there is no interactive tier to demote here. That is a statement
33
+ about tier ORDER, not about exclusivity. Identity-match against the configured org
34
+ remains mandatory on either substrate.
25
35
 
26
36
  - `SONARQUBE_CLI_TOKEN` — required (Sonar user/analysis token).
27
37
  - `SONARQUBE_CLI_ORG` — required for SonarQube Cloud.
@@ -89,16 +99,21 @@ being on PATH is not access. Probe by searching projects (the `projects` toolset
89
99
  always enabled):
90
100
 
91
101
  - If a `mcp__sonarqube__*` project-search tool returns, access is proven.
92
- - If no `mcp__sonarqube__*` tool is present, or the call fails authentication, fail
93
- loudly and do not improvise a substitute:
102
+ - If no `mcp__sonarqube__*` tool is present on this surface, that is a **demotion,
103
+ not a blocker**. Fall back to the Sonar Web API with the same resolved token for
104
+ the read-only operation at hand.
105
+ - Only when neither substrate can prove access — no MCP tool *and* no usable token
106
+ — is this a terminal tool-access-gate failure. Say so, and do not improvise a
107
+ third route:
94
108
 
95
109
  ```text
96
110
  Error: no SonarQube access. Run /lisa:setup:sonar (or `sonar integrate <agent>`), and set SONARQUBE_CLI_TOKEN (+ SONARQUBE_CLI_ORG for Cloud / SONARQUBE_CLI_SERVER for Server).
97
111
  ```
98
112
 
99
- There is no hand-rolled REST fallback: the official MCP is headless-capable via the
100
- token env vars, so it is the only sanctioned substrate. A missing MCP is a
101
- tool-access-gate failure to surface, not a reason to curl the Web API.
113
+ The distinction matters because the two cases have different remedies. An absent
114
+ MCP on a surface that holds a valid credential is a wiring gap the agent can work
115
+ around; treating it as terminal manufactures a tool-access failure on a surface
116
+ that has access.
102
117
 
103
118
  ## Operation → toolset map
104
119
 
@@ -127,14 +142,17 @@ tool accepts them.
127
142
  Every operation in the map above is **read-only** — quality, coverage, and
128
143
  security data. So the `credential-substrate-precedence` guarded fallback for
129
144
  mutating operations (write, read back, assert the tenant from the response, roll
130
- back on mismatch) is not engaged here; with one substrate there is nothing to
131
- fall back to in any case. A future operation that mutates Sonar state marking
145
+ back on mismatch) is not engaged here, because nothing in the map writes. The
146
+ Web API fallback is sanctioned for READS only; it does not open a mutation path.
147
+ A future operation that mutates Sonar state — marking
132
148
  a hotspot safe, changing an issue's status — is a write and MUST reconcile by
133
149
  read-back before any retry.
134
150
 
135
151
  ## Invariants
136
152
 
137
- - The official SonarQube MCP is the only substrate; there is no REST fallback.
153
+ - The official SonarQube MCP is the preferred substrate, not the only one. The
154
+ Sonar Web API with the same token is a sanctioned read-only fallback, and a
155
+ missing MCP is a demotion rather than a terminal failure.
138
156
  - `SONARQUBE_CLI_*` values are resolved through `lisa-secrets-access` and
139
157
  exported in-process, with the bare environment variables as the documented
140
158
  fallback. Never write them to a dotfile or a `.env` on a local surface.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "3.51.3",
3
+ "version": "3.51.4",
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": "3.51.3",
3
+ "version": "3.51.4",
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": "3.51.3",
3
+ "version": "3.51.4",
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": "3.51.3",
3
+ "version": "3.51.4",
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": "3.51.3",
3
+ "version": "3.51.4",
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": "3.51.3",
3
+ "version": "3.51.4",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -179,8 +179,14 @@ the chokepoint cannot answer for is a setup gap to fix, not a store to add.
179
179
  4. Keep MCP adapters and name the operations for which MCP is the only substrate.
180
180
  5. Make the terminal failure name the exact credential and remediation command.
181
181
 
182
- Single-substrate access skills are conformant when their one substrate is
183
- provider-credential-authenticated (`lisa-sonarcloud-access`: the official SonarQube MCP
184
- authenticates headlessly from `SONARQUBE_CLI_TOKEN`, so it *is* the tier 1 substrate and
185
- needs no separate REST tier). Reserve a multi-tier ladder for vendors whose MCP is
186
- browser-OAuth or keychain-bound and therefore dead headless.
182
+ An access skill whose MCP is provider-credential-authenticated has no interactive
183
+ tier to demote — that MCP *is* the tier 1 substrate (`lisa-sonarcloud-access`: the
184
+ official SonarQube MCP authenticates headlessly from `SONARQUBE_CLI_TOKEN`).
185
+ Reserve a browser-OAuth demotion for vendors whose MCP is keychain-bound and
186
+ therefore dead headless.
187
+
188
+ That is a claim about tier ORDER and never about exclusivity. "Tier 1 needs no
189
+ demotion" does not license "there is no other substrate": where the vendor exposes
190
+ a token-authenticated Web API, it remains a sanctioned read-only fallback for a
191
+ surface on which the MCP is not wired, and a missing MCP there is a demotion rather
192
+ than a terminal tool-access failure.
@@ -33,14 +33,17 @@ unavailable" means.
33
33
  Do not blind-retry a failed or absent substrate, and never silently no-op when no
34
34
  tier is available.
35
35
 
36
- Some MCPs authenticate headlessly from an env token and need no separate REST
37
- tier — such an MCP **is** the configured-provider substrate on both developer
38
- machines and cloud routines, so a single-substrate access skill is conformant. The
39
- official SonarQube MCP is one such case (`SONARQUBE_CLI_TOKEN`
40
- [+ `SONARQUBE_CLI_ORG`/`SONARQUBE_CLI_SERVER`]): `lisa-sonarcloud-access` resolves it as a
41
- single substrate with no hand-rolled REST fallback. Reserve the multi-tier ladder
42
- for vendors whose MCP is browser-OAuth or keychain-bound and therefore dead
43
- headless.
36
+ Some MCPs authenticate headlessly from an env token such an MCP **is** the
37
+ configured-provider substrate on both developer machines and cloud routines, so it
38
+ sits at tier 1 with nothing above it to demote. The official SonarQube MCP is one
39
+ such case (`SONARQUBE_CLI_TOKEN` [+ `SONARQUBE_CLI_ORG`/`SONARQUBE_CLI_SERVER`]):
40
+ `lisa-sonarcloud-access` prefers it and falls back to the token-authenticated Sonar
41
+ Web API for reads on a surface where it is not wired. Reserve the browser-OAuth
42
+ demotion for vendors whose MCP is keychain-bound and therefore dead headless.
43
+
44
+ Being top of the ladder is not the same as being the whole ladder. An access layer
45
+ may say "prefer this substrate"; it may not say "this is the only one" while the
46
+ vendor exposes a token-authenticated API the same credential already opens.
44
47
 
45
48
  ## Access Skills
46
49
 
@@ -66,7 +69,7 @@ Source audit date: 2026-06-23. Scope: `plugins/src/**/skills/**` and
66
69
  | Notion | setup-only references | `notion-access` | Done. |
67
70
  | Linear | Multiple base queue/read/write/verify skills | Raw Linear MCP | Access layer added; consumers still need migration to `linear-access`. |
68
71
  | Jam | None in `plugins/src` at audit time | No access layer | Access layer added for host rules that include Jam triage. |
69
- | SonarCloud | Routed through `sonarcloud-access` | Official SonarQube MCP (single substrate) | Migrated to the official token-authed SonarQube MCP; bespoke REST dispatch removed. |
72
+ | SonarCloud | Routed through `sonarcloud-access` | Official SonarQube MCP preferred; token-authed Web API as the read-only fallback | Migrated to the official token-authed SonarQube MCP; the bespoke REST *dispatch* was removed, which is not the same as forbidding a Web API read. |
70
73
  | Sentry | No Sentry MCP references in `plugins/src`; CLI/REST mentions only | CLI/REST scattered in observability docs | Access layer added for future MCP-backed consumers. |
71
74
  | PostHog | No PostHog MCP references in `plugins/src`; observability docs mention PostHog detection | No access layer | Access layer added for future MCP-backed consumers. |
72
75
  | Google Play | No MCP surface; EAS submit docs only | `play-store-access` for Expo post-submit release visibility | Done for Expo stack. |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lisa-sonarcloud-access
3
- description: "Vendor-neutral access layer for SonarQube Cloud/Server. Sonar triage skills MUST delegate through this skill rather than calling the SonarQube MCP tools directly. Single substrate: the official SonarQube MCP server (mcp__sonarqube__*), authenticated headlessly from SONARQUBE_CLI_TOKEN (+ SONARQUBE_CLI_ORG for Cloud, SONARQUBE_CLI_SERVER for Server)."
3
+ description: "Vendor-neutral access layer for SonarQube Cloud/Server. Sonar triage skills MUST delegate through this skill rather than calling the SonarQube MCP tools directly. Preferred substrate: the official SonarQube MCP server (mcp__sonarqube__*), authenticated headlessly from SONARQUBE_CLI_TOKEN (+ SONARQUBE_CLI_ORG for Cloud, SONARQUBE_CLI_SERVER for Server); the Sonar Web API, authenticated with the same token, is the sanctioned fallback when the MCP is not wired on this surface."
4
4
  allowed-tools: ["Bash", "Read", "Skill"]
5
5
  ---
6
6
 
@@ -12,16 +12,26 @@ this skill owns the tool selection.
12
12
 
13
13
  ## Substrate
14
14
 
15
- There is exactly one substrate: the **official SonarQube MCP server**, provided by
15
+ The **preferred** substrate is the **official SonarQube MCP server**, provided by
16
16
  the `sonarqube` plugin and launched by the `sonar` CLI (`sonar run mcp`). It
17
17
  authenticates headlessly from environment variables — no browser, no OS keychain —
18
18
  so it is the same substrate on a developer machine and in a headless cloud routine.
19
-
20
- That makes this skill conformant with `credential-substrate-precedence` as a
21
- single-substrate access layer: this MCP **is** the configured-provider substrate
22
- (it is token-authenticated, not browser-OAuth), so there is no interactive tier to
23
- demote and no second REST tier to add. Identity-match against the configured org
24
- remains mandatory, as on every substrate.
19
+ Prefer it because it owns the tool selection this skill exists to centralise.
20
+
21
+ It is not the only sanctioned substrate. The **Sonar Web API**, authenticated with
22
+ the same token, is a sanctioned fallback for read-only operations when the MCP is
23
+ not wired on this surface. An earlier revision of this file said otherwise — that
24
+ the MCP was "the only sanctioned substrate" and a missing MCP was "not a reason to
25
+ curl the Web API" — and that was wrong on its face: `.github/workflows/quality.yml`
26
+ already reads `api/ce/task` with a token to turn an opaque failed scan into an
27
+ operator-readable one. A rule the shipping repository contradicts is documentation,
28
+ not a constraint.
29
+
30
+ The distinction that does hold: a token-authenticated MCP **is** the
31
+ configured-provider substrate under `credential-substrate-precedence` (it is not
32
+ browser-OAuth), so there is no interactive tier to demote here. That is a statement
33
+ about tier ORDER, not about exclusivity. Identity-match against the configured org
34
+ remains mandatory on either substrate.
25
35
 
26
36
  - `SONARQUBE_CLI_TOKEN` — required (Sonar user/analysis token).
27
37
  - `SONARQUBE_CLI_ORG` — required for SonarQube Cloud.
@@ -89,16 +99,21 @@ being on PATH is not access. Probe by searching projects (the `projects` toolset
89
99
  always enabled):
90
100
 
91
101
  - If a `mcp__sonarqube__*` project-search tool returns, access is proven.
92
- - If no `mcp__sonarqube__*` tool is present, or the call fails authentication, fail
93
- loudly and do not improvise a substitute:
102
+ - If no `mcp__sonarqube__*` tool is present on this surface, that is a **demotion,
103
+ not a blocker**. Fall back to the Sonar Web API with the same resolved token for
104
+ the read-only operation at hand.
105
+ - Only when neither substrate can prove access — no MCP tool *and* no usable token
106
+ — is this a terminal tool-access-gate failure. Say so, and do not improvise a
107
+ third route:
94
108
 
95
109
  ```text
96
110
  Error: no SonarQube access. Run /lisa:setup:sonar (or `sonar integrate <agent>`), and set SONARQUBE_CLI_TOKEN (+ SONARQUBE_CLI_ORG for Cloud / SONARQUBE_CLI_SERVER for Server).
97
111
  ```
98
112
 
99
- There is no hand-rolled REST fallback: the official MCP is headless-capable via the
100
- token env vars, so it is the only sanctioned substrate. A missing MCP is a
101
- tool-access-gate failure to surface, not a reason to curl the Web API.
113
+ The distinction matters because the two cases have different remedies. An absent
114
+ MCP on a surface that holds a valid credential is a wiring gap the agent can work
115
+ around; treating it as terminal manufactures a tool-access failure on a surface
116
+ that has access.
102
117
 
103
118
  ## Operation → toolset map
104
119
 
@@ -127,14 +142,17 @@ tool accepts them.
127
142
  Every operation in the map above is **read-only** — quality, coverage, and
128
143
  security data. So the `credential-substrate-precedence` guarded fallback for
129
144
  mutating operations (write, read back, assert the tenant from the response, roll
130
- back on mismatch) is not engaged here; with one substrate there is nothing to
131
- fall back to in any case. A future operation that mutates Sonar state marking
145
+ back on mismatch) is not engaged here, because nothing in the map writes. The
146
+ Web API fallback is sanctioned for READS only; it does not open a mutation path.
147
+ A future operation that mutates Sonar state — marking
132
148
  a hotspot safe, changing an issue's status — is a write and MUST reconcile by
133
149
  read-back before any retry.
134
150
 
135
151
  ## Invariants
136
152
 
137
- - The official SonarQube MCP is the only substrate; there is no REST fallback.
153
+ - The official SonarQube MCP is the preferred substrate, not the only one. The
154
+ Sonar Web API with the same token is a sanctioned read-only fallback, and a
155
+ missing MCP is a demotion rather than a terminal failure.
138
156
  - `SONARQUBE_CLI_*` values are resolved through `lisa-secrets-access` and
139
157
  exported in-process, with the bare environment variables as the documented
140
158
  fallback. Never write them to a dotfile or a `.env` on a local surface.