Skip to content
WhisperGraph
Skip navigation

Coverage — what we looked at

Every Whisper verdict answers two questions: how bad, and what we actually looked at. Read coverage before band.

Published

On this page (6)

Coverage — what we looked at Documentation

Every Whisper verdict answers two independent questions. band tells you how bad. coverage tells you what we actually looked at. Read both. They are a grid, not a ladder.

Only known-clean — coverage: known-clean. In coverage, no malicious evidence. licenses the word "clean". Every other value is not-clean — and no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. and deadline-hit mean unknown, which is a different thing again.

whisper.assess and whisper.assessUrl return coverage. whisper.explain does not — see the procedure contract below before you rely on either.

The four values whisper.assess returns

coverageWhat it meansWhat to do
known-clean — coverage: known-clean. In coverage, no malicious evidence.We hold data at this granularity and nothing malicious is in it.Treat as clean. This is the only value that licenses closing a ticket on "clean."
malicious-evidenced — coverage: malicious-evidenced. In coverage, with positive evidence of malice.Some positive evidence of malice exists. It may be a single feed at weight 0.5. It does not mean the band is high.Read evidence[] for feed-source-count, then run explain() for the per-feed provenance, weights and timestamps. A count of 1 on a low-weight aggregate list is a lead, not a finding.
ambiguous — coverage: ambiguous. In coverage, and the evidence points both ways.The evidence points both ways — for example an anonymising-egress signal alongside generic abuse listings.Escalate to a human. Do not automate a decision on this value.
no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at.We have never observed this host.Unknown. Never benign. Follow the no-data playbook — do not simply escalate.

Every one of these arrives as a populated row. no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. is a row that says no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at.; it is never an empty result set. If a query returns zero rows, the first hypothesis is that the query is wrong, not that the host is clean.

The case that proves the rule

cypher · runnablegraph.whisper.securitySign in to run
CALL whisper.assess(["140.82.121.3"]) YIELD host, band, coverage, evidence
RETURN host, band, coverage, evidence

text
{"host":"140.82.121.3","band":"LOW","coverage":"malicious-evidenced",
 "evidence":["coverage:malicious-evidenced","band:LOW","host-class:unknown",
             "feed-source:listed","feed-source-count:1"]}

band: LOW beside positive evidence of malice. A pipeline that gates on band alone treats this row as unremarkable. The band is low because the verdict reconciler de-escalates for a multi-tenant apex, for evidence older than 90 days, and for a zero base score — none of which change what we looked at.

That is why the rule is key on coverage, never on band.

no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. is common — here is what to do with it

no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. is not exotic: CALL whisper.assess(["104.16.132.229","104.16.123.96"]) — two ordinary Cloudflare edge addresses — returns band: UNKNOWN, coverage: no-data for both. Hostnames that appear in DNS generally carry real coverage; a bare IPv4 address often does not.

So "escalate everything that says no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at." is not a workable rule at volume, and we are not going to pretend it is. When you get no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at., ask a different question rather than a louder one.

  1. Ask about the container. CALL explain("<enclosing /24>") and the announcing ASN. A host we have never seen inside a heavily-listed block is a different fact from the same host inside a clean one. (On a CIDR or ASN indicator, read explanation and factors[] alongside score: they carry the network-level finding — how many listed addresses and subnets the block contains, and its threat density. See the procedure contract.)
  2. Ask who runs it. CALL whisper.identify(["<host>"]). A no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. verdict on infrastructure that identifies as a known SaaS vendor is expected. On infrastructure that identifies as nothing, the no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. is the finding.
  3. Ask when it appeared. CALL whisper.history.whois("<domain>"). A domain registered this week has no feed history by construction — that is the signal, not the absence of one.
  4. Only then escalate — and escalate with the sentence "we have no observation of this host", never with "it came back clean."

The other three declared values

The coverage vocabulary has seven values. whisper.assess emits four of them. The other three are real, and they are not assess values.

ValueWhere it is observedTreat it as
deadline-hitFrom whisper.walk. CALL whisper.walk("google.com", 2, 1) (a one-millisecond budget) returns coverage: "deadline-hit" with arms.deadline_hit: trueNot a verdict. The time budget expired before coverage could be established. Retry with a larger budget. Never read it as clean and never read it as bad
partialNot observed by any probe run for this pageNot-clean. We covered only part of what you asked about — narrow the scope and re-ask
structural-onlywalk — a whisper.walk value describing atlas adjacency. Not an assess coverage value. Do not gate on it.From whisper.walk only. See belowNot a verdict at all. Do not gate on it

