Issue-Matrix Verdict Reference
Look-up material for the issue-matrix.json verdict vocabulary and the
reference-classification model that decides which discovered #NNNN citations
require a verdict row at all (#3469). This page documents the two levers as a
single source of truth so an operator or agent never has to reverse-engineer
gating behavior from gate error text.
The two levers
The issue-matrix approval gate has two independent decisions, and confusing them is the root of most "why is this blocking approval" surprises:
- Classification decides whether a row is required (gating). It runs
once, over every
#NNNNreference discovered in mission artifacts (spec.md,plan.md,research.md, analysis docs, WP prompts, contracts), and is consumed identically by every site that computes "referenced-but-missing": the WPapproved-transition blocker, the merge-timemerge_gatescheck, andstatus/doctor. One shared function, one answer — a reference is never gating at one site and non-gating at another. - Verdict decides whether an existing row is resolved. An operator may
record any verdict on any row regardless of its classification; a
not-applicableverdict makes a row non-gating regardless of classification, and an implementation-target classification requires a row to exist even if the scaffolder didn't produce one for it.
The two levers can disagree by design (an operator can always assert
not-applicable on a row the scaffolder classified gating), and that
disagreement always resolves in favor of the operator's explicit verdict.
Verdict values
| Verdict | Meaning | Gates approved? |
Gates done/merge? |
|---|---|---|---|
fixed |
The mission fixed the referenced issue. | No (resolves the row) | No |
verified-already-fixed |
The issue was confirmed already fixed before this mission touched it. | No | No |
deferred-with-followup |
Work is deliberately deferred; a follow-up is tracked. Requires an evidence-token (see below). | No | No |
in-mission |
A later work package in this mission will close the issue. | No — accepted at per-WP approved |
Yes — rejected at done; must resolve to a terminal verdict before the mission merges |
not-applicable |
The reference is cited for context only, or is a PR/commit reference — the mission owes it no work. Terminal. | No | No — passes unchanged, unlike in-mission |
not-applicable is additive: it was added alongside the four pre-existing
values with no change to their meaning, so every issue-matrix.json file
written before this change continues to validate with zero migration.
What done enforces
At done (spec-kitty consolidate, through the issue_matrix_verdict_terminality
merge gate, and spec-kitty agent tasks move-task --to done) the verdict
decides resolution for every existing row, whatever its classification:
- Every
in-missionrow blocks inblockmode and warns inwarnmode, whether or not its issue is cited. An uncited row, acontext_onlycitation such assee #12, a one-digit reference the detector skips, or a row recorded withagent issue-verdictalone all count. - When a matrix exists, it is judged whole, even for a Mission with zero gating references: a malformed row or an unknown verdict is unresolved too.
- A Mission with zero gating references and no matrix has nothing to
enforce and passes. After consolidation that means the coordination ref is
valid and holds neither
issue-matrix.jsonnorissue-matrix.md(ISSUE_MATRIX_NOT_AUTHORED). A deleted ref, a failed git probe or an empty matrix still fails. - A Mission with gating references still needs a matrix and a row for each of them (the completeness gate is unchanged); a missing matrix fails.
A PASS says what it judged:
No unresolved (in-mission/unknown) rows among N issue-matrix row(s)No issue-matrix authored and no gating issue references — nothing to enforce
approved is unchanged: an in-mission row is accepted there, and a Mission
with zero gating references never needs a matrix to be approved.
To clear a blocking row, record a terminal verdict (fixed,
verified-already-fixed, deferred-with-followup or not-applicable):
spec-kitty agent issue-verdict --mission <handle> --issue '#5678' --verdict fixed --actor <actor> --evidence-ref <evidence>
Design record: ADR 2026-10-26-1.
Reference classification: which citations become gating rows
Every discovered #NNNN token is classified into exactly one of three
buckets, aggregated over all of its occurrences in the mission's
artifacts (not just the first one found):
- Implementation-target (gating) — the default. A row is required and
must carry a verdict before
approved. - Context-only (non-gating) — the citation is scaffolded as a row for
audit purposes, but does not block approval. A row still records the
citation truthfully (typically with
not-applicable); it just isn't required to unblock the transition. - PR/commit reference (non-gating) — the same as context-only: recorded, never blocking.
Default-gating fail-safe
Classification only ever demotes a reference from gating to non-gating,
and only on a positive, explicit signal. An unmarked bare #NNNN in ordinary
prose always gates. The demoting signals are:
- A
PRorpulltoken immediately associated with the reference (either hash form,PR #300, or a full/pull/<n>URL) — classified as a PR/commit reference. - A line-scoped context marker anywhere on the line:
Follow-up:,baseline-red— the whole statement, and every reference in it, is context. - A positional citation label:
see #,parent,epic. These bind to the reference they lead into, not to the line: in**Input**: Issue #6926 (part of epic #6100), theepiclabel demotes#6100and leaves#6926gating (#7011). - A cross-repo reference (
owner/repo#NN, or a full/issues/<n>URL for a different repository) — already excluded from discovery entirely; it never becomes a row of any kind.
Ambiguity never fails open: if none of the above signals is present, the reference gates.
The Mission's own source issue is never non-gating
The issue a Mission exists to fix always gates, whatever its prose looks like (#7011). The source issue is read from the Mission's own record — every one of these sources that is present contributes:
meta.jsonsource_description, when it opens with the issue form (Issue #N: …,GitHub issue N …,Ticket #N …,#N …); a passing mention of another number deeper in the blurb is not a source issue.- the spec's
**Input**:header line — its first same-repo reference; - any
Closes/Fixes/Resolves #NNNNline in the spec.
A source issue that some scanned artifact cites is promoted to
implementation_target before classification reaches any consumer, so the
scaffold writes it an unknown row and the approval gate forces an explicit
verdict. Promotion never invents a row for a number no artifact cites, and it
never demotes: it is a guarantee layered on top of the heuristic, not a
replacement for it. The not-applicable verdict remains legitimate for
references the Mission genuinely owes no work — it just cannot be reached by
automatic classification for the Mission's own issue (ADR
2026-09-20-1
unchanged).
Multi-occurrence aggregation: implementation-target wins
A #NNNN cited once as context (e.g. parent: #200) and once as an
implementation target (e.g. "fixes the defect from #200") is classified
gating — the least-demoted occurrence wins across the whole aggregate. A
reference is never silently downgraded because one of its several citations
happened to carry a demoting marker.
The evidence-token rule (deferred-with-followup)
A deferred-with-followup verdict's evidence_ref must contain either:
- an issue reference in
#NNNform (the follow-up issue), or - a literal
Follow-up:token.
A bare deferred-with-followup with no follow-up handle in evidence_ref is
rejected. issue-verdict --help documents this rule directly so it is
discoverable before the gate rejects a submission, not only after.
Early discoverability
The specify/plan/tasks/analyze prompt templates carry a non-gating heads-up that approvals require an issue-matrix verdict for every referenced implementation-target issue — so the gate is not a surprise encountered only at the first blocked approval.
See also
spec-kitty agent tasks move-taskandspec-kitty agent issue-verdict— the generated CLI reference for the commands that read and write issue-matrix rows, includingmove-task's--actor/--reasonaliases andissue-verdict's full--helptext.- CLI Command Reference
- ADR 2026-10-26-1 — at
done, every issue-matrix row is judged, cited or not. - ADR 2026-09-20-1 — the design record for the
not-applicableverdict, the classification narrowing, and how it supersedes the never-implemented WP09not_applicableGate-4 intent noted inmerge_gates.py.