@codyswann/lisa 4.55.3 → 4.55.5

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 (134) hide show
  1. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  2. package/dist/core/lisa-owned-hash-ledger.js +6 -0
  3. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  4. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  5. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  6. package/dist/core/upstream-evidence-manifest.js +17 -15
  7. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  8. package/expo/copy-overwrite/scripts/bdd/validate.mjs +84 -8
  9. package/expo/copy-overwrite/scripts/check-bdd-coverage.mjs +1 -1
  10. package/package.json +4 -4
  11. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  12. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  13. package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +22 -7
  14. package/plugins/lisa/.codex-plugin/skills/lisa-github-write-issue/SKILL.md +15 -1
  15. package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +21 -6
  16. package/plugins/lisa/.codex-plugin/skills/lisa-jira-write-ticket/SKILL.md +15 -1
  17. package/plugins/lisa/.codex-plugin/skills/lisa-linear-access/SKILL.md +12 -2
  18. package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +20 -6
  19. package/plugins/lisa/.codex-plugin/skills/lisa-linear-write-issue/SKILL.md +15 -1
  20. package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +21 -7
  21. package/plugins/lisa/.codex-plugin/skills/lisa-track/SKILL.md +16 -2
  22. package/plugins/lisa/.codex-plugin/skills/lisa-tracker-build-intake/SKILL.md +15 -1
  23. package/plugins/lisa/rules/reference/ready-role-filing.md +36 -0
  24. package/plugins/lisa/scripts/intake-blocker-reprobe.mjs +85 -17
  25. package/plugins/lisa/scripts/qa-signal-lifecycle.mjs +5 -2
  26. package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +22 -7
  27. package/plugins/lisa/skills/lisa-github-write-issue/SKILL.md +15 -1
  28. package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +21 -6
  29. package/plugins/lisa/skills/lisa-jira-write-ticket/SKILL.md +15 -1
  30. package/plugins/lisa/skills/lisa-linear-access/SKILL.md +12 -2
  31. package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +20 -6
  32. package/plugins/lisa/skills/lisa-linear-write-issue/SKILL.md +15 -1
  33. package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +21 -7
  34. package/plugins/lisa/skills/lisa-track/SKILL.md +16 -2
  35. package/plugins/lisa/skills/lisa-tracker-build-intake/SKILL.md +15 -1
  36. package/plugins/lisa-agy/plugin.json +1 -1
  37. package/plugins/lisa-agy/scripts/intake-blocker-reprobe.mjs +85 -17
  38. package/plugins/lisa-agy/scripts/qa-signal-lifecycle.mjs +5 -2
  39. package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +22 -7
  40. package/plugins/lisa-agy/skills/lisa-github-write-issue/SKILL.md +15 -1
  41. package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +21 -6
  42. package/plugins/lisa-agy/skills/lisa-jira-write-ticket/SKILL.md +15 -1
  43. package/plugins/lisa-agy/skills/lisa-linear-access/SKILL.md +12 -2
  44. package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +20 -6
  45. package/plugins/lisa-agy/skills/lisa-linear-write-issue/SKILL.md +15 -1
  46. package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +21 -7
  47. package/plugins/lisa-agy/skills/lisa-track/SKILL.md +16 -2
  48. package/plugins/lisa-agy/skills/lisa-tracker-build-intake/SKILL.md +15 -1
  49. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  51. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  52. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-copilot/rules/reference/ready-role-filing.md +36 -0
  56. package/plugins/lisa-copilot/scripts/intake-blocker-reprobe.mjs +85 -17
  57. package/plugins/lisa-copilot/scripts/qa-signal-lifecycle.mjs +5 -2
  58. package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +22 -7
  59. package/plugins/lisa-copilot/skills/lisa-github-write-issue/SKILL.md +15 -1
  60. package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +21 -6
  61. package/plugins/lisa-copilot/skills/lisa-jira-write-ticket/SKILL.md +15 -1
  62. package/plugins/lisa-copilot/skills/lisa-linear-access/SKILL.md +12 -2
  63. package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +20 -6
  64. package/plugins/lisa-copilot/skills/lisa-linear-write-issue/SKILL.md +15 -1
  65. package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +21 -7
  66. package/plugins/lisa-copilot/skills/lisa-track/SKILL.md +16 -2
  67. package/plugins/lisa-copilot/skills/lisa-tracker-build-intake/SKILL.md +15 -1
  68. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-cursor/rules/ready-role-filing-reference.mdc +36 -0
  70. package/plugins/lisa-cursor/scripts/intake-blocker-reprobe.mjs +85 -17
  71. package/plugins/lisa-cursor/scripts/qa-signal-lifecycle.mjs +5 -2
  72. package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +22 -7
  73. package/plugins/lisa-cursor/skills/lisa-github-write-issue/SKILL.md +15 -1
  74. package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +21 -6
  75. package/plugins/lisa-cursor/skills/lisa-jira-write-ticket/SKILL.md +15 -1
  76. package/plugins/lisa-cursor/skills/lisa-linear-access/SKILL.md +12 -2
  77. package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +20 -6
  78. package/plugins/lisa-cursor/skills/lisa-linear-write-issue/SKILL.md +15 -1
  79. package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +21 -7
  80. package/plugins/lisa-cursor/skills/lisa-track/SKILL.md +16 -2
  81. package/plugins/lisa-cursor/skills/lisa-tracker-build-intake/SKILL.md +15 -1
  82. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  84. package/plugins/lisa-expo-agy/plugin.json +1 -1
  85. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  87. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  88. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  89. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  90. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  91. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  92. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  93. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  94. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  95. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  96. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  97. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  98. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  99. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  100. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  101. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  102. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  103. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  104. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  105. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  106. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  107. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  108. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  109. package/plugins/lisa-rails-agy/plugin.json +1 -1
  110. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  111. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  112. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  113. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  114. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  115. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  116. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  117. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  118. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  119. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  120. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  121. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  122. package/plugins/src/base/rules/reference/ready-role-filing.md +36 -0
  123. package/plugins/src/base/scripts/intake-blocker-reprobe.mjs +85 -17
  124. package/plugins/src/base/scripts/qa-signal-lifecycle.mjs +5 -2
  125. package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +22 -7
  126. package/plugins/src/base/skills/lisa-github-write-issue/SKILL.md +15 -1
  127. package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +21 -6
  128. package/plugins/src/base/skills/lisa-jira-write-ticket/SKILL.md +15 -1
  129. package/plugins/src/base/skills/lisa-linear-access/SKILL.md +12 -2
  130. package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +20 -6
  131. package/plugins/src/base/skills/lisa-linear-write-issue/SKILL.md +15 -1
  132. package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +21 -7
  133. package/plugins/src/base/skills/lisa-track/SKILL.md +16 -2
  134. package/plugins/src/base/skills/lisa-tracker-build-intake/SKILL.md +15 -1
