Skip to Content
ConceptsVerdict states

Verdict states

cleanflaggeddisputedunreviewablestaleunknown

Six states, defined once in packages/core/src/verdict.mjs and shared by the gate, the API and the registry site. unknown is not a state anything writes — it is the absence of an entry, and the API returns it as a body rather than a bodyless 404 so the gate always has something to decide from.

StateWhat it means
cleanThis submitted version, read statically, showed no model-detectable mismatch between its stated purpose and its code, at that time. It does not cover dependencies, and it does not mean the copy on your machine is the copy that was reviewed.
flaggedThe review found a mismatch between what the server says it does and what its code does. Carries a severity 0–4 and a finding with a file and a line.
disputedFlagged, and contested with evidence by a maintainer who proved standing. A human review is pending.
unreviewableWe were not able to review it, and we say why — a licence that does not permit it, source we could not read, a remote endpoint with nothing published. Never a pass.
staleA release shipped after the review. The review still describes the version it read; it no longer describes the newest one.
unknownNothing has been submitted for this install configuration. Absence of a verdict is absence of knowledge.

flagged and disputed both block

A dispute changes what the user is told, never whether the call is stopped. If contesting a verdict lifted the block, every flagged maintainer would file one, and the registry would be a formality. Only a human overturn produces a clean head.

/v1/flagged — the feed an org-level gateway mirrors — therefore returns both flagged and disputed. A mirror that only takes flagged silently stops enforcing every verdict anyone has contested.

The decision, computed

The gate resolves exactly one of allow · warn · block from the head alone — no blob fetch, no second round trip, because a verdict that needed a fetch to be actionable would double the latency of every tool call. This table is not transcribed from decide(); it is produced by calling it:

stateseveritydecide()What the user sees
clean0allowNothing. Exit 0, no output, no delay you notice.
flagged3blockThe call is denied and the whole case is printed, ending in the override command.
flagged2warnA one-line notice. No permission decision — your normal permission flow still decides.
disputed4blockThe call is denied and the whole case is printed, ending in the override command.
stale0warnA one-line notice. No permission decision — your normal permission flow still decides.
unreviewable0warnA one-line notice. No permission decision — your normal permission flow still decides.
unknown0warnA one-line notice. No permission decision — your normal permission flow still decides.

Severity is the second half of the rule. BLOCK_SEVERITY_THRESHOLD is 3: a flagged server at severity 2 shows its evidence and proceeds. That is what “do not stop a tool call on a single dissenting model run” means in practice — the reviewer caps severity at 2 whenever its two runs disagreed, so a contested finding warns instead of blocking.

The warn lines, verbatim

Every non-blocking outcome produces one line. They are worth reading together, because the differences between them are the product’s honesty:

WhenThe line
nobody has ever submitted this install configuration⚠ SureX: weather-mcp is not in the registry — nobody has submitted this install configuration. Proceeding unreviewed.
it is in the registry, and nothing has reviewed it⚠ SureX: weather-mcp is listed but has not been reviewed. Proceeding unreviewed.
a release shipped after the review⚠ SureX: weather-mcp released a new version that has not been reviewed yet. Proceeding unreviewed.
the licence gate refused to upload the source⚠ SureX: weather-mcp could not be reviewed (licence). Proceeding unreviewed.
a finding below the blocking threshold⚠ SureX: weather-mcp has a finding below the blocking threshold (severity 2). Proceeding.

The two unknown lines are the pair that matters. “Listed but not reviewed” and “not in the registry at all” are different facts, and telling a user a server “is not in the registry” when it is listed and simply unreviewed is a false statement about our own data.

enforceAfter does not gate blocking

A flagged server blocks from the moment it is flagged. enforceAfter only selects which of three wordings the block message uses:

WindowWording
before enforceAfter“Flagged by automated review. Not confirmed by a human. The maintainer has been notified and may respond.”
after enforceAfter“Flagged by automated review, uncontested since <date>.”
state is disputed“Flagged by automated review, and contested by the maintainer. <their rebuttal> A human review is pending.”

So a maintainer gets a window to answer before an accusation hardens, and users are protected with no delay. The two goals do not trade against each other.

Last updated on