Rework Triage: $ARGUMENTS
Classify why a previous agent attempt at this ticket failed, and convert that cause into a
structural improvement. This is the self-hardening arm of the lifecycle: every classified
failure either hardens the harness (an upstream Lisa issue), the project (a provisioning or
environment ticket), or the spec (a PRD defect flag). A rework cycle that fixes the bug but
never asks why the agent got it wrong guarantees the mistake recurs.
The caller MUST have run lisa-tracker-read first and provided the context bundle (all
comments chronological, linked PRs with review state, issue links, parent epic). Do not
classify from a bare summary — evidence-free classification is worse than none.
Phase 1 — Rework detection
A ticket is rework when it was previously implemented by this lifecycle and has returned
to a build-ready state. Evaluate these signals in order; the first confirmed signal suffices.
If none confirm, output ## Verdict: NOT_REWORK and stop — this skill takes no action on
first-attempt work.
Status history shows a post-implementation regression transition. The ticket's
changelog contains a transition from a post-build state (the configured claimed,
any configured done.* environment state, or a review state) back to the configured
ready state.
- JIRA: fetch the changelog via the
lisa-atlassian-access REST substrate —
GET /rest/api/3/issue/<KEY>/changelog — and scan items[].field == "status" entries.
- GitHub:
gh issue view <n> --json timelineItems (or the timeline API) — scan for the
$DONE/environment label being removed and $READY re-added after a linked PR merged.
- Linear: the Issue history relation — scan state changes from a completed/started state
back to the ready-labeled state.
Merged linked PR + build-ready again. The bundle shows at least one linked PR that is
MERGED, while the ticket currently carries the build-ready role. First-attempt tickets
never have merged PRs.
Prior lifecycle claim marker. The comments contain a prior implementation-cycle
marker for THIS ticket: a [claude-build-intake] claim comment, or a build-evidence
comment posted by lisa-tracker-evidence ([lisa-evidence] / the vendor evidence
header). Only markers proving a prior implementation attempt qualify —
[lisa-rework-triage] comments and other unrelated [lisa-*] annotations never do.
Explicit rework marker. A rework or regression label applied by QA or the verify
lifecycle, or a live QA-failure signal.
The QA-failure signal is transient, so its bare presence is not the signal — its
liveness is. Ask the resolver, never the label list:
RESOLVER="${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-plugins/lisa}}/scripts/qa-signal-lifecycle.mjs"
node "$RESOLVER" --vendor "<jira|linear|github>" --item bundle.json
# bundle.json: { "labels": [...], "comments": [<bodies, oldest first>], "role": "<current>" }
Branch on action, never on the label being there:
outcome |
Meaning |
What triage does |
live |
the failure is unresolved |
signal 4 fires — this is rework |
stale |
a later QA pass, or the certified/terminal role, voided it |
signal 4 does not fire; remove the label (same tracker surface that applied it) and note the repair in the triage comment. Keep evaluating signals 1–3 |
absent |
no signal |
signal 4 does not fire |
unchecked |
a declared void condition has no predicate |
treat as live and surface it — a control nothing can evaluate is a defect to report, not an exemption |
Clearing a stale signal here is the repair path for items labelled before the signal had
an inverse; without it that backlog never drains. The [lisa-qa-fail] comments are the
history and are never touched — a stale signal removed still leaves the failure fully
readable, and signal 3 still reads those comments.
rework and regression are matched on presence as before. Whether they have the same
shape is unverified and not claimed here.
Record which signal fired — it is part of the evidence trail.
Phase 2 — Failure-cause classification
Classify the failed attempt into exactly one primary cause. Every classification must
cite concrete evidence from the bundle, the codebase, or the PRD lineage — a cause without
evidence is UNCLASSIFIED, which is itself a surfaced outcome, never a silent default.
| Cause |
Definition |
Required evidence |
decomposition-infidelity |
The ticket misrepresents the PRD requirement it implements — the agent built what the ticket said, but the ticket distorted the spec. |
Resolve the ticket's requirement id(s) from the source PRD's ## Tickets section (written by lisa-prd-backlink — each entry carries requirements: ["R#"] and the register maps R# to verbatim PRD text). Quote the PRD text vs. the ticket's AC and name the divergence. |
prd-defect |
The ticket faithfully captured the PRD, but the PRD itself was wrong, ambiguous, or missing the failing case. |
Quote the PRD requirement and the QA failure it does not cover or contradicts. |
missing-tool-access |
The agent lacked a tool, credential, environment, or permission the work required, and worked around it blindly. |
The prior cycle's comments/PR show the gap (skipped verification step, "could not access", missing env credentials, absent MCP tool) — cite the marker. |
implementation-defect |
Spec and ticket were right; the agent's code was wrong. |
The failing behavior contradicts an AC the ticket states correctly; cite the AC and the failure report. |
environment-data |
The failure is caused by environment or data state (drift, missing fixtures, shared-state collision), not by the code under test. |
The failure reproduces only in the affected environment, or the report references data absent from the environment's seed/fixtures. |
verification-gap |
The code was wrong AND the verification lifecycle should have caught it — the codified regression test was missing, too weak, or asserted the wrong thing. |
Name the verification/codify-verification artifact from the prior cycle that failed to catch this class of failure. Frequently a secondary cause alongside implementation-defect; record both, primary first. |
Classification sources, in priority order: the QA failure report (comments), the prior
cycle's evidence comment and PR review thread, the PRD requirement register via
lisa-prd-backlink lineage, and the codebase itself (Glob/Grep the failing surface).
Phase 3 — Post the triage comment
Post one structured comment on the ticket via the vendor comment surface (lisa-atlassian-access operation: comment, gh issue comment, or the Linear comment mutation):
[lisa-rework-triage] Rework detected (signal: <signal>)
Fingerprint: <ticket-key>|<last merged PR number, or none>|<primary cause>
Primary cause: <cause>
Secondary cause: <cause or none>
Evidence: <2-4 lines citing the specific PRD text / AC / comment / PR review / environment fact>
Hardening action: <what Phase 4 filed, with link — or "none required (implementation-defect)">
Idempotency: the fingerprint is the literal Fingerprint: line —
<ticket-key>|<last merged PR number>|<primary cause>, with none as the PR component
when detection fired on a claim marker or label and no merged PR exists. Before posting,
scan existing comments for a [lisa-rework-triage] block whose Fingerprint: line
matches — if present, skip posting and report already-triaged. One triage per bounce,
never one per cycle re-entry.
Phase 4 — Route the cause to its hardening destination
Each cause has exactly one destination. File through the proper write path — never raw
ticket creation — so every hardening artifact passes the same quality gates as any other
Lisa work item.
| Primary cause |
Destination |
Action |
decomposition-infidelity |
Upstream Lisa issue |
The decomposition pipeline produced an unfaithful ticket and every gate passed it — that is a harness defect. File per "Filing upstream" below, citing the PRD text, the distorted ticket AC, and which gate should have caught it. |
verification-gap |
Upstream Lisa issue |
The verification lifecycle passed work it should have failed. File per "Filing upstream", citing the missed failure class and the weak/missing codified test. |
missing-tool-access |
Project tracker |
Create a provisioning ticket via lisa-tracker-write (issue_type: Task, labeled type:tooling) describing the missing tool/credential/environment and which flow needs it. Link it blocks the rework ticket. Pass human_gate: "a human must grant the missing access" per ready-role-filing — the factory cannot provision its own credentials, so this is a declared gate rather than an unclaimed filing. |
environment-data |
Project tracker |
Create an environment-hardening ticket via lisa-tracker-write citing the drift/fixture/shared-state evidence. Link relates to the rework ticket. Pass build_ready: true when the hardening is a code/fixture change the factory can make, or human_gate: "<the shared-environment decision a human owns>" when it is not — per ready-role-filing, never neither. |
prd-defect |
Source PRD |
Comment on the PRD (via the lisa-prd-backlink lineage) quoting the defective requirement and the QA failure; flag for product review. Do NOT silently edit the PRD — spec changes are a human gate. |
implementation-defect (no secondary) |
None |
Normal fix path; the classification comment is the record. Pass the pattern to the learner phase — repeated implementation defects of the same shape escalate to verification-gap. |
Secondary causes route too. A recorded secondary cause triggers its own row's
destination in addition to the primary's: implementation-defect with a
verification-gap secondary files the upstream Lisa issue per the verification-gap
row — the code being wrong does not excuse the verification lifecycle for passing it.
Deduplicate against the primary's filing (one upstream issue per failure class, not one
per cause slot).
| UNCLASSIFIED | Surface to human | Include in the triage comment and the caller's summary; a human decides. Never guess a cause to avoid this outcome. |
Filing upstream
Upstream issues target the Lisa repository itself so the harness gets fixed for every
project at once. Resolve the repo from .lisa.config.json hardening.upstreamRepo;
default CodySwannGT/lisa.
There are two upstream lanes, distinguished by what the filing proposes. Both share
the same dedupe-marker and evidence-chain discipline below; only the label and one body
section differ:
| Lane |
Label |
When |
Extra body section |
| Defect |
self-hardening |
A Lisa gate/skill/template did something wrong — a harness bug the kernel must fix. |
none |
| Contribution |
template-candidate |
A generalizable pattern discovered downstream that would benefit every host project — not a defect, a proposed improvement to Lisa's templates/rules/skills. |
## Proposed template change |
- Dedupe first.
gh issue list -R <upstream> --state open --search "<fingerprint terms>"
— if an open issue already covers this failure class or pattern, comment the new
occurrence on it (evidence compounds; duplicates dilute) and link it instead of filing.
- File with the same bar as any ticket: a three-audience description (what failed or
improved for the operator, what the harness did or could do, what to change), the
verbatim evidence chain (PRD text → ticket AC → QA failure → gate that passed it; for
patterns, the downstream occurrences proving generality), and the lane's label:
gh issue create -R <upstream> --title "<gate/skill>: <failure class>" --label self-hardening
for defects, or
gh issue create -R <upstream> --title "<template surface>: <pattern>" --label template-candidate
for contributions. A template-candidate filing MUST include a
## Proposed template change section naming the Lisa template/rule/skill surface to
change (e.g. typescript/package-lisa/package.lisa.json, a plugins/src/base rule)
and the proposed content or diff sketch, so Lisa-side intake can triage it as a
contribution rather than a defect.
- Close the loop. Reference the upstream issue URL in the triage comment. The upstream
repo's own build intake implements it; the next kernel release ships the hardening (or
the generalized pattern) to every host project.
Verdict
## Verdict: [NOT_REWORK | REWORK_CLASSIFIED | ALREADY_TRIAGED]
**Signal:** [status-history | merged-pr | claim-marker | label | n/a]
**Primary cause:** [cause | n/a]
**Secondary cause:** [cause | none]
**Hardening filed:** [upstream <url> | tracker <key> | prd-comment | none | pending-human]
The caller (ticket-triage Phase 2.5, or a standalone invocation) incorporates this into its
own findings. REWORK_CLASSIFIED never blocks the fix — the rework ticket proceeds to
implementation regardless; hardening runs alongside, not in front of, shipping the fix. The
one exception: missing-tool-access with the gap still present should surface as a Phase 3
ambiguity in the calling triage ("prior attempt lacked ; it is still unavailable"),
which blocks per the normal triage rules.
Rules
- Never classify without evidence;
UNCLASSIFIED beats a guess.
- One primary cause. Record a secondary only when the evidence genuinely supports both.
- Fire only on confirmed rework — first-attempt tickets exit at Phase 1 with
NOT_REWORK.
- All ticket/issue writes go through
lisa-tracker-write or gh as specified — never
bypass the quality gates this loop exists to strengthen.
- Noise discipline: one triage comment per bounce (fingerprinted), no upstream issue without
the dedupe search, and upstream issues describe failure classes, not single incidents.
- Never key on a durable mark whose inverse you have not checked. A signal with no expiry
degrades toward meaning "this item has been around a while"
(
state-changes-without-inverses), and a deterministic input that degrades is
deterministically wrong.
1---2name: lisa-rework-triage3description: Rework detection and agent-failure classification. When a claimed ticket turns out to be rework — previously implemented work bounced back from QA/staging — this skill detects it, classifies WHY the previous agent attempt failed (decomposition infidelity, PRD defect, missing tool access, implementation defect, environment/data, verification gap), posts a structured triage comment, and routes each cause to its hardening destination — including upstream Lisa issues so the harness itself gets fixed and the same mistake structurally cannot repeat. Vendor-neutral: consumes the lisa-tracker-read context bundle; invoked automatically by lisa-ticket-triage Phase 2.5 and runnable standalone.4---56# Rework Triage: $ARGUMENTS78Classify why a previous agent attempt at this ticket failed, and convert that cause into a9structural improvement. This is the self-hardening arm of the lifecycle: every classified10failure either hardens the harness (an upstream Lisa issue), the project (a provisioning or11environment ticket), or the spec (a PRD defect flag). A rework cycle that fixes the bug but12never asks *why the agent got it wrong* guarantees the mistake recurs.1314The caller MUST have run `lisa-tracker-read` first and provided the context bundle (all15comments chronological, linked PRs with review state, issue links, parent epic). Do not16classify from a bare summary — evidence-free classification is worse than none.1718## Phase 1 — Rework detection1920A ticket is **rework** when it was previously implemented by this lifecycle and has returned21to a build-ready state. Evaluate these signals in order; the first confirmed signal suffices.22If none confirm, output `## Verdict: NOT_REWORK` and stop — this skill takes no action on23first-attempt work.24251. **Status history shows a post-implementation regression transition.** The ticket's26 changelog contains a transition from a post-build state (the configured `claimed`,27 any configured `done.*` environment state, or a review state) back to the configured28 `ready` state.29 - JIRA: fetch the changelog via the `lisa-atlassian-access` REST substrate —30 `GET /rest/api/3/issue/<KEY>/changelog` — and scan `items[].field == "status"` entries.31 - GitHub: `gh issue view <n> --json timelineItems` (or the timeline API) — scan for the32 `$DONE`/environment label being removed and `$READY` re-added after a linked PR merged.33 - Linear: the Issue history relation — scan state changes from a completed/started state34 back to the ready-labeled state.352. **Merged linked PR + build-ready again.** The bundle shows at least one linked PR that is36 `MERGED`, while the ticket currently carries the build-ready role. First-attempt tickets37 never have merged PRs.383. **Prior lifecycle claim marker.** The comments contain a prior implementation-cycle39 marker for THIS ticket: a `[claude-build-intake]` claim comment, or a build-evidence40 comment posted by `lisa-tracker-evidence` (`[lisa-evidence]` / the vendor evidence41 header). Only markers proving a prior *implementation* attempt qualify —42 `[lisa-rework-triage]` comments and other unrelated `[lisa-*]` annotations never do.434. **Explicit rework marker.** A `rework` or `regression` label applied by QA or the verify44 lifecycle, or a **live** QA-failure signal.4546 The QA-failure signal is transient, so its bare presence is not the signal — its47 liveness is. Ask the resolver, never the label list:4849 ```bash50 RESOLVER="${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-plugins/lisa}}/scripts/qa-signal-lifecycle.mjs"51 node "$RESOLVER" --vendor "<jira|linear|github>" --item bundle.json52 # bundle.json: { "labels": [...], "comments": [<bodies, oldest first>], "role": "<current>" }53 ```5455 Branch on `action`, never on the label being there:5657 | `outcome` | Meaning | What triage does |58 |---|---|---|59 | `live` | the failure is unresolved | signal 4 fires — this is rework |60 | `stale` | a later QA pass, or the certified/terminal role, voided it | signal 4 does **not** fire; **remove the label** (same tracker surface that applied it) and note the repair in the triage comment. Keep evaluating signals 1–3 |61 | `absent` | no signal | signal 4 does not fire |62 | `unchecked` | a declared void condition has no predicate | treat as `live` and surface it — a control nothing can evaluate is a defect to report, not an exemption |6364 Clearing a stale signal here is the repair path for items labelled before the signal had65 an inverse; without it that backlog never drains. The `[lisa-qa-fail]` comments are the66 history and are never touched — a stale signal removed still leaves the failure fully67 readable, and signal 3 still reads those comments.6869 `rework` and `regression` are matched on presence as before. Whether they have the same70 shape is **unverified** and not claimed here.7172Record which signal fired — it is part of the evidence trail.7374## Phase 2 — Failure-cause classification7576Classify the failed attempt into **exactly one primary cause**. Every classification must77cite concrete evidence from the bundle, the codebase, or the PRD lineage — a cause without78evidence is `UNCLASSIFIED`, which is itself a surfaced outcome, never a silent default.7980| Cause | Definition | Required evidence |81|-------|------------|-------------------|82| `decomposition-infidelity` | The ticket misrepresents the PRD requirement it implements — the agent built what the ticket said, but the ticket distorted the spec. | Resolve the ticket's requirement id(s) from the source PRD's `## Tickets` section (written by `lisa-prd-backlink` — each entry carries `requirements: ["R#"]` and the register maps R# to verbatim PRD text). Quote the PRD text vs. the ticket's AC and name the divergence. |83| `prd-defect` | The ticket faithfully captured the PRD, but the PRD itself was wrong, ambiguous, or missing the failing case. | Quote the PRD requirement and the QA failure it does not cover or contradicts. |84| `missing-tool-access` | The agent lacked a tool, credential, environment, or permission the work required, and worked around it blindly. | The prior cycle's comments/PR show the gap (skipped verification step, "could not access", missing env credentials, absent MCP tool) — cite the marker. |85| `implementation-defect` | Spec and ticket were right; the agent's code was wrong. | The failing behavior contradicts an AC the ticket states correctly; cite the AC and the failure report. |86| `environment-data` | The failure is caused by environment or data state (drift, missing fixtures, shared-state collision), not by the code under test. | The failure reproduces only in the affected environment, or the report references data absent from the environment's seed/fixtures. |87| `verification-gap` | The code was wrong AND the verification lifecycle should have caught it — the codified regression test was missing, too weak, or asserted the wrong thing. | Name the verification/codify-verification artifact from the prior cycle that failed to catch this class of failure. Frequently a **secondary** cause alongside `implementation-defect`; record both, primary first. |8889Classification sources, in priority order: the QA failure report (comments), the prior90cycle's evidence comment and PR review thread, the PRD requirement register via91`lisa-prd-backlink` lineage, and the codebase itself (Glob/Grep the failing surface).9293## Phase 3 — Post the triage comment9495Post one structured comment on the ticket via the vendor comment surface (`lisa-atlassian-access96operation: comment`, `gh issue comment`, or the Linear comment mutation):9798```text99[lisa-rework-triage] Rework detected (signal: <signal>)100Fingerprint: <ticket-key>|<last merged PR number, or none>|<primary cause>101Primary cause: <cause>102Secondary cause: <cause or none>103Evidence: <2-4 lines citing the specific PRD text / AC / comment / PR review / environment fact>104Hardening action: <what Phase 4 filed, with link — or "none required (implementation-defect)">105```106107**Idempotency:** the fingerprint is the literal `Fingerprint:` line —108`<ticket-key>|<last merged PR number>|<primary cause>`, with `none` as the PR component109when detection fired on a claim marker or label and no merged PR exists. Before posting,110scan existing comments for a `[lisa-rework-triage]` block whose `Fingerprint:` line111matches — if present, skip posting and report `already-triaged`. One triage per bounce,112never one per cycle re-entry.113114## Phase 4 — Route the cause to its hardening destination115116Each cause has exactly one destination. File through the proper write path — never raw117ticket creation — so every hardening artifact passes the same quality gates as any other118Lisa work item.119120| Primary cause | Destination | Action |121|---------------|-------------|--------|122| `decomposition-infidelity` | **Upstream Lisa issue** | The decomposition pipeline produced an unfaithful ticket and every gate passed it — that is a harness defect. File per "Filing upstream" below, citing the PRD text, the distorted ticket AC, and which gate should have caught it. |123| `verification-gap` | **Upstream Lisa issue** | The verification lifecycle passed work it should have failed. File per "Filing upstream", citing the missed failure class and the weak/missing codified test. |124| `missing-tool-access` | Project tracker | Create a provisioning ticket via `lisa-tracker-write` (`issue_type: Task`, labeled `type:tooling`) describing the missing tool/credential/environment and which flow needs it. Link it `blocks` the rework ticket. Pass `human_gate: "a human must grant the missing access"` per `ready-role-filing` — the factory cannot provision its own credentials, so this is a declared gate rather than an unclaimed filing. |125| `environment-data` | Project tracker | Create an environment-hardening ticket via `lisa-tracker-write` citing the drift/fixture/shared-state evidence. Link `relates to` the rework ticket. Pass `build_ready: true` when the hardening is a code/fixture change the factory can make, or `human_gate: "<the shared-environment decision a human owns>"` when it is not — per `ready-role-filing`, never neither. |126| `prd-defect` | Source PRD | Comment on the PRD (via the `lisa-prd-backlink` lineage) quoting the defective requirement and the QA failure; flag for product review. Do NOT silently edit the PRD — spec changes are a human gate. |127| `implementation-defect` (no secondary) | None | Normal fix path; the classification comment is the record. Pass the pattern to the `learner` phase — repeated implementation defects of the same shape escalate to `verification-gap`. |128129**Secondary causes route too.** A recorded secondary cause triggers its own row's130destination in addition to the primary's: `implementation-defect` with a131`verification-gap` secondary files the upstream Lisa issue per the `verification-gap`132row — the code being wrong does not excuse the verification lifecycle for passing it.133Deduplicate against the primary's filing (one upstream issue per failure class, not one134per cause slot).135| `UNCLASSIFIED` | Surface to human | Include in the triage comment and the caller's summary; a human decides. Never guess a cause to avoid this outcome. |136137### Filing upstream138139Upstream issues target the Lisa repository itself so the harness gets fixed for every140project at once. Resolve the repo from `.lisa.config.json` `hardening.upstreamRepo`;141default `CodySwannGT/lisa`.142143There are **two upstream lanes**, distinguished by what the filing proposes. Both share144the same dedupe-marker and evidence-chain discipline below; only the label and one body145section differ:146147| Lane | Label | When | Extra body section |148|------|-------|------|--------------------|149| Defect | `self-hardening` | A Lisa gate/skill/template did something wrong — a harness bug the kernel must fix. | none |150| Contribution | `template-candidate` | A generalizable pattern discovered downstream that would benefit every host project — not a defect, a proposed improvement to Lisa's templates/rules/skills. | `## Proposed template change` |1511521. **Dedupe first.** `gh issue list -R <upstream> --state open --search "<fingerprint terms>"`153 — if an open issue already covers this failure class or pattern, comment the new154 occurrence on it (evidence compounds; duplicates dilute) and link it instead of filing.1552. **File with the same bar as any ticket:** a three-audience description (what failed or156 improved for the operator, what the harness did or could do, what to change), the157 verbatim evidence chain (PRD text → ticket AC → QA failure → gate that passed it; for158 patterns, the downstream occurrences proving generality), and the lane's label:159 `gh issue create -R <upstream> --title "<gate/skill>: <failure class>" --label self-hardening`160 for defects, or161 `gh issue create -R <upstream> --title "<template surface>: <pattern>" --label template-candidate`162 for contributions. A `template-candidate` filing MUST include a163 `## Proposed template change` section naming the Lisa template/rule/skill surface to164 change (e.g. `typescript/package-lisa/package.lisa.json`, a `plugins/src/base` rule)165 and the proposed content or diff sketch, so Lisa-side intake can triage it as a166 contribution rather than a defect.1673. **Close the loop.** Reference the upstream issue URL in the triage comment. The upstream168 repo's own build intake implements it; the next kernel release ships the hardening (or169 the generalized pattern) to every host project.170171## Verdict172173```text174## Verdict: [NOT_REWORK | REWORK_CLASSIFIED | ALREADY_TRIAGED]175176**Signal:** [status-history | merged-pr | claim-marker | label | n/a]177**Primary cause:** [cause | n/a]178**Secondary cause:** [cause | none]179**Hardening filed:** [upstream <url> | tracker <key> | prd-comment | none | pending-human]180```181182The caller (ticket-triage Phase 2.5, or a standalone invocation) incorporates this into its183own findings. `REWORK_CLASSIFIED` never blocks the fix — the rework ticket proceeds to184implementation regardless; hardening runs alongside, not in front of, shipping the fix. The185one exception: `missing-tool-access` with the gap still present should surface as a Phase 3186ambiguity in the calling triage ("prior attempt lacked <tool>; it is still unavailable"),187which blocks per the normal triage rules.188189## Rules190191- Never classify without evidence; `UNCLASSIFIED` beats a guess.192- One primary cause. Record a secondary only when the evidence genuinely supports both.193- Fire only on confirmed rework — first-attempt tickets exit at Phase 1 with `NOT_REWORK`.194- All ticket/issue writes go through `lisa-tracker-write` or `gh` as specified — never195 bypass the quality gates this loop exists to strengthen.196- Noise discipline: one triage comment per bounce (fingerprinted), no upstream issue without197 the dedupe search, and upstream issues describe failure *classes*, not single incidents.198- Never key on a durable mark whose inverse you have not checked. A signal with no expiry199 degrades toward meaning "this item has been around a while"200 (`state-changes-without-inverses`), and a deterministic input that degrades is201 deterministically wrong.