@@ -239,8 +239,8 @@ export const VOID_PREDICATES = Object.freeze({
239
239
  "certified-role-reached": ({ role, resolvedRoles }) =>
240
240
  normalize(role) !== "" &&
241
241
  resolvedRoles.some(name => normalize(name) === normalize(role)),
242
- "human-gate-release-recorded": ({ body, comments }) =>
243
- humanGateDischarged({ body, comments }),
242
+ "human-gate-release-recorded": ({ body, comments, trustedHumanActorIds }) =>
243
+ humanGateDischarged({ body, comments, trustedHumanActorIds }),
244
244
  });
245
245
 
246
246
  /**
@@ -331,6 +331,7 @@ const labelNames = labels =>
331
331
  * @param {string} [options.signal] a key of {@link SIGNALS}
332
332
  * @param {readonly unknown[]} [options.labels] the item's labels
333
333
  * @param {readonly unknown[]} [options.comments] comment bodies, oldest first
334
+ * @param {readonly unknown[]} [options.trustedHumanActorIds] explicitly trusted human author identities
334
335
  * @param {unknown} [options.body] the item's description, for body-marker rows
335
336
  * @param {string} [options.role] the item's current lifecycle role name
336
337
  * @param {string} options.vendor `jira` | `linear` | `github`
@@ -341,6 +342,7 @@ export const evaluateSignal = ({
341
342
  signal = QA_FAILURE_SIGNAL,
342
343
  labels,
343
344
  comments,
345
+ trustedHumanActorIds,
344
346
  body,
345
347
  role = "",
346
348
  vendor,
@@ -380,6 +382,7 @@ export const evaluateSignal = ({
380
382
  role,
381
383
  body,
382
384
  comments,
385
+ trustedHumanActorIds,
383
386
  resolvedRoles: voidingRoles({ vendor, config }),
384
387
  };
385
388
  const unchecked = declared.voidConditions.filter(
@@ -6,6 +6,20 @@ allowed-tools: ["Skill", "Bash"]
6
6
 
7
7
  # GitHub Build Intake: $ARGUMENTS
8
8
 
9
+ ## Human-gate release authorization
10
+
11
+ A release requires a trusted human author, not just matching comment text. Follow
12
+ `ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
13
+ author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
14
+ or existing human-authored trusted project policy, and pass it with structured `comments` to every
15
+ hold classifier, reconciliation, normalization and release planner. Never derive trust from the
16
+ comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
17
+ Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
18
+ cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
19
+ replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
20
+ continue through the existing path and never override an independently declared caller hold.
21
+
22
+
9
23
  `$ARGUMENTS` is one of:
10
24
 
11
25
  1. A GitHub `org/repo` token (e.g., `acme/frontend-v2`).
@@ -216,8 +230,8 @@ A blocker is a **claim with a timestamp, not a fact** — it goes stale the mome
216
230
  true, and nothing re-read one before this phase. For each `$BLOCKED` candidate:
217
231
 
218
232
  1. **Read release comments before applying the human gate.** Pass all item comments, labels,
219
- body and configured `humanNeededLabel` to `classifyReadyCandidate(...)`. For a discharged hold,
220
- call `planHumanGateRelease({ labels, body, comments, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
233
+ body, `trustedHumanActorIds` and configured `humanNeededLabel` to `classifyReadyCandidate(...)`. For a discharged hold,
234
+ call `planHumanGateRelease({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
221
235
  and retain its plan. Apply human-marker cleanup only as planned; defer any ready-role restoration
222
236
  until steps 2–5 have cleared the remaining blockers (map the role to the vendor's state or label).
223
237
  A still-active hold is never auto-selected, whatever any probe says. An absent or unreadable
@@ -227,8 +241,9 @@ true, and nothing re-read one before this phase. For each `$BLOCKED` candidate:
227
241
  2. **Extract the stated discharge condition**, then **probe it**. Machine-testable conditions — a
228
242
  version on trunk, a published package, a CI run history, an advisory's patched status — rot
229
243
  fastest and are cheapest to check. A human decision is not machine-testable; leave it.
230
- 3. **Classify with `classifyPreWorkCandidate(...)`** from `scripts/intake-blocker-reprobe.mjs`. A
231
- discharge with no recorded evidence is not a discharge, and neither is a candidate nothing
244
+ 3. **Classify with `classifyPreWorkCandidate(...)`** from `scripts/intake-blocker-reprobe.mjs`.
245
+ Include the structured `comments` and `trustedHumanActorIds` from step 1.
246
+ A discharge with no recorded evidence is not a discharge, and neither is a candidate nothing
232
247
  probed this cycle — the helper refuses both.
233
248
  4. **Record the result on the issue either way** via `formatReprobeNote(...)` as a comment, so the
234
249
  next cycle reads the answer rather than re-deriving it. Keep it idempotent.
@@ -323,7 +338,7 @@ other gate's verdict — however conclusive — may promote an item a person par
323
338
  drift, and a drifted gate fails *silently*, by quietly ceasing to match. Do **not** re-implement
324
339
  the test here, and do **not** key it on `reason=`: markers in the wild carry no `reason=` key at
325
340
  all and sit anywhere in the body, so a structured parse would miss them while appearing to work
326
- on every item that happens to have one. **Pass the item's `comments` alongside its labels and
341
+ on every item that happens to have one. **Pass the item's structured `comments` and `trustedHumanActorIds` alongside its labels and
327
342
  body.** A hold is ended by a release recorded in a comment, so a reader handed no comments cannot
328
343
  see the discharge — it goes on holding an item whose question was answered weeks ago, which is
329
344
  the defect this gate carried from the day it was written (CodySwannGT/lisa#3852). Omitting them
@@ -334,7 +349,7 @@ other gate's verdict — however conclusive — may promote an item a person par
334
349
  and re-rejected every cycle forever and seen by nothing — `lisa-repair-intake` sweeps items that
335
350
  are **not** in the ready role and excludes gated ones outright, so a ready-and-gated item falls
336
351
  outside its filter twice over. Call
337
- `planHumanGateReconciliation({ labels, body, humanNeededLabel, readyLabel, alreadyNotified })`
352
+ `planHumanGateReconciliation({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, alreadyNotified })`
338
353
  and apply exactly the actions it returns: remove `$READY`, add the configured human-needed
339
354
  marker, and post `formatHumanGateNote()` once. The planner is idempotent by state, so an item
340
355
  already out of the lane and already marked yields no second mutation and no second comment. This
@@ -344,7 +359,7 @@ other gate's verdict — however conclusive — may promote an item a person par
344
359
  This ready-lane candidate can retain a historical body marker and a human-needed label.
345
360
  This step reconciles only candidates still in the ready lane; released holds outside it are
346
361
  recovered by `lisa-repair-intake` step 2b (or Phase 2.5 when included in this cycle). Call
347
- `planHumanGateRelease({ labels, body, comments, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
362
+ `planHumanGateRelease({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
348
363
  and apply exactly the actions it returns: remove the configured human-needed marker, add the
349
364
  configured ready role back, and post `formatHumanGateReleaseNote()` once. It is the exact inverse
350
365
  of step 3's planner and it refuses in both directions — an item still held plans nothing, and an
@@ -6,6 +6,20 @@ allowed-tools: ["Bash", "Skill", "Read"]
6
6
 
7
7
  # Write GitHub Issue: $ARGUMENTS
8
8
 
9
+ ## Human-gate release authorization
10
+
11
+ A release requires a trusted human author, not just matching comment text. Follow
12
+ `ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
13
+ author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
14
+ or existing human-authored trusted project policy, and pass it with structured `comments` to every
15
+ hold classifier, reconciliation, normalization and release planner. Never derive trust from the
16
+ comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
17
+ Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
18
+ cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
19
+ replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
20
+ continue through the existing path and never override an independently declared caller hold.
21
+
22
+
9
23
  Create or update a GitHub Issue with all required relationships, metadata, and quality gates. Every section below is mandatory. Thin issues are rejected.
10
24
 
11
25
  This skill is the GitHub counterpart of `lisa-jira-write-ticket`. The two skills share the same gates, description structure, acceptance-criteria format, and verification flow. The data-model translation is documented under "GitHub Issues data model" below — keep that table in sync with `lisa-github-validate-issue` so what one skill writes the other accepts.
@@ -323,7 +337,7 @@ If the label does not exist in the tracker, create it, or record that it could n
323
337
  proceed — the marker still holds. Never file the label *instead of* the marker.
324
338
 
325
339
  **Write a `reason=` the release can name.** The hold's reason is not decoration: a hold ends when a
326
- `[lisa-human-gate-release]` comment repeating that same `reason=` is recorded on the item, and the
340
+ `[lisa-human-gate-release]` comment repeating that same `reason=` is recorded on the item by an authorized human, and the
327
341
  next intake sweep then takes the marker label off and puts the item back in the build-ready role on
328
342
  its own. Matching is per-reason so that a hold declared *after* an earlier release is not born
329
343
  discharged. A keyless hold is legal and is discharged by a keyless release; a hold whose reason is a
@@ -6,6 +6,20 @@ allowed-tools: ["Skill", "Bash"]
6
6
 
7
7
  # JIRA Build Intake: $ARGUMENTS
8
8
 
9
+ ## Human-gate release authorization
10
+
11
+ A release requires a trusted human author, not just matching comment text. Follow
12
+ `ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
13
+ author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
14
+ or existing human-authored trusted project policy, and pass it with structured `comments` to every
15
+ hold classifier, reconciliation, normalization and release planner. Never derive trust from the
16
+ comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
17
+ Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
18
+ cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
19
+ replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
20
+ continue through the existing path and never override an independently declared caller hold.
21
+
22
+
9
23
  All Atlassian operations in this skill go through `lisa-atlassian-access`. Do not call MCP tools or `acli` directly.
10
24
 
11
25
  `$ARGUMENTS` is one of:
@@ -190,8 +204,8 @@ A blocker is a **claim with a timestamp, not a fact** — it goes stale the mome
190
204
  true, and nothing re-read one before this phase. For each pre-work candidate outside `$READY`:
191
205
 
192
206
  1. **Read release comments before applying the human gate.** Pass all item comments, labels,
193
- body and configured `humanNeededLabel` to `classifyReadyCandidate(...)`. For a discharged hold,
194
- call `planHumanGateRelease({ labels, body, comments, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
207
+ body, `trustedHumanActorIds` and configured `humanNeededLabel` to `classifyReadyCandidate(...)`. For a discharged hold,
208
+ call `planHumanGateRelease({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
195
209
  and retain its plan. Apply human-marker cleanup only as planned; defer any ready-role restoration
196
210
  until steps 2–5 have cleared the remaining blockers (map the role to the vendor's state or label).
197
211
  A still-active hold is never auto-selected, whatever any probe says. An absent or unreadable
@@ -202,7 +216,8 @@ true, and nothing re-read one before this phase. For each pre-work candidate out
202
216
  version on trunk, a published package, a CI run history, an advisory's patched status — rot
203
217
  fastest and are cheapest to check. A human decision is not machine-testable; leave it.
204
218
  3. **Classify with `classifyPreWorkCandidate(...)`** from
205
- `scripts/intake-blocker-reprobe.mjs`. A discharge with no recorded evidence is not a discharge,
219
+ `scripts/intake-blocker-reprobe.mjs`, including the structured `comments` and
220
+ `trustedHumanActorIds` from step 1. A discharge with no recorded evidence is not a discharge,
206
221
  and neither is a candidate nothing probed this cycle — the helper refuses both.
207
222
  4. **Record the result on the ticket either way** via `formatReprobeNote(...)` as a comment, so the
208
223
  next cycle reads the answer rather than re-deriving it. Keep it idempotent.
@@ -228,7 +243,7 @@ other gate's verdict — however conclusive — may promote an item a person par
228
243
  drift, and a drifted gate fails *silently*, by quietly ceasing to match. Do **not** re-implement
229
244
  the test here, and do **not** key it on `reason=`: markers in the wild carry no `reason=` key at
230
245
  all and sit anywhere in the body, so a structured parse would miss them while appearing to work
231
- on every item that happens to have one. **Pass the item's `comments` alongside its labels and
246
+ on every item that happens to have one. **Pass the item's structured `comments` and `trustedHumanActorIds` alongside its labels and
232
247
  body.** A hold is ended by a release recorded in a comment, so a reader handed no comments cannot
233
248
  see the discharge — it goes on holding an item whose question was answered weeks ago, which is
234
249
  the defect this gate carried from the day it was written (CodySwannGT/lisa#3852). Omitting them
@@ -239,7 +254,7 @@ other gate's verdict — however conclusive — may promote an item a person par
239
254
  and re-rejected every cycle forever and seen by nothing — `lisa-repair-intake` sweeps items that
240
255
  are **not** in the ready role and excludes gated ones outright, so a ready-and-gated item falls
241
256
  outside its filter twice over. Call
242
- `planHumanGateReconciliation({ labels, body, humanNeededLabel, readyLabel, alreadyNotified })`
257
+ `planHumanGateReconciliation({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, alreadyNotified })`
243
258
  and apply exactly the actions it returns: remove `$READY`, add the configured human-needed
244
259
  marker, and post `formatHumanGateNote()` once. The planner is idempotent by state, so an item
245
260
  already out of the lane and already marked yields no second mutation and no second comment. This
@@ -249,7 +264,7 @@ other gate's verdict — however conclusive — may promote an item a person par
249
264
  This ready-lane candidate can retain a historical body marker and a human-needed label.
250
265
  This step reconciles only candidates still in the ready lane; released holds outside it are
251
266
  recovered by `lisa-repair-intake` step 2b (or Phase 2.5 when included in this cycle). Call
252
- `planHumanGateRelease({ labels, body, comments, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
267
+ `planHumanGateRelease({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
253
268
  and apply exactly the actions it returns: remove the configured human-needed marker, add the
254
269
  configured ready role back, and post `formatHumanGateReleaseNote()` once. It is the exact inverse
255
270
  of step 3's planner and it refuses in both directions — an item still held plans nothing, and an
@@ -6,6 +6,20 @@ allowed-tools: ["Bash", "Skill"]
6
6
 
7
7
  # Write JIRA Ticket: $ARGUMENTS
8
8
 
9
+ ## Human-gate release authorization
10
+
11
+ A release requires a trusted human author, not just matching comment text. Follow
12
+ `ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
13
+ author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
14
+ or existing human-authored trusted project policy, and pass it with structured `comments` to every
15
+ hold classifier, reconciliation, normalization and release planner. Never derive trust from the
16
+ comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
17
+ Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
18
+ cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
19
+ replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
20
+ continue through the existing path and never override an independently declared caller hold.
21
+
22
+
9
23
  All Atlassian operations in this skill go through `lisa-atlassian-access`. Do not call MCP tools or `acli` directly.
10
24
 
11
25
  Create or update a JIRA ticket with all required relationships, metadata, and quality gates. Every section below is mandatory. Thin tickets are rejected.
@@ -308,7 +322,7 @@ If the label does not exist in the tracker, create it, or record that it could n
308
322
  proceed — the marker still holds. Never file the label *instead of* the marker.
309
323
 
310
324
  **Write a `reason=` the release can name.** The hold's reason is not decoration: a hold ends when a
311
- `[lisa-human-gate-release]` comment repeating that same `reason=` is recorded on the item, and the
325
+ `[lisa-human-gate-release]` comment repeating that same `reason=` is recorded on the item by an authorized human, and the
312
326
  next intake sweep then takes the marker label off and puts the item back in the build-ready role on
313
327
  its own. Matching is per-reason so that a hold declared *after* an earlier release is not born
314
328
  discharged. A keyless hold is legal and is discharged by a keyless release; a hold whose reason is a
@@ -323,7 +323,7 @@ query($id:String!,$after:String){
323
323
  project(id:$id){
324
324
  comments(first:100,after:$after){
325
325
  pageInfo{ hasNextPage endCursor }
326
- nodes{ id body createdAt url user{ name } }
326
+ nodes{ id body createdAt url user{ id name } botActor{ __typename } }
327
327
  }
328
328
  }
329
329
  }
@@ -334,13 +334,16 @@ arguments and node shape. For **both** anchors, use this access-layer adapter wi
334
334
  `linear_graphql` above; it accumulates every page and prints no partial history.
335
335
  A read succeeds only after `hasNextPage` is false. Errors, malformed pages, and
336
336
  missing or repeated continuation cursors fail the whole read.
337
+ Preserve `botActor` with each comment: its non-null presence identifies automation,
338
+ even if `user.id` is trusted. When normalizing comments, carry it forward or set
339
+ `isBot: true`; never discard this metadata before release authorization.
337
340
 
338
341
  ```bash
339
342
  linear_list_comment_pages() { # issue|project id -> complete JSON node array
340
343
  local anchor="$1" id="$2" after=null nodes='[]' seen='[]'
341
344
  local query variables response connection cursor
342
345
  case "$anchor" in issue|project) ;; *) echo "Error: invalid comment anchor" >&2; return 1 ;; esac
343
- query='query($id:String!,$after:String){'"$anchor"'(id:$id){comments(first:100,after:$after){pageInfo{hasNextPage endCursor} nodes{id body createdAt url user{name}}}}}'
346
+ query='query($id:String!,$after:String){'"$anchor"'(id:$id){comments(first:100,after:$after){pageInfo{hasNextPage endCursor} nodes{id body createdAt url user{id name} botActor{__typename}}}}}'
344
347
  while :; do
345
348
  variables=$(jq -cn --arg id "$id" --argjson after "$after" '{id:$id,after:$after}') || return 1
346
349
  response=$(linear_graphql "$query" "$variables") || return 1
@@ -367,6 +370,13 @@ linear_list_comment_pages() { # issue|project id -> complete JSON node array
367
370
  }
368
371
  ```
369
372
 
373
+ Keep the returned comment objects intact when a caller evaluates a human-gate release. The
374
+ `user.id` is the stable author identity; `user.name` is display text and never authorizes release.
375
+ Pass structured comments and an independently supplied `trustedHumanActorIds` allowlist to the
376
+ shared gate helpers (`ready-role-filing` — Human-gate release authorization). A body-only projection
377
+ loses identity and cannot discharge a hold. Preserve any explicit bot metadata from the provider;
378
+ if identity or trusted policy is unavailable, leave the hold active.
379
+
370
380
  Call `linear_list_comment_pages project "$PROJECT_ID"` for `project_id`, or
371
381
  `linear_list_comment_pages issue "$ISSUE_ID"` for `issue_id`. The caller receives
372
382
  one complete node array; it must not interpret a failed command as zero comments.
@@ -6,6 +6,20 @@ allowed-tools: ["Skill", "Bash"]
6
6
 
7
7
  # Linear Build Intake: $ARGUMENTS
8
8
 
9
+ ## Human-gate release authorization
10
+
11
+ A release requires a trusted human author, not just matching comment text. Follow
12
+ `ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
13
+ author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
14
+ or existing human-authored trusted project policy, and pass it with structured `comments` to every
15
+ hold classifier, reconciliation, normalization and release planner. Never derive trust from the
16
+ comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
17
+ Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
18
+ cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
19
+ replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
20
+ continue through the existing path and never override an independently declared caller hold.
21
+
22
+
9
23
  `$ARGUMENTS` is one of:
10
24
 
11
25
  1. A Linear team key (e.g. `ENG`) — scans that team for ready Issues.
@@ -183,8 +197,8 @@ A blocker is a **claim with a timestamp, not a fact**. It is written once and go
183
197
  For each pre-work candidate that is **not** in `$READY`:
184
198
 
185
199
  1. **Read release comments before applying the human gate.** Pass all item comments, labels,
186
- body and configured `humanNeededLabel` to `classifyReadyCandidate(...)`. For a discharged hold,
187
- call `planHumanGateRelease({ labels, body, comments, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
200
+ body, `trustedHumanActorIds` and configured `humanNeededLabel` to `classifyReadyCandidate(...)`. For a discharged hold,
201
+ call `planHumanGateRelease({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
188
202
  and retain its plan. Apply human-marker cleanup only as planned; defer any ready-role restoration
189
203
  until steps 2–5 have cleared the remaining blockers (map the role to the vendor's state or label).
190
204
  A still-active hold is never auto-selected, whatever any probe says. An absent or unreadable
@@ -196,7 +210,7 @@ For each pre-work candidate that is **not** in `$READY`:
196
210
  4. **Classify with the shared helper** so the ordering and the evidence requirement cannot drift per vendor:
197
211
 
198
212
  ```text
199
- classifyPreWorkCandidate({ laneType, labels, body, humanNeededLabel, statedBlocker, probe })
213
+ classifyPreWorkCandidate({ laneType, labels, body, comments, trustedHumanActorIds, humanNeededLabel, statedBlocker, probe })
200
214
  → { selectable, reason, humanGated, evidence }
201
215
  ```
202
216
 
@@ -224,7 +238,7 @@ other gate's verdict — however conclusive — may promote an item a person par
224
238
  drift, and a drifted gate fails *silently*, by quietly ceasing to match. Do **not** re-implement
225
239
  the test here, and do **not** key it on `reason=`: markers in the wild carry no `reason=` key at
226
240
  all and sit anywhere in the body, so a structured parse would miss them while appearing to work
227
- on every item that happens to have one. **Pass the item's `comments` alongside its labels and
241
+ on every item that happens to have one. **Pass the item's structured `comments` and `trustedHumanActorIds` alongside its labels and
228
242
  body.** A hold is ended by a release recorded in a comment, so a reader handed no comments cannot
229
243
  see the discharge — it goes on holding an item whose question was answered weeks ago, which is
230
244
  the defect this gate carried from the day it was written (CodySwannGT/lisa#3852). Omitting them
@@ -235,7 +249,7 @@ other gate's verdict — however conclusive — may promote an item a person par
235
249
  and re-rejected every cycle forever and seen by nothing — `lisa-repair-intake` sweeps items that
236
250
  are **not** in the ready role and excludes gated ones outright, so a ready-and-gated item falls
237
251
  outside its filter twice over. Call
238
- `planHumanGateReconciliation({ labels, body, humanNeededLabel, readyLabel, alreadyNotified })`
252
+ `planHumanGateReconciliation({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, alreadyNotified })`
239
253
  and apply exactly the actions it returns: remove `$READY`, add the configured human-needed
240
254
  marker, and post `formatHumanGateNote()` once. The planner is idempotent by state, so an item
241
255
  already out of the lane and already marked yields no second mutation and no second comment. This
@@ -245,7 +259,7 @@ other gate's verdict — however conclusive — may promote an item a person par
245
259
  This ready-lane candidate can retain a historical body marker and a human-needed label.
246
260
  This step reconciles only candidates still in the ready lane; released holds outside it are
247
261
  recovered by `lisa-repair-intake` step 2b (or Phase 2.5 when included in this cycle). Call
248
- `planHumanGateRelease({ labels, body, comments, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
262
+ `planHumanGateRelease({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
249
263
  and apply exactly the actions it returns: remove the configured human-needed marker, add the
250
264
  configured ready role back, and post `formatHumanGateReleaseNote()` once. It is the exact inverse
251
265
  of step 3's planner and it refuses in both directions — an item still held plans nothing, and an
@@ -6,6 +6,20 @@ allowed-tools: ["Bash", "Skill"]
6
6
 
7
7
  # Write Linear Work Item: $ARGUMENTS
8
8
 
9
+ ## Human-gate release authorization
10
+
11
+ A release requires a trusted human author, not just matching comment text. Follow
12
+ `ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
13
+ author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
14
+ or existing human-authored trusted project policy, and pass it with structured `comments` to every
15
+ hold classifier, reconciliation, normalization and release planner. Never derive trust from the
16
+ comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
17
+ Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
18
+ cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
19
+ replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
20
+ continue through the existing path and never override an independently declared caller hold.
21
+
22
+
9
23
  Create or update a Linear work item — Project (for Epics), Issue (for Stories), or sub-Issue (for Sub-tasks) — with all required relationships, metadata, and quality gates. Every section below is mandatory. Thin items are rejected.
10
24
 
11
25
  Repository name for scoped comments: `basename $(git rev-parse --show-toplevel)`.
@@ -304,7 +318,7 @@ proceed — the marker still holds. Never file the label *instead of* the marker
304
318
  **Every marker reader must consult comments.** Use `classifyReadyCandidate` with labels, body, comments and the configured human-needed label, then `planHumanGateRelease` for any release actions. A historical body marker alone is not an active hold after its matching release; unreadable comments leave a hold in place.
305
319
 
306
320
  **Write a `reason=` the release can name.** The hold's reason is not decoration: a hold ends when a
307
- `[lisa-human-gate-release]` comment repeating that same `reason=` is recorded on the item, and the
321
+ `[lisa-human-gate-release]` comment repeating that same `reason=` is recorded on the item by an authorized human, and the
308
322
  next intake sweep then takes the marker label off and puts the item back in the build-ready role on
309
323
  its own. Matching is per-reason so that a hold declared *after* an earlier release is not born
310
324
  discharged. A keyless hold is legal and is discharged by a keyless release; a hold whose reason is a
@@ -6,6 +6,20 @@ allowed-tools: ["Skill", "Bash", "Read", "Write", "Edit"]
6
6
 
7
7
  # Repair Intake: $ARGUMENTS
8
8
 
9
+ ## Human-gate release authorization
10
+
11
+ A release requires a trusted human author, not just matching comment text. Follow
12
+ `ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
13
+ author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
14
+ or existing human-authored trusted project policy, and pass it with structured `comments` to every
15
+ hold classifier, reconciliation, normalization and release planner. Never derive trust from the
16
+ comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
17
+ Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
18
+ cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
19
+ replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
20
+ continue through the existing path and never override an independently declared caller hold.
21
+
22
+
9
23
  Run one batch-**repair** cycle against the queue identified by `$ARGUMENTS`, or by merged GitHub
10
24
  config when the queue is omitted and a GitHub source/tracker default is resolvable. Where `lisa-intake`
11
25
  scans the `ready` role and moves work *forward*, repair-intake scans the **stuck and
@@ -1071,7 +1085,7 @@ with labels like `build-ready`, or with no Lisa status label at all, that are in
1071
1085
  `intake_mode=build`, every non-PRD issue is normalized as a build ticket. If `intake_mode=both`,
1072
1086
  classify PRDs first and normalize all remaining issues as build tickets.
1073
1087
  2a. **Ask whether a person is holding it, before anything else.** Call
1074
- `planLabelNormalization({ labels, body, comments, humanNeededLabel, lifecycleLabels, readyLabel })` from
1088
+ `planLabelNormalization({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, lifecycleLabels, readyLabel })` from
1075
1089
  `scripts/intake-blocker-reprobe.mjs` for every candidate and apply exactly the verdict it
1076
1090
  returns. Do **not** re-implement the test here and do **not** decide held-ness from labels
1077
1091
  alone: the vendor writers stamp the `[lisa-human-gate]` marker into the body of a deliberate
@@ -1088,7 +1102,7 @@ with labels like `build-ready`, or with no Lisa status label at all, that are in
1088
1102
  the safe failure direction without the latch. Count these under `held_for_person`, never under
1089
1103
  `normalized_ready`.
1090
1104
 
1091
- **Pass the item's `comments`.** The planner reads a recorded `[lisa-human-gate-release]` comment
1105
+ **Pass the item's `comments` with author identity and `trustedHumanActorIds`.** The planner reads a recorded `[lisa-human-gate-release]` comment
1092
1106
  as the discharge of the hold naming the same `reason=`, and an item read without its comments is
1093
1107
  an item whose discharge cannot be seen. That fails closed — it stays held — which is the safe
1094
1108
  direction and precisely why the omission is invisible.
@@ -1102,7 +1116,7 @@ with labels like `build-ready`, or with no Lisa status label at all, that are in
1102
1116
 
1103
1117
  Enumerate items carrying the configured `human_needed` marker **or** a `[lisa-human-gate]` marker
1104
1118
  in the body, and for each call
1105
- `planHumanGateRelease({ labels, body, comments, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
1119
+ `planHumanGateRelease({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
1106
1120
  from `scripts/intake-blocker-reprobe.mjs`. Apply exactly the actions it returns: remove the
1107
1121
  human-needed marker, add the configured build `ready` label back, and post
1108
1122
  `formatHumanGateReleaseNote()` once. Do **not** re-implement the discharge test, and do **not**
@@ -1119,10 +1133,10 @@ with labels like `build-ready`, or with no Lisa status label at all, that are in
1119
1133
  item carries no other configured lifecycle label.
1120
1134
 
1121
1135
  This is a genuine exception to "never remove a `human_needed` marker this skill did not apply",
1122
- and the exception is narrow enough to state exactly: provenance is the wrong question when the
1123
- *hold itself* names the condition that voids it and that condition is recorded. The general rule
1124
- stands because "stale" is otherwise a judgment about the block's kind; here nothing is being
1125
- judged — a release naming the hold's own reason is on the item, or it is not.
1136
+ and the exception is narrow enough to state exactly: the release author must first be verified against `trustedHumanActorIds`; only then does the
1137
+ matching release satisfy the hold's stated void condition. The actor who originally applied the
1138
+ marker does not need to match that authorized release author. The general rule
1139
+ stands because "stale" is otherwise a judgment about the block's kind; here an authorized matching release is required; arbitrary matching text is not enough.
1126
1140
 
1127
1141
  **Never edit a description to clear a hold**, here or anywhere. The only body write this plugin
1128
1142
  has is a whole-body replacement, so deleting one line means rewriting the record and hoping
@@ -6,6 +6,20 @@ allowed-tools: ["Skill", "Bash", "Read"]
6
6
 
7
7
  # Track Work: $ARGUMENTS
8
8
 
9
+ ## Human-gate release authorization
10
+
11
+ A release requires a trusted human author, not just matching comment text. Follow
12
+ `ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
13
+ author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
14
+ or existing human-authored trusted project policy, and pass it with structured `comments` to every
15
+ hold classifier, reconciliation, normalization and release planner. Never derive trust from the
16
+ comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
17
+ Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
18
+ cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
19
+ replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
20
+ continue through the existing path and never override an independently declared caller hold.
21
+
22
+
9
23
  Establish the tracked-work invariant before any durable project mutation. Discussion and read-only orientation may proceed without this skill; code, configuration, documentation, research artifacts, plans, investigation findings, tests, commits, and pull requests may not.
10
24
 
11
25
  This flow must return exactly one canonical `(tracker_provider, work_item_ref)` pair or fail closed. It never returns an unvalidated textual guess.
@@ -45,7 +59,7 @@ This is intentionally conservative: ambiguity creates one explicit work item ins
45
59
  ## Phase 3 — Claim and bind
46
60
 
47
61
  The work item is **held** when the caller declared a `human_gate`, independently of any item history,
48
- or `classifyReadyCandidate({ labels, body, comments, humanNeededLabel })` from the shipped
62
+ or `classifyReadyCandidate({ labels, body, comments, trustedHumanActorIds, humanNeededLabel })` from the shipped
49
63
  `scripts/intake-blocker-reprobe.mjs` returns `claimable: false`. Pass the complete live comment
50
64
  history so a matching `[lisa-human-gate-release]` discharges the historical body marker. Never
51
65
  reimplement heldness as a substring test or as the negation of `planHumanGateRelease().released`:
@@ -58,7 +72,7 @@ A held item stops the flow here, whatever roles or labels it carries. Do not inv
58
72
  and carry its reason verbatim in `gate_reason` (null for a keyless hold), then stop.
59
73
 
60
74
  For a discharged item, call
61
- `planHumanGateRelease({ labels, body, comments, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
75
+ `planHumanGateRelease({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
62
76
  and apply only the returned actions before claiming. Keep the body marker as history; a release
63
77
  never overrides a new caller-declared hold or another eligibility check.
64
78
 
@@ -6,6 +6,20 @@ allowed-tools: ["Skill", "Bash", "Read"]
6
6
 
7
7
  # Tracker Build Intake: $ARGUMENTS
8
8
 
9
+ ## Human-gate release authorization
10
+
11
+ A release requires a trusted human author, not just matching comment text. Follow
12
+ `ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
13
+ author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
14
+ or existing human-authored trusted project policy, and pass it with structured `comments` to every
15
+ hold classifier, reconciliation, normalization and release planner. Never derive trust from the
16
+ comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
17
+ Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
18
+ cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
19
+ replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
20
+ continue through the existing path and never override an independently declared caller hold.
21
+
22
+
9
23
  Thin dispatcher. Resolves the configured destination tracker and delegates to the matching vendor build-queue scanner.
10
24
 
11
25
  See the `config-resolution` rule for configuration and dispatch table.
@@ -63,7 +77,7 @@ blocker re-probe carries an absolute human gate: an item carrying the configured
63
77
  or a `[lisa-human-gate]` marker is never auto-selected, whatever a probe returns.
64
78
 
65
79
  That gate has an inverse, and it is forwarded identically: a hold ends when a
66
- `[lisa-human-gate-release]` comment naming the same `reason=` is recorded on the item. Every vendor
80
+ `[lisa-human-gate-release]` comment naming the same `reason=` is recorded on the item by an authorized human. Every vendor
67
81
  scanner passes the item's `comments` into the gate helpers so the discharge is visible, and calls
68
82
  `planHumanGateRelease(...)` to take the marker off and put the item back in the queue. **No vendor
69
83
  scanner clears a hold by editing the description** — the only body write any of them has is a
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.55.3",
3
+ "version": "4.55.5",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.55.3",
3
+ "version": "4.55.5",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.55.3",
3
+ "version": "4.55.5",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.55.3",
3
+ "version": "4.55.5",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.55.3",
3
+ "version": "4.55.5",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.55.3",
3
+ "version": "4.55.5",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.55.3",
3
+ "version": "4.55.5",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.55.3",
3
+ "version": "4.55.5",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.55.3",
3
+ "version": "4.55.5",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.55.3",
3
+ "version": "4.55.5",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.55.3",
3
+ "version": "4.55.5",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.55.3",
3
+ "version": "4.55.5",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"