Treat any value other than known-clean — coverage: known-clean. In coverage, no malicious evidence. as not-clean, and no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at., deadline-hit and partial as unknown, which is a different thing again.

We have not observed partial, and we are not asserting it is unreachable. If a later measurement produces it, this table gains a row.


structural-onlywalk — a whisper.walk value describing atlas adjacency. Not an assess coverage value. Do not gate on it. is a whisper.walk value. It is not an assess value.

Do not gate on structural-onlywalk — a whisper.walk value describing atlas adjacency. Not an assess coverage value. Do not gate on it.. If your code has a branch for it on an assess result, that branch is unreachable — and the branch you are missing is malicious-evidenced — coverage: malicious-evidenced. In coverage, with positive evidence of malice..

The seven values split across two axes, and the split is enforced in the engine:

AxisValuesWhat a value asserts
Verdict axisknown-clean — coverage: known-clean. In coverage, no malicious evidence. · malicious-evidenced — coverage: malicious-evidenced. In coverage, with positive evidence of malice. · ambiguous — coverage: ambiguous. In coverage, and the evidence points both ways.A claim about malice
Presence axisstructural-onlywalk — a whisper.walk value describing atlas adjacency. Not an assess coverage value. Do not gate on it. · partial · no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. · deadline-hitA claim about whether we looked — and nothing about malice

whisper.assess is a verdict procedure: it emits the three verdict-axis values, plus no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at.. whisper.walk is not a verdict procedure: it may emit presence-axis values only, so that a tool which is not authorised to render a verdict cannot leak one through this vocabulary.

whisper.walk's coverage therefore describes atlas and vendor adjacency, not threat coverage — whether the host is reachable in the graph's structure. Its full column set makes this explicit (no_atlas_match, nearest_known_vendors, siblings, arms).

The same indicator can carry two different coverage values from two different procedures, and for one indicator the two flatly disagree.

text
CALL whisper.assess(["185.220.101.1"])  ->  coverage: "ambiguous"       (there is evidence)
CALL whisper.walk("185.220.101.1")      ->  coverage: "no-data"         (no atlas match)

Both are correct. They answer different questions. Read the procedure before you read the column.

One more trap in walk: a truncated walk still returns structural-onlywalk — a whisper.walk value describing atlas adjacency. Not an assess coverage value. Do not gate on it.. CALL whisper.walk("github.com", 2, 3) returns coverage: "structural-only" with arms: {arms_completed: 7, arms_truncated: 5, arms_excluded: 1, deadline_hit: false} — five arms dropped and no deadline flag. Read arms before you read coverage on a walk row.

Which procedure carries coverage

ProcedureReturns coverage?What its coverage is about, and the gotcha
whisper.assessYesThreat coverage — the four values above. Its output contract is host, label, band, sub_labels, signals, coverage, evidence, verdictScore, isThreat, threatSources; YIELD anything else and you get HTTP 400 query-error naming the valid columns.
whisper.assessUrlYesA path axis, not a host axis. Its coverage describes what was checked about the URL path, so the standing rule does not transfer unchanged — read this row before gating on it, and prefer whisper.assess for any decision that turns on host coverage.
whisper.walkYes, but not a verdictAtlas and vendor adjacency. Presence-axis values only. Read arms first.
whisper.explainNoReturns indicator, type, available, cached, found, score, level, explanation, factors, sources, advisory. There is no coverage column at all, so a level: NONE from explain() is not a clean verdict — it is a score, and the question of whether we looked is simply unanswered.

Two gotchas on explain() worth stating plainly:

  • On a CIDR or an ASN, score and level describe the whole network, and explanation and factors[] say why. CALL explain("3.64.0.0/12") returns a CRITICAL level with an explanation that counts the listed addresses and subnets inside the block and gives its threat density. Read the explanation before you act on a network-level score: a large block with a modest density is a different fact from a small block that is listed end to end.
  • advisory is usually null and occasionally load-bearing. explain("1.1.1.1") returns advisory: "allowlist-vouched"; most indicators return null. Select it by name if you need it, and do not treat a blank as "no advisory applies" without checking the indicator type.

The rule key on coverage, never on band is published per procedure, never as a blanket rule, because it is only true of the procedures that return a coverage column.