Skip to main content
Glama

EchelonGraph CVE & Exposure

Server Details

CVE, KEV, EPSS, SBOM and advisory lookups; per-CVE exposure from Shodan data (© Shodan). Keyless.

If you are the author of this connector, you can claim ownership by verifying the domain or GitHub account it belongs to. Claimed connector authors can inspect health checks, view analytics, and manage their listing.
Status
Healthy
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL
Repository
echelongraph/echelongraph-mcp
GitHub Stars
0
Server Listing
EchelonGraph MCP Server

TDQS

A3.9/5.0

Scored across 14 tools

Disambiguation4/5

Most tools target clearly distinct resources: CVE record (get_cve), enrichment (cve_intel), exposure (cve_exposure), EPSS series (epss_history), and KEV feed (kev_recent) are separable, and the three vendor-advisory tools split cleanly by search / by-CVE / by-ID. There is mild overlap in the single-CVE cluster (get_cve vs cve_intel both surface affected-package/CWE-adjacent data), and check_affected vs check_sbom differ mainly by single-component vs list, so a few pairs need the verbose descriptions to disambiguate.

Naming Consistency3/5

snake_case is used throughout, but conventions are mixed: verb_noun (check_affected, get_cve, search_cves), bare noun/topic names (cve_exposure, cve_intel, epss_history, exposure_radar), and a noun+preposition form (vendor_advisories_for_cve) plus kev_recent. The names remain readable and mostly predictable, but there is no single consistent verb_noun pattern.

Tool Count5/5

Fourteen tools is well within a healthy range and each maps to a distinct function: component/SBOM checking, per-CVE record, intel, exposure, EPSS history, CWE listing, KEV feed, summary, and three vendor-advisory views. No tool appears redundant or trivial.

Completeness5/5

The surface covers the full CVE/exposure lifecycle: search and lookup of CVEs and CWEs, component and SBOM impact checking, enrichment (exploits, packages, fixes), EPSS history, KEV catalog, aggregate and per-CVE exposure, and vendor advisories via three complementary entry points. No obvious dead ends for the stated domain.

Available Tools

14 tools
check_affectedAm I affected? (product or package at a version)A
Read-onlyIdempotent
Inspect

Whether a product or package at a given version is affected by known CVEs, from the same matcher as echelongraph.io/am-i-affected. Two lookup paths. The CPE path takes product (the NVD CPE product token, such as openssl or nginx) and version, and returns the CVEs whose NVD CPE match criteria name that product with a version range that includes the version; it matches the token across vendors, so each match names the vendor NVD asserts (cpe_vendor) and whether that vendor was verified (vendor_unknown). The registry path takes ecosystem (npm, PyPI, Maven and other OSV ecosystem names), package and version, and decides each OSV advisory record EchelonGraph holds for that package as affected, not affected or undetermined. Read assessed before count: assessed false means the lookup did not evaluate this component, not_assessed_reason says why (product_not_in_cpe_corpus, package_not_cpe_nameable, candidate_load_pending, candidate_window_truncated, package_not_in_advisory_corpus, no_decidable_advisory), the structured result's state is not_assessed, and a count of 0 there must never be reported as not affected. An advisory whose version range cannot be decided at this version is reported as undetermined (undetermined_count, and up to 50 of them in undetermined), never as safe. The answer also carries match_layer (which path answered), capped (the match list stopped at its cap), candidates_capped (not every candidate CVE was loaded), excluded_count (CPE candidates suppressed by the vendor or platform gate), not_affected_count (advisories decided in your favour) and degraded (the lookup ran out of time). Each match carries cve_id, kev_listed, ransomware, epss_score, effective_score, effective_severity and score_assessed (false: EchelonGraph has not scored the CVE yet, so its echelongraph_score is withheld). Product, version, ecosystem and package travel in request headers, never in the URL. Its structured result carries state (measured only when the answer says assessed true), measured_at (null), method (which matcher answered), coverage (assessed and not_assessed_reason first, then the lookup path and the counts above), freshness (null) and notes, with data equal to the API's JSON. Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole. Cut, the excluded and undetermined samples keep their first 10 entries, each its cve_id and reason, cve_ids keeps its first 10 (each match carries its cve_id), and each match keeps fewer fields, cve_id, kev_listed, ransomware, epss_score, effective_score and score_assessed at least, so that every match stays in the text.

ParametersJSON Schema
NameRequiredDescriptionDefault
packageNoRegistry path: the package name in that ecosystem, such as lodash.
productNoCPE path: the NVD CPE product token, such as openssl, nginx or linux_kernel. Leave out for the registry path.
versionYesThe version to check, such as 3.0.0.
ecosystemNoRegistry path: the package's ecosystem, such as npm, PyPI or Maven. Give with package, not with product.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations already covering readOnly/idempotent/openWorld, the description still adds substantial behavioral context: the assessed/not_assessed_reason contract, the rule that a count of 0 under not_assessed must never be read as safe, undetermined handling, caps (capped, candidates_capped, excluded_count), degraded timeouts, and the 30,000-character truncation policy with what is preserved. This is far beyond what annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The opening sentence front-loads purpose well, but the remainder is a dense, run-on block that packs assessed/undetermined semantics, caps, truncation rules and header transport into long compound sentences. Much of it is useful, but it is not tightly structured or easy to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a 4-parameter tool with an output schema and rich annotations, the description covers every edge case an agent needs: state semantics, truncation, caps, degraded mode and path selection. Nothing material is missing for correct invocation and interpretation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: it clarifies the CPE vs registry path split, that product is an NVD CPE token, that ecosystem uses OSV names, and that parameters travel in request headers rather than the URL. It slightly exceeds what the schema alone conveys.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource+scope: whether a product or package at a given version is affected by known CVEs, and explicitly ties itself to the same matcher as the am-i-affected service. It distinguishes its two lookup paths (CPE vs registry), which differentiates it from siblings like search_cves or cve_exposure.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly explains the two lookup paths and the parameter combinations that select each (product+version for CPE; ecosystem+package+version for registry), which is strong conditional guidance. It does not name alternative sibling tools or state when this tool should be preferred over them, so it stops short of explicit when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_sbomCheck an SBOM against the advisory corpusA
Read-onlyIdempotent
Inspect

Check a dependency list against EchelonGraph's advisory corpus, one verdict per component. Pass purls (package URLs, up to 2,000 distinct) or sbom (a CycloneDX JSON or SPDX JSON document, as JSON text or as an object, up to 5,000,000 characters). The purls are read from the document by this MCP server and only they are sent to the API, in POST bodies of at most 200 purls each, one after another, never in a URL; the document itself is not sent on. Run from npm, this server is on your machine; over the hosted endpoint (mcp.echelongraph.io) it is EchelonGraph's, and the document is the request body, accepted up to 6 MiB. A component without a purl is counted and not checked. Each purl is mapped to its OSV ecosystem, package name and version and matched against the affected version ranges EchelonGraph holds from OSV.dev advisory records; there is no ranking and no score. data.results holds one row per component sent, in order (index counts across batches), with verdict (affected, not_affected, undetermined or not_assessed), assessed, not_assessed_reason, cve_ids, matches, count, not_affected_count and undetermined_count; data.summary counts the verdicts, summed over the batches (partial is true when any batch's was). not_affected is the only clean verdict. undetermined: advisories name the package but at least one could not be decided at this version and none matched. not_assessed: no verdict at all, because the package is not in the corpus, the purl type has no OSV ecosystem, a deb, apk or rpm purl carries no distro qualifier naming its release (EchelonGraph does not guess one), the version is missing, the lookup failed, or the batch's time budget ran out first (time_budget). Neither undetermined nor not_assessed is clean, and the note gives their counts. The API allows 1,200 components a minute per caller; when it answers 429 with Retry-After, the tool waits as asked and sends the batch again, within 50 seconds per call. When the next wait would pass that, or a batch after the first fails, the tool stops and answers what it has: coverage.not_sent counts the purls not sent and coverage.not_sent_reason says why (time_budget, rate_limited or request_failed), data.not_sent_purls lists them for a later call, and they are not checked and not clean. A list or document with more than 2,000 distinct purls is refused, not truncated: split it. Its structured result carries state (measured when at least one component got a verdict, else not_assessed), measured_at (null: the corpus is read through a cache, so no single read time exists), method, coverage (what the input held, what was sent in how many batches, and what was not sent and why), freshness (null) and notes, with data equal to the API's JSON (for more than one batch, the batches' answers merged); the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends. Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole. Cut, each row keeps index, purl, verdict, not_assessed_reason and cve_ids at least, and the rows whose verdict is not_affected, then not_assessed, are left out of the text before any other; not_sent_purls keeps its first 10, and the note says from which position of the input the purls not sent run.

ParametersJSON Schema
NameRequiredDescriptionDefault
sbomNoa CycloneDX JSON or SPDX JSON document, as JSON text or as an object; its purls are read by this MCP server and only they are sent to the API; over the hosted endpoint (mcp.echelongraph.io) the document is the request body
purlsNopackage URLs to check, e.g. pkg:npm/lodash@4.17.20 or pkg:deb/debian/openssl@3.0.11-1~deb12u1?distro=debian-12 (up to 2,000 distinct, sent in batches of 200)

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover safety (readOnly/openWorld/idempotent), but the description discloses behavior they cannot: 1,200 components/minute rate limit, 429 Retry-After handling within a 50-second per-call budget, batching of 200 purls, partial-result semantics, and exactly what causes undetermined vs not_assessed. This is unusually rich disclosure of failure and truncation behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded, but the remainder is one dense run-on paragraph of nested clauses with some redundancy ('not checked and not clean' appears twice). The complexity justifies length, yet headings or bullets would make the rate-limit, verdict and truncation rules far easier to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-param tool with an output schema, this covers everything an agent needs: input limits, batching, verdict taxonomy, partial-coverage fields, retry/stop conditions, and text-truncation behavior including which fields survive the cut. Nothing material is left to inference.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema: purls are parsed from the document server-side and only they are sent, the document is never sent as a URL, and concrete limits (2,000 distinct purls, 5M chars, 6 MiB hosted) are given.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening states a specific verb and resource: 'Check a dependency list against EchelonGraph's advisory corpus, one verdict per component,' and the 'one verdict per component' scope distinguishes it from single-package siblings like check_affected. It never names a sibling directly, so differentiation is implicit rather than explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear in-tool context: supply purls or an SBOM, and a list over 2,000 distinct purls is refused and must be split. However, it never states when to reach for check_sbom versus check_affected, so the agent must infer the batch-vs-single distinction.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cve_exposureInternet exposure for one CVEA
Read-onlyIdempotent
Inspect

Internet-exposure footprint for one CVE from EchelonGraph's KEV-exposure radar: how many internet-facing services (distinct ip:port, returned as exposed_hosts; a machine answering on two ports counts twice) the radar has on record running a version its CVE matcher maps to this CVE, with a country/product breakdown and a ransomware flag. Aggregate and host-redacted; free and keyless. Method: exposure counts are derived from Shodan data. Shodan data is owned by Shodan, which holds its copyright (© Shodan). Every 12 h, when Shodan query credits allow, the radar runs one Shodan query per tracked product, reads up to 100 ip:port services per query, and keeps a service when its banner version matches a CISA-KEV or high-EPSS CVE; a service whose row has not been written or refreshed for 21 days is dropped. last_seen is when EchelonGraph last wrote or refreshed a service's row, not when the service was observed and not when its vulnerable version was last confirmed: it is set to the time of the write when a search matches the banner, and again when a re-check finds the port still listed by Shodan InternetDB, without re-reading the banner, so a patched service can stay counted while its port stays open. A count is therefore a banner-version inference over a sample, not an exploit test and not an internet-wide census. The radar only looks for its tracked set of CVEs: for a CVE outside that set the note says NOT ASSESSED (exposure_state not_assessed), and its 0 is not a measurement. Its structured result's state is not_assessed with measured_at null: the per-CVE answer says when EchelonGraph last wrote a row (last_seen), not when any counted service was observed, so no count is presented as a dated measurement; the count is still relayed, labelled, as what the radar holds on record. exposure_state says what the count is: exposed, measured_zero, not_assessed or tracking_unknown; coverage.in_scope is the API's tracked verdict; freshness is null, since the per-CVE answer carries no last completed check; data is the API's JSON. The result's last text block repeats the structured result without data (the first text block), without the note's sentences (the text block before it), with which notes ends, and without method where the note quotes it verbatim ("Method: …"). Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole.

ParametersJSON Schema
NameRequiredDescriptionDefault
cve_idYesa CVE ID, e.g. CVE-2023-44487

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover read-only/idempotent/open-world, and the description adds substantial non-redundant behavior: Shodan-derived sampling, the 12 h credit-limited query cycle, the 100 ip:port read cap, the 21-day staleness drop, and the precise (and counterintuitive) meaning of last_seen as a write/refresh time rather than observation time. It also discloses the 30,000-character truncation behavior and that counts are banner-version inference, not exploit tests.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core purpose is front-loaded, but the description then sprawls into meta-commentary about text-block repetition, which notes end which block, and where verbatim method text is quoted. Much of this belongs in the output schema or docs, not in a selection/description string, and it buries the usable signal.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite verbosity, everything an agent needs is present: the unit of counting, sampling caveats, exposure_state semantics, last_seen semantics, out-of-scope handling, and truncation behavior, on top of annotations and an output schema that already describe safety and return shape.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single cve_id parameter, so the schema already carries the format example. The description adds semantics about what happens for CVEs outside the tracked set but nothing about the parameter itself, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific resource and scope: the internet-exposure footprint for one CVE, with a concrete unit (distinct ip:port services, double-counted across ports). It implicitly separates itself from the sibling exposure_radar by being per-CVE, but never names or contrasts that sibling explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives real usage context: it only covers the radar's tracked CVE set, out-of-scope CVEs return NOT ASSESSED, and the 0 for those is not a measurement. However it never says when to pick this tool over exposure_radar, cve_intel, or check_affected, so the alternative-selection guidance is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cve_intelCVE weakness, exploits and packagesA
Read-onlyIdempotent
Inspect

Weakness, public exploit code, affected packages and fixed versions for one CVE, from EchelonGraph's per-CVE enrichment. Returns cwes (each cwe_id with its name and source), exploits (each with kind, source_name, source_url, first_seen_at and verified_status; at most 10, verified first) with exploits_total (every reference on record), exploits_capped (true when exploits lists fewer than exploits_total), exploits_by_kind and exploits_by_status, affected_packages (ecosystem, package_name, version_range, fixed_version), fixed_versions (ecosystem, package_name, vulnerable_range, fixed_version) and timeline (the newest enrichment-history rows, with timeline_total). verified_status is the label stored with each reference: verified for a Metasploit module, for an Exploit-DB entry Exploit-DB marks verified, and for curated seed rows marked so; reported for a public artefact nothing has confirmed works (nuclei templates, GitHub proofs of concept, unverified Exploit-DB entries); unconfirmed where a curated row says so. It is a label from the source, not a guarantee that the exploit works against a given system. An empty exploits list is not evidence that no public exploit exists: it covers only the sources EchelonGraph ingests, and which of them are polled depends on the deployment. A section the API could not read is named in coverage.sections_failed and left out of data, never relayed as an empty list. Vendor advisories, patches, generated summaries, trending signals and historical incidents are not relayed. Pass a CVE ID like CVE-2021-44228. Its structured result carries state (measured), measured_at (null: each row carries its own time), method, coverage (the sections relayed, failed and left out, and per-list counts), freshness (null) and notes, with data, which the first text block holds whole up to 30,000 characters; the result's last text block repeats it without data and without the note's sentences (the text block before it), with which notes ends. Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole.

ParametersJSON Schema
NameRequiredDescriptionDefault
cve_idYesa CVE ID, e.g. CVE-2021-44228

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover the safety profile (readOnly, idempotent, non-destructive, openWorld), and the description goes well beyond them: it defines verified_status semantics, the exploits cap (10, verified first) with exploits_total/exploits_capped, the deployment-dependent source coverage, the coverage.sections_failed failure mode, and the truncation contract at 30,000 characters. This is unusually rich behavioral disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded, but the bulk of the text is a dense, single-paragraph exposition of return-value structure (state, measured_at, coverage, freshness, notes, data, first/last text blocks, TEXT CUT behavior). Since an output schema exists, most of that detail is redundant here, making the description oversized for what it must convey.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a per-CVE enrichment tool with an output schema already present, the description covers the non-obvious gaps an agent would otherwise miss: source-deployment-dependent coverage, the failed-section failure mode, verified_status interpretation and the truncation limit. Nothing essential to calling it correctly is absent, though the sibling-routing guidance remains implicit.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is a single required parameter with 100% schema description coverage, so the schema carries the semantics. The description only repeats the format example (CVE-2021-44228) already present in the schema and adds no validation or formatting rules. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names a concrete resource and scope: weakness, exploits, affected packages and fixed versions for ONE CVE, sourced from EchelonGraph enrichment. It further delineates by enumerating what is NOT relayed (vendor advisories, patches, summaries, trending, incidents), which separates it from sibling get_vendor_advisory and cve_summary even without naming them. It stops short of naming a sibling explicitly, so a 4 rather than 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage context is clear: pass a CVE ID like CVE-2021-44228, and the exclusion list tells the agent to route elsewhere for advisories, summaries, trending or incidents. It also warns that an empty exploits list is not proof of no exploit and that coverage.sections_failed must be checked, which shapes correct use. No explicit when-not-to-use statement naming alternatives, so 4.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cve_summaryCVE feed summaryB
Read-onlyIdempotent
Inspect

Summary of EchelonGraph's CVE Pulse feed: summary.total active CVEs, their counts by severity band (summary.critical, summary.high, summary.medium, summary.low), the count with no band (summary.none), and summary.last_updated, the newest modification time among those records. summary.none is not a severity rating of None: it counts the active CVEs with no severity band from any source, that is, CVEs not yet scored, and the answer may carry the same count again as summary.unscored. Whenever summary.none is above zero the note says so: report those CVEs as not yet scored, not as CVEs rated None. summary.nvd_critical, summary.nvd_high, summary.nvd_medium, summary.nvd_low and summary.nvd_none count the same active CVEs as summary.total by NVD's CVSS severity label (v3.x, else v4.0; before NVD's record arrives, or where it gives none, a pre-NVD label from the CVE.org record or a GitHub advisory can stand in): provenance, never EchelonGraph's severity band. summary.nvd_none counts the active CVEs with no Critical, High, Medium or Low label there, CVEs NVD never labelled under CVSS v3 among them, and many of those carry an NVD CVSS v2 score instead: it is neither a count of CVEs rated None nor the count of CVEs with no severity, which is summary.none. Whenever summary.nvd_none is above zero the note says what it counts, with its count. summary.rejected counts the CVE records rejected (withdrawn) by their numbering authority, which summary.total and the other counts above leave out: report them as withdrawn records, never as vulnerabilities. poller holds the in-memory counters of the NVD poller of the one API instance that answered (cves_ingested, cves_skipped, http_retries, poll_count, poll_errors, last_poll_at, last_poll_dur_ms, interval), counted since that instance last started and zeroed on every restart: they describe that instance, never the feed's size, intake, reliability or freshness. Whenever the answer carries poller the note says so. A poller field the answer sends in a JSON type other than the one described here is left out of data and named in the note, and a poller that is neither a JSON object nor null is left out whole: summary is relayed either way. The feed is polled from its sources on a schedule, so this is the state as of that update. Its structured result carries state (measured), measured_at, method, coverage, freshness (null: the feed serves no poll-completion time) and notes, with data equal to the API's JSON less each poller field (or the whole poller) the note names as left out; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends. Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

B3.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive), so the bar is lower, and the description still adds real behavioral context: the data is a point-in-time state from a scheduled poll, freshness is null because no poll-completion time is served, poller counters are per-instance and zeroed on restart, and output is truncated past 30,000 characters with a TEXT CUT note. Much of the remaining text documents output fields rather than invocation behavior, keeping it just short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single unbroken ~600-word paragraph for a zero-parameter tool, with repeated conditional boilerplate ('Whenever summary.none is above zero the note says so', 'Whenever the answer carries poller the note says so'). Much of the field-by-field explanation duplicates what an output schema should carry, and there is no structure, headings or bullets to make it scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a relay tool with a structured result envelope and an output schema, the description is more than complete on result interpretation: it covers state, measured_at, method, coverage, freshness-null, notes, poller exclusion and truncation. The only real gap is invocation context (why/when to pick this over sibling tools), which the rubric weights elsewhere.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes no parameters, so per the rubric the baseline is 4. The description adds nothing about inputs (there are none) and spends its length on output semantics, which is appropriate for a zero-argument call.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening line states the resource clearly ('Summary of EchelonGraph's CVE Pulse feed') and the enumeration of summary.* fields makes the returned aggregate counts concrete. However, it never names or contrasts with siblings such as cve_intel, cve_exposure or search_cves, so an agent must infer where this fits in the family. Clear purpose, no sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance whatsoever: nothing says to call this for a fleet-wide severity snapshot rather than search_cves or cve_intel, and no exclusions or alternatives are named. The only prescriptive text concerns how to report results, not when to invoke the tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

epss_historyEPSS change history for one CVEA
Read-onlyIdempotent
Inspect

How one CVE's EPSS score (FIRST's exploit-prediction probability, 0 to 1, with its percentile) has changed, as EchelonGraph recorded it: points, oldest first, each with at, epss_score and epss_percentile; current, the record's value now (epss_score, epss_percentile, epss_updated_at); series_kind, always change_only; series_starts_at, when EchelonGraph began recording EPSS changes for any CVE; history_rows, points_truncated and latest_point_matches_current. Pass a CVE ID like CVE-2023-44487. The series is change-only: a point is a recorded change, and a day without a point is not a recorded value. Never interpolate it into a daily series. Before series_starts_at nothing was recorded, so a missing point there means not recorded, not unchanged, and the value in force before a CVE's first point is not in the series. latest_point_matches_current false means a change is missing from the series. Its structured result carries state (measured), measured_at (current.epss_updated_at: when EchelonGraph last wrote a changed value, not FIRST's score date), method, coverage (series_kind, series_starts_at, points, points_truncated), freshness (null) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends. Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole.

ParametersJSON Schema
NameRequiredDescriptionDefault
cve_idYesa CVE ID, e.g. CVE-2023-44487

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare it a read-only, idempotent, open-world, non-destructive call, but the description goes far beyond that: change-only series semantics, the meaning of series_starts_at, latest_point_matches_current=false as a signal of a missing change, the structured result's state/method/coverage/freshness shape, and the 30,000-character TEXT CUT truncation behavior. This is exactly the behavioral context annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The information is genuinely valuable, but it is delivered as a dense wall of semicolon-joined clauses with little paragraphing, making key rules hard to scan. The core purpose is front-loaded, yet the return-shape and truncation details pile into the same run-on sentences, hurting readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex, semantically tricky tool (change-only, no interpolation, truncation-aware), the description covers the edge cases an agent must understand to read the data correctly. An output schema exists, yet the extra disclosure about result blocks and truncation is warranted and present, so nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is a single parameter with 100% schema description coverage, so the schema already documents cve_id. The description adds only a concrete example format (CVE-2023-44487), matching the schema example rather than extending it. Baseline 3 applies when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb and resource: it returns how one CVE's EPSS score has changed over time, and it even defines EPSS (FIRST's exploit-prediction probability, 0 to 1, with percentile). No sibling tool (get_cve, cve_intel, cve_summary, etc.) deals with EPSS change history, so the purpose is unambiguously distinct from every alternative offered.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives strong interpretive rules ('Pass a CVE ID like CVE-2023-44487', 'Never interpolate it into a daily series', what a missing point means), which shape correct use. However it never states when to reach for this tool versus cve_intel, cve_summary or get_cve, so tool selection guidance is only implied by the resource type.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

exposure_radarExposure radar totalsA
Read-onlyIdempotent
Inspect

Aggregate totals from EchelonGraph's internet-exposure radars, each refreshed on its own schedule: internet-facing services running actively-exploited (CISA-KEV) CVEs, plus the ransomware-linked subset, derived from Shodan data; unauthenticated data stores and observability UIs, found through Shodan (LeakIX when Shodan query credits run low) and then confirmed by EchelonGraph's own identified check (not a pure read: on Redis it names its client, and on ClickHouse its query is recorded in the server's query log); leaked credentials sampled from public GitHub push events; and shadow AI services found through Certificate Transparency logs and Shodan and then checked by EchelonGraph's identified probes. It also gives MCP-server counts: hostnames named like an MCP server in EchelonGraph's own Certificate Transparency feed (no Shodan data), each counted once by its latest verdict from EchelonGraph's identified MCP probe, which never sends tools/call. Every number in the result is labelled here and in the result's note by what it counts; a field this version cannot label is left out and named in the note. kev_exposure: kev_exposure.distinct_hosts counts distinct ip:port services, not machines (a machine answering on two ports counts twice), with at least one CISA-KEV-listed CVE on record, and kev_exposure.ransomware_hosts those with a ransomware-linked one; kev_exposure.kev_cves_exposed and kev_exposure.ransomware_cves count distinct CVEs with at least one such service; kev_exposure.correlations counts service×CVE pairs, not services, so a service with three KEV CVEs counts three times. kev_exposure.top_products, kev_exposure.top_countries and kev_exposure.top_cves rank up to 12 products, 10 countries and 12 CVEs by those services; kev_exposure.top_cves[].cvss_v3_score and kev_exposure.top_cves[].epss_score are the highest CVSS v3 base score and EPSS probability recorded on that CVE's observations. kev_exposure.trend counts service×CVE pairs still on record by the week in which each was first recorded, over 12 weeks, so earlier weeks read low. kev_exposure.newest_kev lists the 15 CVEs that EchelonGraph's CVE records most recently mark as CISA-KEV-listed, each with an exposure_state: exposed, where kev_exposure.newest_kev[].exposed_hosts counts distinct ip:port services on record with it; or not_assessed, where the API's answer holds no measurement for that CVE (its 0 is not one) and no count is relayed, and cve_exposure says per CVE whether the radar tracks it. kev_exposure.newest_kev[].cvss_v3_score and kev_exposure.newest_kev[].epss_score are the CVE record's CVSS v3 base score and EPSS probability. exposed_databases: exposed_databases.distinct_hosts counts distinct ip:port services the check confirmed answering without authentication, and exposed_databases.engines the distinct engine types among them; exposed_databases.top_engines and exposed_databases.top_countries rank up to 15 engines and 10 countries by those services. exposed_databases.pii_likely and exposed_databases.pci_likely count services whose schema names (never record values) pass a high-confidence, precision-first gate for personal or payment-card data, so a service outside them is not shown to hold no such data. exposed_databases.window.from and exposed_databases.window.to are timestamps, not counts: when EchelonGraph's check last confirmed the oldest and the newest of the services counted, a span of checks made at different times; with a counted service that has no such time on record there is no window. leaked_credentials: leaked_credentials.total counts (repository, secret) pairs, not distinct secrets, so one secret in three repositories counts three times; leaked_credentials.distinct_secrets counts each secret once and leaked_credentials.distinct_repos counts repositories; leaked_credentials.top_providers and leaked_credentials.top_types rank up to 15 providers and secret types by those pairs. None is validated: each is a credential-shaped string that passed EchelonGraph's filters, at most structurally checked and never tested against its provider. leaked_credentials.window.from and leaked_credentials.window.to are timestamps, not counts: when EchelonGraph's detector last found the oldest and the newest of the pairs counted. Each of those three radars also carries generated_at, when the API computed its totals, and, when the API can tell, last_run_at. kev_exposure.last_run_at, exposed_databases.last_run_at and leaked_credentials.last_run_at are timestamps, not counts: each is when that radar last completed a check, a cycle whose reads succeeded, among them a Shodan search (for exposed_databases, or its LeakIX fallback) that answered at least one query, or for leaked_credentials a read of the public GitHub event stream. A cycle that read nothing does not move it, and it is not the time of every record a radar's numbers count, which cover everything still on record, not only what the last check found. A radar whose answer carries no last_run_at has none in the result, and the note says nothing about it. shadow_ai: the result is regrouped by what each number counts. shadow_ai.confirmed_exposed counts services EchelonGraph's probes found answering without an authentication gate (liveness active, or rechecking during a re-check): confirmed_exposed.total is the sum of confirmed_exposed.by_category, and confirmed_exposed.last_24h counts those first recorded in the last 24 h. Of the shadow_ai numbers, only confirmed_exposed counts exposed services. confirmed_exposed.window.from and confirmed_exposed.window.to are timestamps, not counts: when EchelonGraph's verifier ran the probe that last decided the oldest and the newest of those services, a span of probes made at different times. shadow_ai.observed counts every Certificate Transparency or Shodan observation on record, whatever its verification state: its numbers are observed, not exposed. They are observed.total; observed.by_category (the same observations by category); observed.last_24h (those first recorded in the last 24 h); observed.trend_30d (observations per UTC day over the last 30 days); and observed.top_products, observed.top_countries and observed.top_issuers (up to ten products, countries and issuers ranked by observations, where an issuer is the certificate's CA for a Certificate Transparency observation and the hosting operator Shodan reports for a Shodan one). shadow_ai.authentication counts observations by probe outcome: authentication.observed where a probe observed an authentication gate (a 401/403, a login page or an auth marker), and authentication.not_determined where the service answered but no probe could tell. Neither authentication count is part of confirmed_exposed, and observed.total minus confirmed_exposed.total is not a count of secured services. The shadow-AI poller block carries only running and last_run_at: last_run_at is when the radar's leader last completed a Certificate Transparency (crt.sh) cycle, and its running is true only when that was within 30 minutes of the answer. mcp_servers: counts and timestamps only, no hostname. mcp_servers.total counts hostnames the AI-exposure radar has checked for an MCP server, each once by its latest verdict on record, and not every one is an MCP server; EchelonGraph's own control servers are left out, and mcp_servers.own_controls_excluded counts them. mcp_servers.total is mcp_servers.protected plus mcp_servers.pending_readjudication plus mcp_servers.not_assessed. mcp_servers.protected counts hostnames whose /mcp endpoint asked for credentials and whose OAuth protected-resource metadata validated under RFC 9728; mcp_servers.prm_via divides them by where that document was found: mcp_servers.prm_via.header, mcp_servers.prm_via.wellknown_path and mcp_servers.prm_via.wellknown_root. mcp_servers.pending_readjudication counts verdicts of a rule since replaced, not yet re-checked. mcp_servers.not_assessed counts the rest, whose protection the radar could not assess (not assessed does not mean unprotected), and mcp_servers.not_assessed_by_reason puts each in one bucket. mcp_servers.not_assessed_by_reason.identified_no_challenge holds servers that identified themselves as MCP servers and did not ask for credentials at the handshake. That is normal in MCP: authorization is optional in the spec, and a server can enforce it at tools/call instead, which EchelonGraph never sends, so this bucket is not a finding of exposure. mcp_servers.not_assessed_by_reason.resource_mismatch, mcp_servers.not_assessed_by_reason.cross_origin_pointer, mcp_servers.not_assessed_by_reason.bare_challenge_no_prm, mcp_servers.not_assessed_by_reason.pointer_unreachable, mcp_servers.not_assessed_by_reason.pointer_invalid, mcp_servers.not_assessed_by_reason.no_authorization_servers, mcp_servers.not_assessed_by_reason.wellknown_unreachable and mcp_servers.not_assessed_by_reason.metadata_invalid hold endpoints that asked for credentials but whose RFC 9728 metadata did not validate, by why, so none of them is shown to lack protection; mcp_servers.not_assessed_by_reason.challenge_unadjudicated holds endpoints that asked for credentials before that check existed, not yet re-checked. mcp_servers.not_assessed_by_reason.no_http_answer holds hostnames that gave no HTTP answer, and mcp_servers.not_assessed_by_reason.not_identified_as_mcp hostnames whose HTTP answer identified no MCP server. mcp_servers.era divides every counted hostname by protocol era: mcp_servers.era.legacy; mcp_servers.era.dual, a lower bound; mcp_servers.era.modern, not proven modern-only; mcp_servers.era.unknown; and mcp_servers.era.not_measured, recorded before the era probe and not re-checked since. mcp_servers.transport divides them by transport: mcp_servers.transport.streamable_http, mcp_servers.transport.legacy_sse, mcp_servers.transport.unknown and mcp_servers.transport.not_measured. mcp_servers.window.from and mcp_servers.window.to are when the oldest and the newest of the verdicts counted were last checked. mcp_servers.last_run_at is a timestamp, not a count: when the AI-exposure radar, which checks other AI services too, last completed a check; mcp_servers.enabled is whether one completed within 45 minutes of the answer, and mcp_servers.counted_at is when the API read the counts. A partition whose buckets do not add up to the count it divides is left out and named; an answer that does not say it is the MCP-server counts, or whose mcp_servers.total, mcp_servers.protected, mcp_servers.pending_readjudication and mcp_servers.not_assessed are missing or contradict each other, is a failure. Shodan data is owned by Shodan, which holds its copyright (© Shodan). Its structured result's state is not_assessed with measured_at null: every radar answered, but none gives one time at which what it counts was observed (mcp_servers dates its verdicts at most by a window, mcp_servers.window), so no count is presented as a dated measurement; each count is still relayed, labelled, as what that radar holds on record. freshness gives each radar's last_run_at (and running for shadow_ai, enabled for mcp_servers) where the API serves one; coverage names the radars that answered; data is the relayed result above. The result's last text block repeats the structured result without data (the first text block) and without the note's sentences (the text block before it), with which notes ends. Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Despite readOnlyHint=true, the description discloses that this is 'not a pure read' because probes name their client on Redis and are logged in ClickHouse's query log, plus data provenance (Shodan, LeakIX fallback, Certificate Transparency), that the MCP probe never sends tools/call, refresh cadences, staleness windows and the failure conditions for the MCP block. It also spells out truncation behavior past 30,000 characters of JSON and what the state=not_assessed result means. This is far beyond what the annotations convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded, but the body is an enormous single-paragraph run-on that prose-documents essentially the entire output schema field by field, for a tool that already has an output schema. 'timestamps, not counts' and similar counting disclaimers are repeated many times, so much of the text is redundant rather than additive.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a high-complexity multi-radar aggregate, the description covers provenance, side effects, per-field counting semantics, staleness/refresh semantics, failure detection, and response-truncation behaviour. An agent can interpret the returned counts correctly without opening the output schema, so nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the schema has nothing to document and there is no parameter behaviour to add meaning to. Baseline for a parameterless tool is 4; the description cannot score higher because no parameter semantics exist to clarify.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource ('aggregate totals from EchelonGraph's internet-exposure radars') and enumerates the exact content (KEV exposure, exposed databases, leaked credentials, shadow AI, MCP-server counts), which lets an agent distinguish this broad aggregate endpoint from the per-CVE siblings like get_cve or cve_exposure. It is clear and specific, but it never explicitly contrasts itself with those sibling tools, so it falls short of full sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: the tool is the overview of radar totals, but there is no sentence saying when to reach for this instead of cve_exposure, kev_recent or search_cves. It does supply substantial interpretation guidance (e.g. a service outside pii_likely is not shown to hold no such data; a missing last_run_at means the note says nothing), which is helpful context but not when-to-use routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_cveCVE detailA
Read-onlyIdempotent
Inspect

One CVE's record: description, severity, cvss_v3_score, cvss_v4_score and cvss_v4_severity (when the record has a CVSS v4 score), echelongraph_score and echelongraph_severity with score_confidence (EchelonGraph's multi-source score) and score_assessed (whether EchelonGraph has scored it), epss_score and epss_percentile, CISA-KEV status (kev_listed, kev_added_date, and kev_ransomware for known ransomware-campaign use), ghsa_id (GitHub GHSA), references, cpe_match (the CPE criteria as one flat list) and cpe_configurations (NVD's configurations as NVD sent them, with each AND/OR operator, negate, versionStartExcluding and matchCriteriaId; absent where EchelonGraph has stored none, which is not a finding that no product is affected), published, modified and updated_at; each field only where the record has it. Pass a CVE ID like CVE-2023-44487. echelongraph_score, echelongraph_severity and echelongraph_risk are EchelonGraph's score only when score_assessed is true. With score_assessed false the CVE is NOT YET SCORED, not scored 0: any of those three it carries (0, NONE, 0) is a placeholder, not a rating, and does not mean the CVE is harmless; the API may leave them out instead, score_confidence is NONE, and score_unassessed_reason says why (a rejected record, withdrawn by its numbering authority, is never scored, and the note says NOT SCORED). The note labels each such CVE NOT YET SCORED: report it that way, never as a score of 0. An answer with no score_assessed (an API older than that field) does not say whether the CVE was scored, the note says so, and a 0 there is not a rating either. Its structured result carries state (measured), measured_at, method, coverage, freshness (null: the feed serves no poll-completion time) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends. Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole. Cut, each list in the record keeps its first entries, and the note names each list cut with its full length.

ParametersJSON Schema
NameRequiredDescriptionDefault
cve_idYesa CVE ID, e.g. CVE-2023-44487

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly/idempotent annotations, it discloses the critical unscored-CVE semantics (placeholders of 0/NONE that must not be read as a rating), the score_assessed gate, and the 30,000-character truncation behavior with per-list cutting. These are exactly the behavioral traits an agent needs and none are derivable from the annotations or schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The prose is dense and comma-chained, and a large portion explains return-value layout (text blocks, data duplication, truncation), which overlaps the output schema the agent already receives. The genuinely load-bearing sentences about unassessed scores are buried mid-paragraph, so front-loading could be improved.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only detail fetch with an output schema, the description supplies the interpretive context the schema cannot: unassessed-score placeholders, score_confidence NONE, score_unassessed_reason, and truncation handling. Nothing an agent needs to call or correctly interpret the result is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% for the single cve_id parameter, so the schema already documents type and format; the description's example ID duplicates the schema's own example. Nothing additional about ID syntax or validation is added, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening clause 'One CVE's record' states a specific verb-plus-resource, and the description enumerates the fields returned and the one input (a CVE ID) so the agent can distinguish it from list-oriented siblings like search_cves and cve_summary. There is no ambiguity about what the tool fetches.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It tells the agent what to pass ('a CVE ID like CVE-2023-44487') and how to interpret results, but never states when to choose this over cve_summary, cve_intel, or search_cves. Usage is implied by the single-record scope rather than stated against alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_cweCWE and its CVEsA
Read-onlyIdempotent
Inspect

One CWE (weakness class) and the CVEs classified under it. Returns cwe_id, name and description (from the MITRE CWE catalog EchelonGraph embeds, version catalog_version), total (the active CVEs in EchelonGraph's feed that an NVD, GitHub or CVE.org record classifies under it, rejected and reserved records left out), and cves, one page of 50: each with cve_id, severity, cvss_v3_score, echelongraph_score, echelongraph_severity, score_assessed, kev_listed, published and a shortened description. order says how the rows are sorted (CISA-KEV-listed first, then EchelonGraph score); an answer without order does not state its order, and the note says so. page is the page served, page_size its size and max_page the last page the API serves: a later page is answered as max_page, so past max_page pages total counts CVEs no page lists. echelongraph_score is EchelonGraph's score only when score_assessed is true; the note labels each row that is NOT YET SCORED. A total of 0 says that no CVE in EchelonGraph's feed is classified under that CWE, not that none exists. Pass cwe_id like CWE-79 (or 79) and an optional page (1-200). Its structured result carries state (measured), measured_at (null), method, coverage (total, returned, page, page_requested, page_size, max_page), freshness (null) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends. Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNopage of 50 CVEs (default 1, max 200)
cwe_idYesa CWE ID, e.g. CWE-79 (or 79)

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the read-only, idempotent and open-world annotations, the description discloses important behavioral details: pagination past max_page is coerced to max_page, total 0 has a specific meaning, echelongraph_score is only meaningful when score_assessed is true, and the structured result's handling of text-block truncation is explained.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with purpose, but it is excessively long and runs several dense clauses together. Much of the return-field and structured-result detail duplicates the output schema, and the text-block mechanics add significant length without proportionate selection benefit.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity, annotations, and existing output schema, the description is more than complete. It covers output structure, pagination edge cases, scoring caveats, truncation behavior, and result-shape details that an agent would need to interpret responses correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both parameters. The description repeats accepted cwe_id formats and the page range without adding substantive meaning beyond the schema's own descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a precise verb-and-resource statement: 'One CWE (weakness class) and the CVEs classified under it.' It clearly distinguishes this tool from siblings like get_cve and search_cves by specifying it returns one CWE plus its classified CVEs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the return contents and the required cwe_id parameter, but the description never explicitly states when to choose this tool over alternatives such as get_cve or search_cves, nor does it name any exclusions or prerequisites.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_vendor_advisoryVendor advisory detailA
Read-onlyIdempotent
Inspect

One vendor advisory in full, by vendor and the vendor's advisory ID (the vendor and vendor_advisory_id fields of a row from search_vendor_advisories or vendor_advisories_for_cve): title, description, severity, cvss_v3_score, cve_ids and known_cve_ids (those with a record in EchelonGraph's CVE feed), affected_products, remediation, references, vendor_modified_at, and withdrawn_at and withdrawn_reason when the vendor withdrew it. Each advisory carries vendor_published_at (the vendor's date), our_first_seen_at (when EchelonGraph first recorded it) and withdrawn (true: the vendor rescinded it; the note names each such advisory). coverage.vendor_window is that vendor's window in what EchelonGraph holds: vendor, advisories (how many EchelonGraph holds from that vendor), earliest_vendor_published_at and latest_vendor_published_at (the earliest and latest vendor_published_at among them, null when none is held) and history_backfill: complete (the vendor's published history has been read back as far as its source goes), in_progress or not_started (it is still being read, so the vendor's older advisories are not all held yet), or not_supported (EchelonGraph has no history read for that vendor, so what it holds is what the vendor's feed has carried); null when the windows could not be read or carry none for that vendor. measured_at is our_first_seen_at. Its structured result carries state (measured), measured_at, method, coverage, freshness (null: the answer carries no poll-completion time) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends. Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole.

ParametersJSON Schema
NameRequiredDescriptionDefault
vendorYesthe vendor slug, e.g. microsoft, redhat, github
advisory_idYesthe vendor's advisory ID, e.g. RHSA-2024:1234 or GHSA-xxxx-xxxx-xxxx

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only, idempotent, open-world, and non-destructive behavior. The description adds substantial behavioral detail beyond annotations: the result fields, coverage.vendor_window semantics, freshness, measured_at, structured result shape, and truncation behavior past 30,000 characters including what the first text block contains and where full data lives.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core purpose is front-loaded in the first clause, but the remainder is a dense wall of implementation details about return fields, coverage windows, structured results, and truncation. Given that an output schema already exists, much of this is redundant, making the description less concise than it could be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only single-advisory fetch with annotations and an output schema, the description is more than complete: it covers purpose, argument provenance, returned advisory fields, coverage metadata, structured result behavior, and text truncation. No essential context for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents the vendor slug and advisory ID formats with examples. The description adds meaning by identifying vendor and advisory_id as fields from rows returned by search_vendor_advisories or vendor_advisories_for_cve, helping the agent know where to obtain them.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'One vendor advisory in full, by vendor and the vendor's advisory ID'. It distinguishes this detail-fetch tool from sibling search/list tools by naming search_vendor_advisories and vendor_advisories_for_cve as sources for the input IDs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clarifies that the vendor and advisory_id arguments are the corresponding fields from search_vendor_advisories or vendor_advisories_for_cve, implying it is used after finding an advisory. It gives clear context but does not state explicit when-not conditions or direct alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

kev_recentRecent CISA KEV additionsA
Read-onlyIdempotent
Inspect

The CVEs CISA has added to its Known Exploited Vulnerabilities (KEV) catalog, newest first, from EchelonGraph's copy of that catalog, which polls CISA's feed every 5 minutes. Each row in kev gives cve_id, kev_added_date (CISA's dateAdded), kev_due_date, kev_vendor, kev_product, kev_vuln_name and kev_ransomware (known ransomware-campaign use), EchelonGraph's severity, cvss_v3_score, epss_score, epss_percentile and eg_kev_tier for the CVE, and our_first_seen_kev, when EchelonGraph's poller first recorded the CVE entering the catalog (null where no such record exists). Filter by since and until (YYYY-MM-DD, inclusive, on kev_added_date; an RFC 3339 timestamp, such as the kev_added_date 2024-04-12T00:00:00Z that CVE records carry, is read as the date written in it, with the time and offset dropped, and anything else is refused), ransomware, and vendor (an exact, case-insensitive match on kev_vendor); page with limit (1 to 200, default 50) and cursor, passing back the previous page's next_cursor with the same filters. Rows within one date are ordered by cve_id. total counts the CVEs matching the filters; kev_listed_total counts every CVE EchelonGraph holds as KEV-listed, and catalog.catalog_count is CISA's own count in the catalog last fetched, so a gap between the two is entries not yet in EchelonGraph's CVE table, which no page returns. CISA's requiredAction and shortDescription are not returned. Its structured result carries state (measured), measured_at (our last successful fetch of CISA's feed, null when the API does not give it), method, coverage (the CISA KEV catalog: total, returned, kev_listed_total, catalog_count, limit, has_more), freshness (last_successful_fetch_at, catalog_version, date_released) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends. Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole. Cut, each row keeps fewer fields, cve_id, kev_added_date, kev_vendor and kev_ransomware at least, or rows are left out, and next_cursor still continues after the last row of the page, not of the text.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNopage size (default 50, max 200)
sinceNoearliest kev_added_date to include, YYYY-MM-DD (an RFC 3339 timestamp is read as the date written in it)
untilNolatest kev_added_date to include, YYYY-MM-DD (an RFC 3339 timestamp is read as the date written in it)
cursorNonext_cursor from the previous page
vendorNoCISA vendorProject, an exact case-insensitive match, e.g. 'Microsoft'
ransomwareNotrue: only CVEs with known ransomware-campaign use; false: only those without

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, open-world), and the description adds substantial operational context: the catalog is polled every 5 minutes, the gap between total, kev_listed_total and catalog_count means entries not yet in EchelonGraph's CVE table, requiredAction and shortDescription are not returned, and output is truncated past 30,000 characters with a documented fallback.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and scope are front-loaded, and most sentences carry load-bearing detail. But the single dense paragraph of run-on clauses is hard to scan, and the output/truncation discussion dominates roughly half the text, diluting the key selection signals.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a paged, filtered read tool with 6 optional params and an existing output schema, the description is thorough: it explains filter semantics, paging continuity, coverage counters, freshness metadata, the shape of the structured result and text blocks, and how truncation degrades fields. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema: inclusive date semantics on kev_added_date, RFC 3339 timestamps being reduced to the written date while anything else is refused, exact case-insensitive vendor matching on kev_vendor, limit bounds/default, and the requirement to pass next_cursor back with the same filters. Ordering by cve_id within a date is also documented only here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'The CVEs CISA has added to its Known Exploited Vulnerabilities (KEV) catalog, newest first.' It also names the data source and refresh cadence, so an agent can immediately distinguish it from siblings like search_cves or cve_intel.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is strongly implied by 'newest first' plus the since/until, ransomware and vendor filters, and paging mechanics are spelled out. However, the description never says when to choose this tool over siblings such as search_cves or cve_summary, and gives no explicit exclusions, so routing is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_cvesSearch CVEsA
Read-onlyIdempotent
Inspect

Search/list CVEs from EchelonGraph's CVE feed (NVD + MITRE-CNA pre-NVD + CISA-KEV + EPSS + GitHub GHSA, each polled on a schedule). Filter by severity, minimum CVSS, free text, and sort; page with limit and offset. Returns cves, each with cve_id, severity, cvss_v3_score, echelongraph_score and score_assessed (whether EchelonGraph has scored it), epss_score and kev_listed where the record has them, and the list's total, total_counted (false: the matches were not counted, so total is not a count), total_is_lower_bound (true: at least total), search_relaxed (true: a phrase was relaxed to all of its words), limit and offset. echelongraph_score, echelongraph_severity and echelongraph_risk are EchelonGraph's score only when score_assessed is true. With score_assessed false the CVE is NOT YET SCORED, not scored 0: any of those three it carries (0, NONE, 0) is a placeholder, not a rating, and does not mean the CVE is harmless; the API may leave them out instead, score_confidence is NONE, and score_unassessed_reason says why (a rejected record, withdrawn by its numbering authority, is never scored, and the note says NOT SCORED). The note labels each such CVE NOT YET SCORED: report it that way, never as a score of 0. An answer with no score_assessed (an API older than that field) does not say whether the CVE was scored, the note says so, and a 0 there is not a rating either. Its structured result carries state (measured), measured_at, method, coverage, freshness (null: the feed serves no poll-completion time) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends. coverage repeats total, total_counted, total_is_lower_bound, search_relaxed, limit and offset, and gives returned, the rows in this page. Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole. Cut, each row keeps at least the fields named above and the first 200 characters of its description (100 on a page too long for that), or rows are left out and the note gives the offset to call next.

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNosort order (default: published)
limitNopage size (default 20, max 50)
offsetNorows to skip (default 0)
searchNofree-text search (product, vendor, or keyword, e.g. 'tomcat')
min_cvssNominimum CVSS score
severityNofilter to one severity

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish the safe read-only, idempotent, open-world profile, and the description goes well beyond them: it explains score_assessed semantics (a false value is NOT YET SCORED, not 0), search_relaxed, lower-bound totals, truncated text past 30,000 characters, and the fallback page/offset behavior for cut rows. This is unusually rich disclosure of return-shape and edge-case behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is enormously oversized: the score_assessed/NOT-YET-SCORED caveat is restated three or four times, and text-truncation behavior is re-explained at length. The first sentence is well front-loaded, but most of the body is repetitive rather than each sentence earning its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a search tool with six optional params and an existing output schema, the description is more than complete: it documents result fields, scoring caveats, coverage counts, and truncation fallbacks beyond what the schema provides. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all six parameters (sort, limit, offset, search, min_cvss, severity). The description restates the same filters without adding format or syntax detail, so a baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Search/list CVEs from EchelonGraph's CVE feed') and names the five underlying sources (NVD, MITRE-CNA, CISA-KEV, EPSS, GHSA). An agent can distinguish it from siblings like get_cve or cve_summary since this is the list/search entry point.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description covers how to filter and page ('Filter by severity, minimum CVSS, free text, and sort; page with limit and offset'), which implies usage, but never states when to prefer this tool over siblings such as cve_intel or get_cve. No explicit alternatives or when-not-to-use conditions are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_vendor_advisoriesSearch vendor advisoriesA
Read-onlyIdempotent
Inspect

Search or list vendor-published advisories, newest first. A query of 3 or more characters is matched case-insensitively as a substring of each advisory's title, description, vendor name, vendor_advisory_id, affected_products and cve_ids (search_match substring). A query of 1 or 2 characters matches whole words only (search_match word): it must equal, ignoring case, a whole word (a run of letters and digits) of one of those, so xz finds xz-utils but not xzibit, and a 1- or 2-character query with any other character, such as c#, matches nothing. Filter by vendor (slug), by severity band, and by whether the advisory names any CVE ID. Advisories their vendor withdrew are left out. Returns advisories, each with vendor, vendor_advisory_id, title, severity, cvss_v3_score, cve_ids, summary and affected_products where present, and the answer's total, total_capped, limit, offset, search_applied and search_match. A search counts at most 1,000 matches: past that, total is 1000 and total_capped is true, which means 1,000 or more (the note writes 1,000+), never exactly 1,000; paging past it still works. Without a query, total is the exact count and total_capped is false. Each advisory carries vendor_published_at (the vendor's date), our_first_seen_at (when EchelonGraph first recorded it) and withdrawn (true: the vendor rescinded it; the note names each such advisory). The query is sent in a request header, never in the URL. coverage repeats total, total_capped, limit, offset, search_applied and search_match, and gives returned, the rows in this page, and vendor_windows, each vendor's window in what EchelonGraph holds (only that vendor's when vendor is given): vendor, advisories (how many EchelonGraph holds from that vendor), earliest_vendor_published_at and latest_vendor_published_at (the earliest and latest vendor_published_at among them, null when none is held) and history_backfill: complete (the vendor's published history has been read back as far as its source goes), in_progress or not_started (it is still being read, so the vendor's older advisories are not all held yet), or not_supported (EchelonGraph has no history read for that vendor, so what it holds is what the vendor's feed has carried). An advisory a vendor published before its earliest_vendor_published_at is not held, so no advisory from a vendor is not a finding that it published none. measured_at is null. Its structured result carries state (measured), measured_at, method, coverage, freshness (null: the answer carries no poll-completion time) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends. Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole. Cut, each row keeps vendor, vendor_advisory_id, title, severity and cve_ids at least, its strings and lists shortened, or rows are left out and the note gives the offset to call next.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNopage size (default 20, max 50)
queryNofree text, at most 100 bytes: a product, an advisory ID, a CVE ID or a keyword, e.g. 'exchange server'; 1 or 2 characters match whole words only
offsetNorows to skip (default 0)
vendorNoa vendor slug, e.g. microsoft, redhat, github
has_cveNotrue: only advisories naming a CVE; false: only those naming none
severityNoone severity band

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only cover safety (readOnly, idempotent, openWorld, non-destructive), so the description carries extra weight and delivers it: withdrawn advisories are excluded, searches cap at 1,000 matches with total_capped semantics, and JSON is truncated past 30,000 characters. It also discloses coverage freshness/history_backfill states and the note/text-block structure, far beyond the annotation bar.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The opening is well front-loaded, but the body is a dense multi-hundred-word blob with no structural breaks, and it re-specifies return fields and the coverage/notes duplication even though an output schema already exists. Much is justified by complexity, yet several sentences restate rather than add.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool this complex it leaves little unsaid: matching rules, filters, exclusion of withdrawn advisories, caps, paging, coverage windows and truncation behavior are all addressed. An agent has enough to call and interpret it correctly, with the output schema covering the return shape.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description adds real query semantics beyond the schema: 3+ characters match as a case-insensitive substring, 1-2 characters match whole words only (xz finds xz-utils but not xzibit, c# matches nothing). That meaningfully extends the schema's terse 'query' text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence gives a specific verb and resource ('Search or list vendor-published advisories, newest first') with ordering/scoping baked in. It clearly reads as a broad advisory-search tool, but it never explicitly distinguishes itself from close siblings like get_vendor_advisory or vendor_advisories_for_cve.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description extensively explains how filtering works (vendor slug, severity band, has_cve) and how queries match, which implies when the tool is applicable. However, it never states when to reach for this tool over alternatives such as search_cves or get_vendor_advisory, and gives no when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vendor_advisories_for_cveVendor advisories for one CVEA
Read-onlyIdempotent
Inspect

The vendor-published advisories that name one CVE, newest first, at most 20: for each, vendor, vendor_display_name, vendor_advisory_id, title, severity and cvss_v3_score where the vendor gives them. Covers the vendor feeds EchelonGraph polls, for example Microsoft MSRC, Red Hat, Cisco, Palo Alto Networks and GitHub GHSA; an empty answer means that none of the advisories EchelonGraph holds from those feeds names the CVE, not that no vendor published one (see vendor_windows and vendors_not_fully_held). Each advisory carries vendor_published_at (the vendor's date), our_first_seen_at (when EchelonGraph first recorded it) and withdrawn (true: the vendor rescinded it; the note names each such advisory). Pass a CVE ID like CVE-2024-21412. coverage gives returned, cap and at_cap (true: the answer is full, so there may be more); cve_year, the year in the CVE ID; vendor_windows, each vendor's window in what EchelonGraph holds: vendor, advisories (how many EchelonGraph holds from that vendor), earliest_vendor_published_at and latest_vendor_published_at (the earliest and latest vendor_published_at among them, null when none is held) and history_backfill: complete (the vendor's published history has been read back as far as its source goes), in_progress or not_started (it is still being read, so the vendor's older advisories are not all held yet), or not_supported (EchelonGraph has no history read for that vendor, so what it holds is what the vendor's feed has carried); and vendors_not_fully_held, the vendors with no advisory in the answer of which EchelonGraph holds none, whose earliest held advisory is dated after 1 January of cve_year, or whose history is still being read, which the note names. An advisory a vendor published before its earliest_vendor_published_at is not held, so no advisory from a vendor is not a finding that it published none. vendor_windows and vendors_not_fully_held are null when the windows could not be read, and the note says so. measured_at is null. Its structured result carries state (measured), measured_at, method, coverage, freshness (null: the answer carries no poll-completion time) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends. Past 30,000 characters of JSON, the first text block holds data cut to fit, and the note says what the cut leaves out and where to read it (TEXT CUT); data in the structured result always holds it whole. Cut, each row keeps vendor, vendor_advisory_id, title, severity and cve_ids at least, its strings and lists shortened.

ParametersJSON Schema
NameRequiredDescriptionDefault
cve_idYesa CVE ID, e.g. CVE-2024-21412

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only/idempotent/open-world safety, yet the description adds substantial behavior the annotations cannot: the 20-row cap, newest-first ordering, withdrawn-advisory flagging, null semantics for measured_at/freshness, the coverage object (returned/cap/at_cap), and the 30,000-character truncation rule including what the cut preserves and where the whole data lives. This is unusually rich disclosure for a read-only tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded, but the body is one enormous run-on paragraph that buries return-shape details, truncation rules and null semantics together with no headings or bullets. Much of that material duplicates the output schema, so the size is not earning its place in the description.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a single required param, an existing output schema and a complex response (coverage, vendor_windows, vendors_not_fully_held, notes), the description is thorough about nulls, truncation and empty-result interpretation. It is nearly over-complete; the only gap is that it never explicitly routes the agent against sibling advisory tools.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the single cve_id parameter is already documented, and the description's 'Pass a CVE ID like CVE-2024-21412' merely repeats the schema example. It does add the derived cve_year concept, but that is a response field rather than input guidance, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource+scope: the vendor-published advisories naming one CVE, newest first, capped at 20. It also enumerates the covered feeds (MSRC, Red Hat, Cisco, Palo Alto, GHSA), which separates it from siblings like get_vendor_advisory and search_vendor_advisories without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by 'the vendor-published advisories that name one CVE' and the caveat that an empty answer means EchelonGraph holds none, not that no vendor published one. However it never explicitly contrasts this tool with get_vendor_advisory or search_vendor_advisories, and its references to vendor_windows/vendors_not_fully_held are response fields, not alternative tools, so the agent must infer when to prefer this call.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updates
    • Changedcheck_sbom1 field changed
      • changedInput schema / properties / sbom / description
        Previous value: -"a CycloneDX JSON or SPDX JSON document, as JSON text or as an object; its purls are read here and only they are sent"New value: +"a CycloneDX JSON or SPDX JSON document, as JSON text or as an object; its purls are read by this MCP server and only they are sent to the API; over the hosted endpoint (mcp.echelongraph.io) the document is the request body"
    • Changedcve_summary1 field changed
      • changedOutput schema / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "description": "What the answer covers; null where the answer says nothing about it.",
        -        "type": "null"
        -      },
        -      "data": {
        -        "additionalProperties": {},
        -        "properties": {
        -          "poller": {
        -            "anyOf": [
        -              {
        -                "additionalProperties": {},
        -                "properties": {
        -                  "cves_ingested": {
        -                    "description": "CVE records this instance's NVD poller wrote since the instance last started: never the feed's size or intake.",
        -                    "type": [
        -                      "number",
        -                      "null"
        -                    ]
        -                  },
        -                  "cves_skipped": {
        -                    "description": "CVE records this instance's NVD poller skipped since the instance last started.",
        -                    "type": [
        -                      "number",
        -                      "null"
        -                    ]
        -                  },
        -                  "http_retries": {
        -                    "description": "HTTP retries this instance's NVD poller made since the instance last started.",
        -                    "type": [
        -                      "number",
        -                      "null"
        -                    ]
        -                  },
        -                  "interval": {
        -                    "description": "How often this instance's NVD poller polls.",
        -                    "type": [
        -                      "string",
        -                      "null"
        -                    ]
        -                  },
        -                  "last_poll_at": {
        -                    "description": "When this instance's NVD poller last polled: never the feed's freshness.",
        -                    "type": [
        -                      "string",
        -                      "null"
        -                    ]
        -                  },
        -                  "last_poll_dur_ms": {
        -                    "description": "How long that poll took, in milliseconds.",
        -                    "type": [
        -                      "number",
        -                      "null"
        -                    ]
        -                  },
        -                  "poll_count": {
        -                    "description": "Polls this instance's NVD poller made since the instance last started.",
        -                    "type": [
        -                      "number",
        -                      "null"
        -                    ]
        -                  },
        -                  "poll_errors": {
        -                    "description": "Polls of this instance's NVD poller that failed since the instance last started: never the feed's reliability.",
        -                    "type": [
        -                      "number",
        -                      "null"
        -                    ]
        -                  }
        -                },
        -                "type": "object"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ],
        -            "description": "poller holds the in-memory counters of the NVD poller of the one API instance that answered (cves_ingested, cves_skipped, http_retries, poll_count, poll_errors, last_poll_at, last_poll_dur_ms, interval), counted since that instance last started and zeroed on every restart: they describe that instance, never the feed's size, intake, reliability or freshness. Whenever the answer carries poller the note says so."
        -          },
        -          "summary": {
        -            "additionalProperties": {},
        -            "properties": {
        -              "critical": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "high": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "last_updated": {
        -                "type": [
        -                  "string",
        -                  "null"
        -                ]
        -              },
        -              "low": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "medium": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "none": {
        -                "description": "The active CVEs with no severity band from any source: CVEs not yet scored, not a severity rating of None.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "nvd_critical": {
        -                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Critical: NVD's label, as provenance, never EchelonGraph's severity band.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "nvd_high": {
        -                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is High: NVD's label, as provenance, never EchelonGraph's severity band.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "nvd_low": {
        -                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Low: NVD's label, as provenance, never EchelonGraph's severity band.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "nvd_medium": {
        -                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Medium: NVD's label, as provenance, never EchelonGraph's severity band.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "nvd_none": {
        -                "description": "Of the active CVEs total counts, those with no Critical, High, Medium or Low NVD CVSS severity label, many of them with an NVD CVSS v2 score instead: neither a count of CVEs rated None nor the count of CVEs with no severity, which is none.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "rejected": {
        -                "description": "The CVE records rejected (withdrawn) by their numbering authority, which total and every other count here leave out: withdrawn records, never vulnerabilities.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "total": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "unscored": {
        -                "description": "The same count as none, under its own name.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "anyOf": [
        -          {
        -            "description": "An RFC 3339 instant.",
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        -      },
        -      "method": {
        -        "description": "How the numbers were produced.",
        -        "type": "string"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        -        "enum": [
        -          "measured",
        -          "not_assessed"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "data"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "type": "null"
        -      },
        -      "error": {
        -        "additionalProperties": false,
        -        "properties": {
        -          "kind": {
        -            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        -            "enum": [
        -              "network",
        -              "timeout",
        -              "http",
        -              "not_json",
        -              "not_object",
        -              "invalid_input",
        -              "internal",
        -              "unexpected_shape",
        -              "radars"
        -            ],
        -            "type": "string"
        -          },
        -          "message": {
        -            "description": "The cause: the API's own message, or what went wrong.",
        -            "type": "string"
        -          },
        -          "path": {
        -            "description": "The API path requested, when a request was made.",
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "status": {
        -            "anyOf": [
        -              {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ],
        -            "description": "The HTTP status, when the API answered one."
        -          }
        -        },
        -        "required": [
        -          "kind",
        -          "path",
        -          "status",
        -          "message"
        -        ],
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "type": "null"
        -      },
        -      "method": {
        -        "type": "null"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        -        "enum": [
        -          "failed",
        -          "invalid_input"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "error"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "description": "What the answer covers; null where the answer says nothing about it.",
        +        "type": "null"
        +      },
        +      "data": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "poller": {
        +            "anyOf": [
        +              {
        +                "additionalProperties": {},
        +                "properties": {
        +                  "cves_ingested": {
        +                    "description": "CVE records this instance's NVD poller wrote since the instance last started: never the feed's size or intake.",
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  },
        +                  "cves_skipped": {
        +                    "description": "CVE records this instance's NVD poller skipped since the instance last started.",
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  },
        +                  "http_retries": {
        +                    "description": "HTTP retries this instance's NVD poller made since the instance last started.",
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  },
        +                  "interval": {
        +                    "description": "How often this instance's NVD poller polls.",
        +                    "type": [
        +                      "string",
        +                      "null"
        +                    ]
        +                  },
        +                  "last_poll_at": {
        +                    "description": "When this instance's NVD poller last polled: never the feed's freshness.",
        +                    "type": [
        +                      "string",
        +                      "null"
        +                    ]
        +                  },
        +                  "last_poll_dur_ms": {
        +                    "description": "How long that poll took, in milliseconds.",
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  },
        +                  "poll_count": {
        +                    "description": "Polls this instance's NVD poller made since the instance last started.",
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  },
        +                  "poll_errors": {
        +                    "description": "Polls of this instance's NVD poller that failed since the instance last started: never the feed's reliability.",
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  }
        +                },
        +                "type": "object"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "poller holds the in-memory counters of the NVD poller of the one API instance that answered (cves_ingested, cves_skipped, http_retries, poll_count, poll_errors, last_poll_at, last_poll_dur_ms, interval), counted since that instance last started and zeroed on every restart: they describe that instance, never the feed's size, intake, reliability or freshness. Whenever the answer carries poller the note says so. A poller field the answer sends in a JSON type other than the one described here is left out of data and named in the note, and a poller that is neither a JSON object nor null is left out whole: summary is relayed either way."
        +          },
        +          "summary": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "critical": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "high": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "last_updated": {
        +                "type": [
        +                  "string",
        +                  "null"
        +                ]
        +              },
        +              "low": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "medium": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "none": {
        +                "description": "The active CVEs with no severity band from any source: CVEs not yet scored, not a severity rating of None.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "nvd_critical": {
        +                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Critical: NVD's label, as provenance, never EchelonGraph's severity band.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "nvd_high": {
        +                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is High: NVD's label, as provenance, never EchelonGraph's severity band.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "nvd_low": {
        +                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Low: NVD's label, as provenance, never EchelonGraph's severity band.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "nvd_medium": {
        +                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Medium: NVD's label, as provenance, never EchelonGraph's severity band.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "nvd_none": {
        +                "description": "Of the active CVEs total counts, those with no Critical, High, Medium or Low NVD CVSS severity label, many of them with an NVD CVSS v2 score instead: neither a count of CVEs rated None nor the count of CVEs with no severity, which is none.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "rejected": {
        +                "description": "The CVE records rejected (withdrawn) by their numbering authority, which total and every other count here leave out: withdrawn records, never vulnerabilities.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "total": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "unscored": {
        +                "description": "The same count as none, under its own name.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "anyOf": [
        +          {
        +            "description": "An RFC 3339 instant.",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        +      },
        +      "method": {
        +        "description": "How the numbers were produced.",
        +        "type": "string"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        +        "enum": [
        +          "measured",
        +          "not_assessed"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "data"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "type": "null"
        +      },
        +      "error": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "kind": {
        +            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        +            "enum": [
        +              "network",
        +              "timeout",
        +              "http",
        +              "not_json",
        +              "not_object",
        +              "invalid_input",
        +              "internal",
        +              "unexpected_shape",
        +              "radars"
        +            ],
        +            "type": "string"
        +          },
        +          "message": {
        +            "description": "The cause: the API's own message, or what went wrong.",
        +            "type": "string"
        +          },
        +          "path": {
        +            "description": "The API path requested, when a request was made.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "status": {
        +            "anyOf": [
        +              {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "The HTTP status, when the API answered one."
        +          }
        +        },
        +        "required": [
        +          "kind",
        +          "path",
        +          "status",
        +          "message"
        +        ],
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "type": "null"
        +      },
        +      "method": {
        +        "type": "null"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        +        "enum": [
        +          "failed",
        +          "invalid_input"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "error"
        +    ],
        +    "type": "object"
        +  }
        +]
  2. 6 tool updates
    • Changedcheck_sbom1 field changed
      • changedOutput schema / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "batch_size": {
        -                "description": "The most purls one request carries (the API's cap per request).",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "batches": {
        -                "description": "Requests the distinct purls make, at batch_size each.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "batches_sent": {
        -                "description": "Of those, the ones the API answered.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "components_in_document": {
        -                "anyOf": [
        -                  {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ],
        -                "description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
        -              },
        -              "distinct_purls": {
        -                "description": "Distinct purls to check: sent plus not_sent.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "duplicates_removed": {
        -                "description": "Purls that appeared more than once and were sent once.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "input": {
        -                "description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document.",
        -                "enum": [
        -                  "purls",
        -                  "cyclonedx",
        -                  "spdx"
        -                ],
        -                "type": "string"
        -              },
        -              "not_assessed": {
        -                "anyOf": [
        -                  {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ],
        -                "description": "Of those sent, the components with no verdict, as the answer counts them."
        -              },
        -              "not_sent": {
        -                "description": "Distinct purls not sent, listed in data.not_sent_purls: not checked, and not clean.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "not_sent_reason": {
        -                "anyOf": [
        -                  {
        -                    "enum": [
        -                      "time_budget",
        -                      "rate_limited",
        -                      "request_failed"
        -                    ],
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ],
        -                "description": "Why not_sent is above 0: time_budget (the call's 50 s budget ran out, or waiting out the API's Retry-After would pass it), rate_limited (a 429 without Retry-After, or a 429 after 10 waits), request_failed (a batch after the first failed; the note quotes how). null when every purl was sent."
        -              },
        -              "partial": {
        -                "description": "true when not every purl was sent (not_sent above 0) or any batch's summary.partial was true (its time budget ran out first); otherwise the answer's summary.partial.",
        -                "type": [
        -                  "boolean",
        -                  "null"
        -                ]
        -              },
        -              "rate_limit_waits": {
        -                "description": "How many times the API answered 429 and the tool waited its Retry-After before sending the batch again.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "sent": {
        -                "description": "Distinct purls sent and answered.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "waited_ms": {
        -                "description": "Milliseconds spent in those waits.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "with_purl": {
        -                "description": "Of those, the ones carrying a purl.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "without_purl": {
        -                "description": "The ones without a purl: not checked, and not clean.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              }
        -            },
        -            "required": [
        -              "input",
        -              "components_in_document",
        -              "with_purl",
        -              "without_purl",
        -              "duplicates_removed",
        -              "distinct_purls",
        -              "batch_size",
        -              "batches",
        -              "batches_sent",
        -              "sent",
        -              "not_sent",
        -              "not_sent_reason",
        -              "rate_limit_waits",
        -              "waited_ms",
        -              "not_assessed",
        -              "partial"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "What the answer covers; null where the answer says nothing about it."
        -      },
        -      "data": {
        -        "additionalProperties": {},
        -        "properties": {
        -          "answered_at": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "components": {
        -            "type": [
        -              "number",
        -              "null"
        -            ]
        -          },
        -          "match_layer": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "not_sent_purls": {
        -            "anyOf": [
        -              {
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ],
        -            "description": "The distinct purls not sent (coverage.not_sent_reason says why): not checked, and not clean. Present only when some were not sent."
        -          },
        -          "results": {
        -            "items": {
        -              "additionalProperties": {},
        -              "properties": {
        -                "advisories_considered": {
        -                  "type": [
        -                    "number",
        -                    "null"
        -                  ]
        -                },
        -                "assessed": {
        -                  "description": "Whether the matcher produced a verdict for this component. false is never clean.",
        -                  "type": [
        -                    "boolean",
        -                    "null"
        -                  ]
        -                },
        -                "candidates_capped": {
        -                  "type": [
        -                    "boolean",
        -                    "null"
        -                  ]
        -                },
        -                "capped": {
        -                  "type": [
        -                    "boolean",
        -                    "null"
        -                  ]
        -                },
        -                "code": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "count": {
        -                  "type": [
        -                    "number",
        -                    "null"
        -                  ]
        -                },
        -                "cve_ids": {
        -                  "anyOf": [
        -                    {
        -                      "items": {
        -                        "type": "string"
        -                      },
        -                      "type": "array"
        -                    },
        -                    {
        -                      "type": "null"
        -                    }
        -                  ]
        -                },
        -                "ecosystem": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "error": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "index": {
        -                  "type": [
        -                    "number",
        -                    "null"
        -                  ]
        -                },
        -                "input_kind": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "matches": {
        -                  "anyOf": [
        -                    {
        -                      "items": {
        -                        "additionalProperties": {},
        -                        "properties": {
        -                          "cve_id": {
        -                            "type": [
        -                              "string",
        -                              "null"
        -                            ]
        -                          }
        -                        },
        -                        "type": "object"
        -                      },
        -                      "type": "array"
        -                    },
        -                    {
        -                      "type": "null"
        -                    }
        -                  ]
        -                },
        -                "not_affected_count": {
        -                  "type": [
        -                    "number",
        -                    "null"
        -                  ]
        -                },
        -                "not_assessed_reason": {
        -                  "description": "Why assessed is false: package_not_in_advisory_corpus, no_decidable_advisory, advisory_lookup_failed, candidate_window_truncated, time_budget, distro_release_unknown, purl_type_unsupported, version_missing or invalid_component.",
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "package": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "purl": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "undetermined": {
        -                  "anyOf": [
        -                    {
        -                      "items": {
        -                        "additionalProperties": {},
        -                        "properties": {
        -                          "cve_id": {
        -                            "type": [
        -                              "string",
        -                              "null"
        -                            ]
        -                          }
        -                        },
        -                        "type": "object"
        -                      },
        -                      "type": "array"
        -                    },
        -                    {
        -                      "type": "null"
        -                    }
        -                  ]
        -                },
        -                "undetermined_count": {
        -                  "type": [
        -                    "number",
        -                    "null"
        -                  ]
        -                },
        -                "verdict": {
        -                  "description": "affected (count > 0); not_affected (assessed, no match, nothing undetermined: the only clean verdict); undetermined (advisories name the package, at least one could not be decided, none matched: not clean); not_assessed (no verdict: not clean).",
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "version": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                }
        -              },
        -              "type": "object"
        -            },
        -            "type": "array"
        -          },
        -          "summary": {
        -            "additionalProperties": {},
        -            "properties": {
        -              "affected": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "components": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "corpus_cache_max_age_ms": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "elapsed_ms": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "lookups": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "not_affected": {
        -                "description": "Components with a decided, clean verdict.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "not_assessed": {
        -                "description": "Components with no verdict: not clean.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "not_assessed_by_reason": {
        -                "anyOf": [
        -                  {
        -                    "additionalProperties": {},
        -                    "properties": {
        -                      "advisory_lookup_failed": {
        -                        "type": "number"
        -                      },
        -                      "candidate_window_truncated": {
        -                        "type": "number"
        -                      },
        -                      "distro_release_unknown": {
        -                        "description": "deb, apk or rpm purls without a distro qualifier naming the release, which EchelonGraph does not guess.",
        -                        "type": "number"
        -                      },
        -                      "invalid_component": {
        -                        "type": "number"
        -                      },
        -                      "no_decidable_advisory": {
        -                        "type": "number"
        -                      },
        -                      "package_not_in_advisory_corpus": {
        -                        "type": "number"
        -                      },
        -                      "purl_type_unsupported": {
        -                        "type": "number"
        -                      },
        -                      "time_budget": {
        -                        "description": "Components the batch's time budget ran out before: not clean; check them again.",
        -                        "type": "number"
        -                      },
        -                      "version_missing": {
        -                        "type": "number"
        -                      }
        -                    },
        -                    "type": "object"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ],
        -                "description": "The not_assessed components, counted by not_assessed_reason."
        -              },
        -              "partial": {
        -                "description": "true when the time budget ran out before every component was looked up.",
        -                "type": [
        -                  "boolean",
        -                  "null"
        -                ]
        -              },
        -              "time_budget_ms": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "undetermined": {
        -                "description": "Components whose advisories could not all be decided and none matched: not clean.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "anyOf": [
        -          {
        -            "description": "An RFC 3339 instant.",
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        -      },
        -      "method": {
        -        "description": "How the numbers were produced.",
        -        "type": "string"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        -        "enum": [
        -          "measured",
        -          "not_assessed"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "data"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "batch_size": {
        -                "description": "The most purls one request carries (the API's cap per request).",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "batches": {
        -                "description": "Requests the distinct purls make, at batch_size each.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "batches_sent": {
        -                "description": "Of those, the ones the API answered.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "components_in_document": {
        -                "anyOf": [
        -                  {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ],
        -                "description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
        -              },
        -              "distinct_purls": {
        -                "description": "Distinct purls to check: sent plus not_sent.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "duplicates_removed": {
        -                "description": "Purls that appeared more than once and were sent once.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "input": {
        -                "description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document.",
        -                "enum": [
        -                  "purls",
        -                  "cyclonedx",
        -                  "spdx"
        -                ],
        -                "type": "string"
        -              },
        -              "not_assessed": {
        -                "anyOf": [
        -                  {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ],
        -                "description": "Of those sent, the components with no verdict, as the answer counts them."
        -              },
        -              "not_sent": {
        -                "description": "Distinct purls not sent, listed in data.not_sent_purls: not checked, and not clean.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "not_sent_reason": {
        -                "anyOf": [
        -                  {
        -                    "enum": [
        -                      "time_budget",
        -                      "rate_limited",
        -                      "request_failed"
        -                    ],
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ],
        -                "description": "Why not_sent is above 0: time_budget (the call's 50 s budget ran out, or waiting out the API's Retry-After would pass it), rate_limited (a 429 without Retry-After, or a 429 after 10 waits), request_failed (a batch after the first failed; the note quotes how). null when every purl was sent."
        -              },
        -              "partial": {
        -                "description": "true when not every purl was sent (not_sent above 0) or any batch's summary.partial was true (its time budget ran out first); otherwise the answer's summary.partial.",
        -                "type": [
        -                  "boolean",
        -                  "null"
        -                ]
        -              },
        -              "rate_limit_waits": {
        -                "description": "How many times the API answered 429 and the tool waited its Retry-After before sending the batch again.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "sent": {
        -                "description": "Distinct purls sent and answered.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "waited_ms": {
        -                "description": "Milliseconds spent in those waits.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "with_purl": {
        -                "description": "Of those, the ones carrying a purl.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "without_purl": {
        -                "description": "The ones without a purl: not checked, and not clean.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              }
        -            },
        -            "required": [
        -              "input",
        -              "components_in_document",
        -              "with_purl",
        -              "without_purl",
        -              "duplicates_removed",
        -              "distinct_purls",
        -              "batch_size",
        -              "batches",
        -              "batches_sent",
        -              "sent",
        -              "not_sent",
        -              "not_sent_reason",
        -              "rate_limit_waits",
        -              "waited_ms",
        -              "not_assessed",
        -              "partial"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "error": {
        -        "additionalProperties": false,
        -        "properties": {
        -          "kind": {
        -            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        -            "enum": [
        -              "network",
        -              "timeout",
        -              "http",
        -              "not_json",
        -              "not_object",
        -              "invalid_input",
        -              "internal",
        -              "unexpected_shape",
        -              "radars"
        -            ],
        -            "type": "string"
        -          },
        -          "message": {
        -            "description": "The cause: the API's own message, or what went wrong.",
        -            "type": "string"
        -          },
        -          "path": {
        -            "description": "The API path requested, when a request was made.",
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "status": {
        -            "anyOf": [
        -              {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ],
        -            "description": "The HTTP status, when the API answered one."
        -          }
        -        },
        -        "required": [
        -          "kind",
        -          "path",
        -          "status",
        -          "message"
        -        ],
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "type": "null"
        -      },
        -      "method": {
        -        "type": "null"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        -        "enum": [
        -          "failed",
        -          "invalid_input"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "error"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "batch_size": {
        +                "description": "The most purls one request carries (the API's cap per request).",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "batches": {
        +                "description": "Requests the distinct purls make, at batch_size each.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "batches_sent": {
        +                "description": "Of those, the ones the API answered.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "components_in_document": {
        +                "anyOf": [
        +                  {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
        +              },
        +              "distinct_purls": {
        +                "description": "Distinct purls to check: sent plus not_sent.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "duplicates_removed": {
        +                "description": "Purls that appeared more than once and were sent once.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "input": {
        +                "description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document.",
        +                "enum": [
        +                  "purls",
        +                  "cyclonedx",
        +                  "spdx"
        +                ],
        +                "type": "string"
        +              },
        +              "not_assessed": {
        +                "anyOf": [
        +                  {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Of those sent, the components with no verdict, as the answer counts them."
        +              },
        +              "not_sent": {
        +                "description": "Distinct purls not sent, listed in data.not_sent_purls: not checked, and not clean.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "not_sent_reason": {
        +                "anyOf": [
        +                  {
        +                    "enum": [
        +                      "time_budget",
        +                      "rate_limited",
        +                      "request_failed"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Why not_sent is above 0: time_budget (the call's 50 s budget ran out, before a batch or while one was unanswered, which is then cut off; or waiting out the API's Retry-After would pass it), rate_limited (a 429 without Retry-After, or a 429 after 10 waits), request_failed (a batch after the first failed; the note quotes how). null when every purl was sent."
        +              },
        +              "partial": {
        +                "description": "true when not every purl was sent (not_sent above 0) or any batch's summary.partial was true (its time budget ran out first); otherwise the answer's summary.partial.",
        +                "type": [
        +                  "boolean",
        +                  "null"
        +                ]
        +              },
        +              "rate_limit_waits": {
        +                "description": "How many times the API answered 429 and the tool waited its Retry-After before sending the batch again.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "sent": {
        +                "description": "Distinct purls sent and answered.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "waited_ms": {
        +                "description": "Milliseconds spent in those waits.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "with_purl": {
        +                "description": "Of those, the ones carrying a purl.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "without_purl": {
        +                "description": "The ones without a purl: not checked, and not clean.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              }
        +            },
        +            "required": [
        +              "input",
        +              "components_in_document",
        +              "with_purl",
        +              "without_purl",
        +              "duplicates_removed",
        +              "distinct_purls",
        +              "batch_size",
        +              "batches",
        +              "batches_sent",
        +              "sent",
        +              "not_sent",
        +              "not_sent_reason",
        +              "rate_limit_waits",
        +              "waited_ms",
        +              "not_assessed",
        +              "partial"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "What the answer covers; null where the answer says nothing about it."
        +      },
        +      "data": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "answered_at": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "components": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "match_layer": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "not_sent_purls": {
        +            "anyOf": [
        +              {
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "The distinct purls not sent (coverage.not_sent_reason says why): not checked, and not clean. Present only when some were not sent."
        +          },
        +          "results": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "advisories_considered": {
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "assessed": {
        +                  "description": "Whether the matcher produced a verdict for this component. false is never clean.",
        +                  "type": [
        +                    "boolean",
        +                    "null"
        +                  ]
        +                },
        +                "candidates_capped": {
        +                  "type": [
        +                    "boolean",
        +                    "null"
        +                  ]
        +                },
        +                "capped": {
        +                  "type": [
        +                    "boolean",
        +                    "null"
        +                  ]
        +                },
        +                "code": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "count": {
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "cve_ids": {
        +                  "anyOf": [
        +                    {
        +                      "items": {
        +                        "type": "string"
        +                      },
        +                      "type": "array"
        +                    },
        +                    {
        +                      "type": "null"
        +                    }
        +                  ]
        +                },
        +                "ecosystem": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "error": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "index": {
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "input_kind": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "matches": {
        +                  "anyOf": [
        +                    {
        +                      "items": {
        +                        "additionalProperties": {},
        +                        "properties": {
        +                          "cve_id": {
        +                            "type": [
        +                              "string",
        +                              "null"
        +                            ]
        +                          }
        +                        },
        +                        "type": "object"
        +                      },
        +                      "type": "array"
        +                    },
        +                    {
        +                      "type": "null"
        +                    }
        +                  ]
        +                },
        +                "not_affected_count": {
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "not_assessed_reason": {
        +                  "description": "Why assessed is false: package_not_in_advisory_corpus, no_decidable_advisory, advisory_lookup_failed, candidate_window_truncated, time_budget, distro_release_unknown, purl_type_unsupported, version_missing or invalid_component.",
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "package": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "purl": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "undetermined": {
        +                  "anyOf": [
        +                    {
        +                      "items": {
        +                        "additionalProperties": {},
        +                        "properties": {
        +                          "cve_id": {
        +                            "type": [
        +                              "string",
        +                              "null"
        +                            ]
        +                          }
        +                        },
        +                        "type": "object"
        +                      },
        +                      "type": "array"
        +                    },
        +                    {
        +                      "type": "null"
        +                    }
        +                  ]
        +                },
        +                "undetermined_count": {
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "verdict": {
        +                  "description": "affected (count > 0); not_affected (assessed, no match, nothing undetermined: the only clean verdict); undetermined (advisories name the package, at least one could not be decided, none matched: not clean); not_assessed (no verdict: not clean).",
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "version": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "summary": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "affected": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "components": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "corpus_cache_max_age_ms": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "elapsed_ms": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "lookups": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "not_affected": {
        +                "description": "Components with a decided, clean verdict.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "not_assessed": {
        +                "description": "Components with no verdict: not clean.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "not_assessed_by_reason": {
        +                "anyOf": [
        +                  {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "advisory_lookup_failed": {
        +                        "type": "number"
        +                      },
        +                      "candidate_window_truncated": {
        +                        "type": "number"
        +                      },
        +                      "distro_release_unknown": {
        +                        "description": "deb, apk or rpm purls without a distro qualifier naming the release, which EchelonGraph does not guess.",
        +                        "type": "number"
        +                      },
        +                      "invalid_component": {
        +                        "type": "number"
        +                      },
        +                      "no_decidable_advisory": {
        +                        "type": "number"
        +                      },
        +                      "package_not_in_advisory_corpus": {
        +                        "type": "number"
        +                      },
        +                      "purl_type_unsupported": {
        +                        "type": "number"
        +                      },
        +                      "time_budget": {
        +                        "description": "Components the batch's time budget ran out before: not clean; check them again.",
        +                        "type": "number"
        +                      },
        +                      "version_missing": {
        +                        "type": "number"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "The not_assessed components, counted by not_assessed_reason."
        +              },
        +              "partial": {
        +                "description": "true when the time budget ran out before every component was looked up.",
        +                "type": [
        +                  "boolean",
        +                  "null"
        +                ]
        +              },
        +              "time_budget_ms": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "undetermined": {
        +                "description": "Components whose advisories could not all be decided and none matched: not clean.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "anyOf": [
        +          {
        +            "description": "An RFC 3339 instant.",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        +      },
        +      "method": {
        +        "description": "How the numbers were produced.",
        +        "type": "string"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        +        "enum": [
        +          "measured",
        +          "not_assessed"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "data"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "batch_size": {
        +                "description": "The most purls one request carries (the API's cap per request).",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "batches": {
        +                "description": "Requests the distinct purls make, at batch_size each.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "batches_sent": {
        +                "description": "Of those, the ones the API answered.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "components_in_document": {
        +                "anyOf": [
        +                  {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
        +              },
        +              "distinct_purls": {
        +                "description": "Distinct purls to check: sent plus not_sent.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "duplicates_removed": {
        +                "description": "Purls that appeared more than once and were sent once.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "input": {
        +                "description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document.",
        +                "enum": [
        +                  "purls",
        +                  "cyclonedx",
        +                  "spdx"
        +                ],
        +                "type": "string"
        +              },
        +              "not_assessed": {
        +                "anyOf": [
        +                  {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Of those sent, the components with no verdict, as the answer counts them."
        +              },
        +              "not_sent": {
        +                "description": "Distinct purls not sent, listed in data.not_sent_purls: not checked, and not clean.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "not_sent_reason": {
        +                "anyOf": [
        +                  {
        +                    "enum": [
        +                      "time_budget",
        +                      "rate_limited",
        +                      "request_failed"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Why not_sent is above 0: time_budget (the call's 50 s budget ran out, before a batch or while one was unanswered, which is then cut off; or waiting out the API's Retry-After would pass it), rate_limited (a 429 without Retry-After, or a 429 after 10 waits), request_failed (a batch after the first failed; the note quotes how). null when every purl was sent."
        +              },
        +              "partial": {
        +                "description": "true when not every purl was sent (not_sent above 0) or any batch's summary.partial was true (its time budget ran out first); otherwise the answer's summary.partial.",
        +                "type": [
        +                  "boolean",
        +                  "null"
        +                ]
        +              },
        +              "rate_limit_waits": {
        +                "description": "How many times the API answered 429 and the tool waited its Retry-After before sending the batch again.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "sent": {
        +                "description": "Distinct purls sent and answered.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "waited_ms": {
        +                "description": "Milliseconds spent in those waits.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "with_purl": {
        +                "description": "Of those, the ones carrying a purl.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "without_purl": {
        +                "description": "The ones without a purl: not checked, and not clean.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              }
        +            },
        +            "required": [
        +              "input",
        +              "components_in_document",
        +              "with_purl",
        +              "without_purl",
        +              "duplicates_removed",
        +              "distinct_purls",
        +              "batch_size",
        +              "batches",
        +              "batches_sent",
        +              "sent",
        +              "not_sent",
        +              "not_sent_reason",
        +              "rate_limit_waits",
        +              "waited_ms",
        +              "not_assessed",
        +              "partial"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "error": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "kind": {
        +            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        +            "enum": [
        +              "network",
        +              "timeout",
        +              "http",
        +              "not_json",
        +              "not_object",
        +              "invalid_input",
        +              "internal",
        +              "unexpected_shape",
        +              "radars"
        +            ],
        +            "type": "string"
        +          },
        +          "message": {
        +            "description": "The cause: the API's own message, or what went wrong.",
        +            "type": "string"
        +          },
        +          "path": {
        +            "description": "The API path requested, when a request was made.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "status": {
        +            "anyOf": [
        +              {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "The HTTP status, when the API answered one."
        +          }
        +        },
        +        "required": [
        +          "kind",
        +          "path",
        +          "status",
        +          "message"
        +        ],
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "type": "null"
        +      },
        +      "method": {
        +        "type": "null"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        +        "enum": [
        +          "failed",
        +          "invalid_input"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "error"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedexposure_radar1 field changed
      • changedOutput schema / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "answered": {
        -                "description": "The radars that answered. On a failure their answers are withheld.",
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              },
        -              "failed": {
        -                "description": "The radars that could not be read.",
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              },
        -              "radars": {
        -                "description": "The radars this tool reads.",
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            },
        -            "required": [
        -              "radars",
        -              "answered",
        -              "failed"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "What the answer covers; null where the answer says nothing about it."
        -      },
        -      "data": {
        -        "additionalProperties": false,
        -        "properties": {
        -          "exposed_databases": {
        -            "additionalProperties": false,
        -            "properties": {
        -              "distinct_hosts": {
        -                "type": "number"
        -              },
        -              "engines": {
        -                "type": "number"
        -              },
        -              "generated_at": {
        -                "description": "An RFC 3339 instant.",
        -                "type": "string"
        -              },
        -              "last_run_at": {
        -                "description": "An RFC 3339 instant.",
        -                "type": "string"
        -              },
        -              "pci_likely": {
        -                "type": "number"
        -              },
        -              "pii_likely": {
        -                "type": "number"
        -              },
        -              "top_countries": {
        -                "items": {
        -                  "additionalProperties": false,
        -                  "properties": {
        -                    "country": {
        -                      "type": "string"
        -                    },
        -                    "hosts": {
        -                      "type": "number"
        -                    }
        -                  },
        -                  "required": [
        -                    "country",
        -                    "hosts"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              "top_engines": {
        -                "items": {
        -                  "additionalProperties": false,
        -                  "properties": {
        -                    "engine": {
        -                      "type": "string"
        -                    },
        -                    "hosts": {
        -                      "type": "number"
        -                    }
        -                  },
        -                  "required": [
        -                    "engine",
        -                    "hosts"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              }
        -            },
        -            "type": "object"
        -          },
        -          "kev_exposure": {
        -            "additionalProperties": false,
        -            "properties": {
        -              "correlations": {
        -                "type": "number"
        -              },
        -              "distinct_hosts": {
        -                "type": "number"
        -              },
        -              "generated_at": {
        -                "description": "An RFC 3339 instant.",
        -                "type": "string"
        -              },
        -              "kev_cves_exposed": {
        -                "type": "number"
        -              },
        -              "last_run_at": {
        -                "description": "An RFC 3339 instant.",
        -                "type": "string"
        -              },
        -              "newest_kev": {
        -                "items": {
        -                  "additionalProperties": false,
        -                  "properties": {
        -                    "added_date": {
        -                      "type": "string"
        -                    },
        -                    "cve_id": {
        -                      "type": "string"
        -                    },
        -                    "cvss_v3_score": {
        -                      "type": "number"
        -                    },
        -                    "epss_score": {
        -                      "type": "number"
        -                    },
        -                    "exposed_hosts": {
        -                      "type": "number"
        -                    },
        -                    "exposure_state": {
        -                      "enum": [
        -                        "exposed",
        -                        "measured_zero",
        -                        "not_assessed"
        -                      ],
        -                      "type": "string"
        -                    },
        -                    "ransomware": {
        -                      "type": "boolean"
        -                    },
        -                    "severity": {
        -                      "type": "string"
        -                    },
        -                    "vuln_name": {
        -                      "type": "string"
        -                    }
        -                  },
        -                  "required": [
        -                    "cve_id",
        -                    "exposure_state"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              "ransomware_cves": {
        -                "type": "number"
        -              },
        -              "ransomware_hosts": {
        -                "type": "number"
        -              },
        -              "top_countries": {
        -                "items": {
        -                  "additionalProperties": false,
        -                  "properties": {
        -                    "country": {
        -                      "type": "string"
        -                    },
        -                    "hosts": {
        -                      "type": "number"
        -                    }
        -                  },
        -                  "required": [
        -                    "country",
        -                    "hosts"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              "top_cves": {
        -                "items": {
        -                  "additionalProperties": false,
        -                  "properties": {
        -                    "cve_id": {
        -                      "type": "string"
        -                    },
        -                    "cvss_v3_score": {
        -                      "type": "number"
        -                    },
        -                    "epss_score": {
        -                      "type": "number"
        -                    },
        -                    "hosts": {
        -                      "type": "number"
        -                    },
        -                    "ransomware": {
        -                      "type": "boolean"
        -                    },
        -                    "severity": {
        -                      "type": "string"
        -                    }
        -                  },
        -                  "required": [
        -                    "cve_id",
        -                    "hosts"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              "top_products": {
        -                "items": {
        -                  "additionalProperties": false,
        -                  "properties": {
        -                    "hosts": {
        -                      "type": "number"
        -                    },
        -                    "product": {
        -                      "type": "string"
        -                    }
        -                  },
        -                  "required": [
        -                    "product",
        -                    "hosts"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              "trend": {
        -                "items": {
        -                  "additionalProperties": false,
        -                  "properties": {
        -                    "new_exposures": {
        -                      "type": "number"
        -                    },
        -                    "week": {
        -                      "type": "string"
        -                    }
        -                  },
        -                  "required": [
        -                    "week",
        -                    "new_exposures"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              }
        -            },
        -            "type": "object"
        -          },
        -          "leaked_credentials": {
        -            "additionalProperties": false,
        -            "properties": {
        -              "distinct_repos": {
        -                "type": "number"
        -              },
        -              "distinct_secrets": {
        -                "type": "number"
        -              },
        -              "generated_at": {
        -                "description": "An RFC 3339 instant.",
        -                "type": "string"
        -              },
        -              "last_run_at": {
        -                "description": "An RFC 3339 instant.",
        -                "type": "string"
        -              },
        -              "top_providers": {
        -                "items": {
        -                  "additionalProperties": false,
        -                  "properties": {
        -                    "count": {
        -                      "type": "number"
        -                    },
        -                    "provider": {
        -                      "type": "string"
        -                    }
        -                  },
        -                  "required": [
        -                    "provider",
        -                    "count"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              "top_types": {
        -                "items": {
        -                  "additionalProperties": false,
        -                  "properties": {
        -                    "count": {
        -                      "type": "number"
        -                    },
        -                    "secret_type": {
        -                      "type": "string"
        -                    }
        -                  },
        -                  "required": [
        -                    "secret_type",
        -                    "count"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              "total": {
        -                "type": "number"
        -              }
        -            },
        -            "type": "object"
        -          },
        -          "mcp_servers": {
        -            "additionalProperties": false,
        -            "properties": {
        -              "counted_at": {
        -                "description": "An RFC 3339 instant.",
        -                "type": "string"
        -              },
        -              "enabled": {
        -                "type": "boolean"
        -              },
        -              "era": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "dual": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "legacy": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "modern": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "not_measured": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "unknown": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  }
        -                },
        -                "required": [
        -                  "legacy",
        -                  "dual",
        -                  "modern",
        -                  "unknown",
        -                  "not_measured"
        -                ],
        -                "type": "object"
        -              },
        -              "last_run_at": {
        -                "description": "An RFC 3339 instant.",
        -                "type": "string"
        -              },
        -              "not_assessed": {
        -                "maximum": 9007199254740991,
        -                "minimum": 0,
        -                "type": "integer"
        -              },
        -              "not_assessed_by_reason": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "bare_challenge_no_prm": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "challenge_unadjudicated": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "cross_origin_pointer": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "identified_no_challenge": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "metadata_invalid": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "no_authorization_servers": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "no_http_answer": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "not_identified_as_mcp": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "pointer_invalid": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "pointer_unreachable": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "resource_mismatch": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "wellknown_unreachable": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  }
        -                },
        -                "required": [
        -                  "identified_no_challenge",
        -                  "resource_mismatch",
        -                  "cross_origin_pointer",
        -                  "bare_challenge_no_prm",
        -                  "pointer_unreachable",
        -                  "pointer_invalid",
        -                  "no_authorization_servers",
        -                  "wellknown_unreachable",
        -                  "metadata_invalid",
        -                  "challenge_unadjudicated",
        -                  "no_http_answer",
        -                  "not_identified_as_mcp"
        -                ],
        -                "type": "object"
        -              },
        -              "own_controls_excluded": {
        -                "maximum": 9007199254740991,
        -                "minimum": 0,
        -                "type": "integer"
        -              },
        -              "pending_readjudication": {
        -                "maximum": 9007199254740991,
        -                "minimum": 0,
        -                "type": "integer"
        -              },
        -              "prm_via": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "header": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "wellknown_path": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "wellknown_root": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  }
        -                },
        -                "required": [
        -                  "header",
        -                  "wellknown_path",
        -                  "wellknown_root"
        -                ],
        -                "type": "object"
        -              },
        -              "protected": {
        -                "maximum": 9007199254740991,
        -                "minimum": 0,
        -                "type": "integer"
        -              },
        -              "total": {
        -                "maximum": 9007199254740991,
        -                "minimum": 0,
        -                "type": "integer"
        -              },
        -              "transport": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "legacy_sse": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "not_measured": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "streamable_http": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  },
        -                  "unknown": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": 0,
        -                    "type": "integer"
        -                  }
        -                },
        -                "required": [
        -                  "streamable_http",
        -                  "legacy_sse",
        -                  "unknown",
        -                  "not_measured"
        -                ],
        -                "type": "object"
        -              },
        -              "window": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "from": {
        -                    "description": "An RFC 3339 instant.",
        -                    "type": "string"
        -                  },
        -                  "to": {
        -                    "description": "An RFC 3339 instant.",
        -                    "type": "string"
        -                  }
        -                },
        -                "required": [
        -                  "from",
        -                  "to"
        -                ],
        -                "type": "object"
        -              }
        -            },
        -            "required": [
        -              "total",
        -              "protected",
        -              "pending_readjudication",
        -              "not_assessed"
        -            ],
        -            "type": "object"
        -          },
        -          "shadow_ai": {
        -            "additionalProperties": false,
        -            "properties": {
        -              "authentication": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "not_determined": {
        -                    "type": "number"
        -                  },
        -                  "observed": {
        -                    "type": "number"
        -                  }
        -                },
        -                "type": "object"
        -              },
        -              "confirmed_exposed": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "by_category": {
        -                    "additionalProperties": {
        -                      "type": "number"
        -                    },
        -                    "propertyNames": {
        -                      "type": "string"
        -                    },
        -                    "type": "object"
        -                  },
        -                  "last_24h": {
        -                    "type": "number"
        -                  },
        -                  "total": {
        -                    "type": "number"
        -                  }
        -                },
        -                "type": "object"
        -              },
        -              "observed": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "by_category": {
        -                    "additionalProperties": {
        -                      "type": "number"
        -                    },
        -                    "propertyNames": {
        -                      "type": "string"
        -                    },
        -                    "type": "object"
        -                  },
        -                  "last_24h": {
        -                    "type": "number"
        -                  },
        -                  "last_observation": {
        -                    "description": "An RFC 3339 instant.",
        -                    "type": "string"
        -                  },
        -                  "top_countries": {
        -                    "items": {
        -                      "additionalProperties": false,
        -                      "properties": {
        -                        "count": {
        -                          "type": "number"
        -                        },
        -                        "country": {
        -                          "type": "string"
        -                        }
        -                      },
        -                      "required": [
        -                        "country",
        -                        "count"
        -                      ],
        -                      "type": "object"
        -                    },
        -                    "type": "array"
        -                  },
        -                  "top_issuers": {
        -                    "items": {
        -                      "additionalProperties": false,
        -                      "properties": {
        -                        "count": {
        -                          "type": "number"
        -                        },
        -                        "issuer": {
        -                          "type": "string"
        -                        }
        -                      },
        -                      "required": [
        -                        "issuer",
        -                        "count"
        -                      ],
        -                      "type": "object"
        -                    },
        -                    "type": "array"
        -                  },
        -                  "top_products": {
        -                    "items": {
        -                      "additionalProperties": false,
        -                      "properties": {
        -                        "count": {
        -                          "type": "number"
        -                        },
        -                        "product": {
        -                          "type": "string"
        -                        }
        -                      },
        -                      "required": [
        -                        "product",
        -                        "count"
        -                      ],
        -                      "type": "object"
        -                    },
        -                    "type": "array"
        -                  },
        -                  "total": {
        -                    "type": "number"
        -                  },
        -                  "trend_30d": {
        -                    "items": {
        -                      "additionalProperties": false,
        -                      "properties": {
        -                        "count": {
        -                          "type": "number"
        -                        },
        -                        "date": {
        -                          "type": "string"
        -                        }
        -                      },
        -                      "required": [
        -                        "date",
        -                        "count"
        -                      ],
        -                      "type": "object"
        -                    },
        -                    "type": "array"
        -                  }
        -                },
        -                "type": "object"
        -              },
        -              "poller": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "last_run_at": {
        -                    "description": "An RFC 3339 instant.",
        -                    "type": "string"
        -                  },
        -                  "running": {
        -                    "type": "boolean"
        -                  }
        -                },
        -                "required": [
        -                  "running",
        -                  "last_run_at"
        -                ],
        -                "type": "object"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "kev_exposure",
        -          "exposed_databases",
        -          "leaked_credentials",
        -          "shadow_ai",
        -          "mcp_servers"
        -        ],
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "exposed_databases": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "last_run_at": {
        -                    "anyOf": [
        -                      {
        -                        "description": "An RFC 3339 instant.",
        -                        "type": "string"
        -                      },
        -                      {
        -                        "type": "null"
        -                      }
        -                    ]
        -                  }
        -                },
        -                "required": [
        -                  "last_run_at"
        -                ],
        -                "type": "object"
        -              },
        -              "kev_exposure": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "last_run_at": {
        -                    "anyOf": [
        -                      {
        -                        "description": "An RFC 3339 instant.",
        -                        "type": "string"
        -                      },
        -                      {
        -                        "type": "null"
        -                      }
        -                    ]
        -                  }
        -                },
        -                "required": [
        -                  "last_run_at"
        -                ],
        -                "type": "object"
        -              },
        -              "leaked_credentials": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "last_run_at": {
        -                    "anyOf": [
        -                      {
        -                        "description": "An RFC 3339 instant.",
        -                        "type": "string"
        -                      },
        -                      {
        -                        "type": "null"
        -                      }
        -                    ]
        -                  }
        -                },
        -                "required": [
        -                  "last_run_at"
        -                ],
        -                "type": "object"
        -              },
        -              "mcp_servers": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "enabled": {
        -                    "type": [
        -                      "boolean",
        -                      "null"
        -                    ]
        -                  },
        -                  "last_run_at": {
        -                    "anyOf": [
        -                      {
        -                        "description": "An RFC 3339 instant.",
        -                        "type": "string"
        -                      },
        -                      {
        -                        "type": "null"
        -                      }
        -                    ]
        -                  }
        -                },
        -                "required": [
        -                  "last_run_at",
        -                  "enabled"
        -                ],
        -                "type": "object"
        -              },
        -              "shadow_ai": {
        -                "additionalProperties": false,
        -                "properties": {
        -                  "last_run_at": {
        -                    "anyOf": [
        -                      {
        -                        "description": "An RFC 3339 instant.",
        -                        "type": "string"
        -                      },
        -                      {
        -                        "type": "null"
        -                      }
        -                    ]
        -                  },
        -                  "running": {
        -                    "type": [
        -                      "boolean",
        -                      "null"
        -                    ]
        -                  }
        -                },
        -                "required": [
        -                  "last_run_at",
        -                  "running"
        -                ],
        -                "type": "object"
        -              }
        -            },
        -            "required": [
        -              "kev_exposure",
        -              "exposed_databases",
        -              "leaked_credentials",
        -              "shadow_ai",
        -              "mcp_servers"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "The producing radar's last completed check (last_run_at), where the API serves one."
        -      },
        -      "measured_at": {
        -        "anyOf": [
        -          {
        -            "description": "An RFC 3339 instant.",
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        -      },
        -      "method": {
        -        "description": "How the numbers were produced.",
        -        "type": "string"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        -        "enum": [
        -          "measured",
        -          "not_assessed"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "data"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "answered": {
        -                "description": "The radars that answered. On a failure their answers are withheld.",
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              },
        -              "failed": {
        -                "description": "The radars that could not be read.",
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              },
        -              "radars": {
        -                "description": "The radars this tool reads.",
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            },
        -            "required": [
        -              "radars",
        -              "answered",
        -              "failed"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "error": {
        -        "additionalProperties": false,
        -        "properties": {
        -          "kind": {
        -            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        -            "enum": [
        -              "network",
        -              "timeout",
        -              "http",
        -              "not_json",
        -              "not_object",
        -              "invalid_input",
        -              "internal",
        -              "unexpected_shape",
        -              "radars"
        -            ],
        -            "type": "string"
        -          },
        -          "message": {
        -            "description": "The cause: the API's own message, or what went wrong.",
        -            "type": "string"
        -          },
        -          "path": {
        -            "description": "The API path requested, when a request was made.",
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "radars": {
        -            "description": "Each radar that could not be read, and why.",
        -            "items": {
        -              "additionalProperties": false,
        -              "properties": {
        -                "kind": {
        -                  "enum": [
        -                    "network",
        -                    "timeout",
        -                    "http",
        -                    "not_json",
        -                    "not_object",
        -                    "unexpected_shape"
        -                  ],
        -                  "type": "string"
        -                },
        -                "message": {
        -                  "type": "string"
        -                },
        -                "path": {
        -                  "type": "string"
        -                },
        -                "radar": {
        -                  "type": "string"
        -                },
        -                "status": {
        -                  "anyOf": [
        -                    {
        -                      "maximum": 9007199254740991,
        -                      "minimum": -9007199254740991,
        -                      "type": "integer"
        -                    },
        -                    {
        -                      "type": "null"
        -                    }
        -                  ]
        -                }
        -              },
        -              "required": [
        -                "radar",
        -                "kind",
        -                "path",
        -                "status",
        -                "message"
        -              ],
        -              "type": "object"
        -            },
        -            "type": "array"
        -          },
        -          "status": {
        -            "anyOf": [
        -              {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ],
        -            "description": "The HTTP status, when the API answered one."
        -          }
        -        },
        -        "required": [
        -          "kind",
        -          "path",
        -          "status",
        -          "message"
        -        ],
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "type": "null"
        -      },
        -      "method": {
        -        "type": "null"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        -        "enum": [
        -          "failed",
        -          "invalid_input"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "error"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "answered": {
        +                "description": "The radars that answered. On a failure their answers are withheld.",
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              },
        +              "failed": {
        +                "description": "The radars that could not be read.",
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              },
        +              "radars": {
        +                "description": "The radars this tool reads.",
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            },
        +            "required": [
        +              "radars",
        +              "answered",
        +              "failed"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "What the answer covers; null where the answer says nothing about it."
        +      },
        +      "data": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "exposed_databases": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "distinct_hosts": {
        +                "type": "number"
        +              },
        +              "engines": {
        +                "type": "number"
        +              },
        +              "generated_at": {
        +                "description": "An RFC 3339 instant.",
        +                "type": "string"
        +              },
        +              "last_run_at": {
        +                "description": "An RFC 3339 instant.",
        +                "type": "string"
        +              },
        +              "pci_likely": {
        +                "type": "number"
        +              },
        +              "pii_likely": {
        +                "type": "number"
        +              },
        +              "top_countries": {
        +                "items": {
        +                  "additionalProperties": false,
        +                  "properties": {
        +                    "country": {
        +                      "type": "string"
        +                    },
        +                    "hosts": {
        +                      "type": "number"
        +                    }
        +                  },
        +                  "required": [
        +                    "country",
        +                    "hosts"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "top_engines": {
        +                "items": {
        +                  "additionalProperties": false,
        +                  "properties": {
        +                    "engine": {
        +                      "type": "string"
        +                    },
        +                    "hosts": {
        +                      "type": "number"
        +                    }
        +                  },
        +                  "required": [
        +                    "engine",
        +                    "hosts"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "window": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "from": {
        +                    "description": "An RFC 3339 instant.",
        +                    "type": "string"
        +                  },
        +                  "to": {
        +                    "description": "An RFC 3339 instant.",
        +                    "type": "string"
        +                  }
        +                },
        +                "required": [
        +                  "from",
        +                  "to"
        +                ],
        +                "type": "object"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "kev_exposure": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "correlations": {
        +                "type": "number"
        +              },
        +              "distinct_hosts": {
        +                "type": "number"
        +              },
        +              "generated_at": {
        +                "description": "An RFC 3339 instant.",
        +                "type": "string"
        +              },
        +              "kev_cves_exposed": {
        +                "type": "number"
        +              },
        +              "last_run_at": {
        +                "description": "An RFC 3339 instant.",
        +                "type": "string"
        +              },
        +              "newest_kev": {
        +                "items": {
        +                  "additionalProperties": false,
        +                  "properties": {
        +                    "added_date": {
        +                      "type": "string"
        +                    },
        +                    "cve_id": {
        +                      "type": "string"
        +                    },
        +                    "cvss_v3_score": {
        +                      "type": "number"
        +                    },
        +                    "epss_score": {
        +                      "type": "number"
        +                    },
        +                    "exposed_hosts": {
        +                      "type": "number"
        +                    },
        +                    "exposure_state": {
        +                      "enum": [
        +                        "exposed",
        +                        "measured_zero",
        +                        "not_assessed"
        +                      ],
        +                      "type": "string"
        +                    },
        +                    "ransomware": {
        +                      "type": "boolean"
        +                    },
        +                    "severity": {
        +                      "type": "string"
        +                    },
        +                    "vuln_name": {
        +                      "type": "string"
        +                    }
        +                  },
        +                  "required": [
        +                    "cve_id",
        +                    "exposure_state"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "ransomware_cves": {
        +                "type": "number"
        +              },
        +              "ransomware_hosts": {
        +                "type": "number"
        +              },
        +              "top_countries": {
        +                "items": {
        +                  "additionalProperties": false,
        +                  "properties": {
        +                    "country": {
        +                      "type": "string"
        +                    },
        +                    "hosts": {
        +                      "type": "number"
        +                    }
        +                  },
        +                  "required": [
        +                    "country",
        +                    "hosts"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "top_cves": {
        +                "items": {
        +                  "additionalProperties": false,
        +                  "properties": {
        +                    "cve_id": {
        +                      "type": "string"
        +                    },
        +                    "cvss_v3_score": {
        +                      "type": "number"
        +                    },
        +                    "epss_score": {
        +                      "type": "number"
        +                    },
        +                    "hosts": {
        +                      "type": "number"
        +                    },
        +                    "ransomware": {
        +                      "type": "boolean"
        +                    },
        +                    "severity": {
        +                      "type": "string"
        +                    }
        +                  },
        +                  "required": [
        +                    "cve_id",
        +                    "hosts"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "top_products": {
        +                "items": {
        +                  "additionalProperties": false,
        +                  "properties": {
        +                    "hosts": {
        +                      "type": "number"
        +                    },
        +                    "product": {
        +                      "type": "string"
        +                    }
        +                  },
        +                  "required": [
        +                    "product",
        +                    "hosts"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "trend": {
        +                "items": {
        +                  "additionalProperties": false,
        +                  "properties": {
        +                    "new_exposures": {
        +                      "type": "number"
        +                    },
        +                    "week": {
        +                      "type": "string"
        +                    }
        +                  },
        +                  "required": [
        +                    "week",
        +                    "new_exposures"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "leaked_credentials": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "distinct_repos": {
        +                "type": "number"
        +              },
        +              "distinct_secrets": {
        +                "type": "number"
        +              },
        +              "generated_at": {
        +                "description": "An RFC 3339 instant.",
        +                "type": "string"
        +              },
        +              "last_run_at": {
        +                "description": "An RFC 3339 instant.",
        +                "type": "string"
        +              },
        +              "top_providers": {
        +                "items": {
        +                  "additionalProperties": false,
        +                  "properties": {
        +                    "count": {
        +                      "type": "number"
        +                    },
        +                    "provider": {
        +                      "type": "string"
        +                    }
        +                  },
        +                  "required": [
        +                    "provider",
        +                    "count"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "top_types": {
        +                "items": {
        +                  "additionalProperties": false,
        +                  "properties": {
        +                    "count": {
        +                      "type": "number"
        +                    },
        +                    "secret_type": {
        +                      "type": "string"
        +                    }
        +                  },
        +                  "required": [
        +                    "secret_type",
        +                    "count"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "total": {
        +                "type": "number"
        +              },
        +              "window": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "from": {
        +                    "description": "An RFC 3339 instant.",
        +                    "type": "string"
        +                  },
        +                  "to": {
        +                    "description": "An RFC 3339 instant.",
        +                    "type": "string"
        +                  }
        +                },
        +                "required": [
        +                  "from",
        +                  "to"
        +                ],
        +                "type": "object"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "mcp_servers": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "counted_at": {
        +                "description": "An RFC 3339 instant.",
        +                "type": "string"
        +              },
        +              "enabled": {
        +                "type": "boolean"
        +              },
        +              "era": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "dual": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "legacy": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "modern": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "not_measured": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "unknown": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  }
        +                },
        +                "required": [
        +                  "legacy",
        +                  "dual",
        +                  "modern",
        +                  "unknown",
        +                  "not_measured"
        +                ],
        +                "type": "object"
        +              },
        +              "last_run_at": {
        +                "description": "An RFC 3339 instant.",
        +                "type": "string"
        +              },
        +              "not_assessed": {
        +                "maximum": 9007199254740991,
        +                "minimum": 0,
        +                "type": "integer"
        +              },
        +              "not_assessed_by_reason": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "bare_challenge_no_prm": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "challenge_unadjudicated": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "cross_origin_pointer": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "identified_no_challenge": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "metadata_invalid": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "no_authorization_servers": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "no_http_answer": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "not_identified_as_mcp": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "pointer_invalid": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "pointer_unreachable": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "resource_mismatch": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "wellknown_unreachable": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  }
        +                },
        +                "required": [
        +                  "identified_no_challenge",
        +                  "resource_mismatch",
        +                  "cross_origin_pointer",
        +                  "bare_challenge_no_prm",
        +                  "pointer_unreachable",
        +                  "pointer_invalid",
        +                  "no_authorization_servers",
        +                  "wellknown_unreachable",
        +                  "metadata_invalid",
        +                  "challenge_unadjudicated",
        +                  "no_http_answer",
        +                  "not_identified_as_mcp"
        +                ],
        +                "type": "object"
        +              },
        +              "own_controls_excluded": {
        +                "maximum": 9007199254740991,
        +                "minimum": 0,
        +                "type": "integer"
        +              },
        +              "pending_readjudication": {
        +                "maximum": 9007199254740991,
        +                "minimum": 0,
        +                "type": "integer"
        +              },
        +              "prm_via": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "header": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "wellknown_path": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "wellknown_root": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  }
        +                },
        +                "required": [
        +                  "header",
        +                  "wellknown_path",
        +                  "wellknown_root"
        +                ],
        +                "type": "object"
        +              },
        +              "protected": {
        +                "maximum": 9007199254740991,
        +                "minimum": 0,
        +                "type": "integer"
        +              },
        +              "total": {
        +                "maximum": 9007199254740991,
        +                "minimum": 0,
        +                "type": "integer"
        +              },
        +              "transport": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "legacy_sse": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "not_measured": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "streamable_http": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  },
        +                  "unknown": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": 0,
        +                    "type": "integer"
        +                  }
        +                },
        +                "required": [
        +                  "streamable_http",
        +                  "legacy_sse",
        +                  "unknown",
        +                  "not_measured"
        +                ],
        +                "type": "object"
        +              },
        +              "window": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "from": {
        +                    "description": "An RFC 3339 instant.",
        +                    "type": "string"
        +                  },
        +                  "to": {
        +                    "description": "An RFC 3339 instant.",
        +                    "type": "string"
        +                  }
        +                },
        +                "required": [
        +                  "from",
        +                  "to"
        +                ],
        +                "type": "object"
        +              }
        +            },
        +            "required": [
        +              "total",
        +              "protected",
        +              "pending_readjudication",
        +              "not_assessed"
        +            ],
        +            "type": "object"
        +          },
        +          "shadow_ai": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "authentication": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "not_determined": {
        +                    "type": "number"
        +                  },
        +                  "observed": {
        +                    "type": "number"
        +                  }
        +                },
        +                "type": "object"
        +              },
        +              "confirmed_exposed": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "by_category": {
        +                    "additionalProperties": {
        +                      "type": "number"
        +                    },
        +                    "propertyNames": {
        +                      "type": "string"
        +                    },
        +                    "type": "object"
        +                  },
        +                  "last_24h": {
        +                    "type": "number"
        +                  },
        +                  "total": {
        +                    "type": "number"
        +                  },
        +                  "window": {
        +                    "additionalProperties": false,
        +                    "properties": {
        +                      "from": {
        +                        "description": "An RFC 3339 instant.",
        +                        "type": "string"
        +                      },
        +                      "to": {
        +                        "description": "An RFC 3339 instant.",
        +                        "type": "string"
        +                      }
        +                    },
        +                    "required": [
        +                      "from",
        +                      "to"
        +                    ],
        +                    "type": "object"
        +                  }
        +                },
        +                "type": "object"
        +              },
        +              "observed": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "by_category": {
        +                    "additionalProperties": {
        +                      "type": "number"
        +                    },
        +                    "propertyNames": {
        +                      "type": "string"
        +                    },
        +                    "type": "object"
        +                  },
        +                  "last_24h": {
        +                    "type": "number"
        +                  },
        +                  "last_observation": {
        +                    "description": "An RFC 3339 instant.",
        +                    "type": "string"
        +                  },
        +                  "top_countries": {
        +                    "items": {
        +                      "additionalProperties": false,
        +                      "properties": {
        +                        "count": {
        +                          "type": "number"
        +                        },
        +                        "country": {
        +                          "type": "string"
        +                        }
        +                      },
        +                      "required": [
        +                        "country",
        +                        "count"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "type": "array"
        +                  },
        +                  "top_issuers": {
        +                    "items": {
        +                      "additionalProperties": false,
        +                      "properties": {
        +                        "count": {
        +                          "type": "number"
        +                        },
        +                        "issuer": {
        +                          "type": "string"
        +                        }
        +                      },
        +                      "required": [
        +                        "issuer",
        +                        "count"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "type": "array"
        +                  },
        +                  "top_products": {
        +                    "items": {
        +                      "additionalProperties": false,
        +                      "properties": {
        +                        "count": {
        +                          "type": "number"
        +                        },
        +                        "product": {
        +                          "type": "string"
        +                        }
        +                      },
        +                      "required": [
        +                        "product",
        +                        "count"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "type": "array"
        +                  },
        +                  "total": {
        +                    "type": "number"
        +                  },
        +                  "trend_30d": {
        +                    "items": {
        +                      "additionalProperties": false,
        +                      "properties": {
        +                        "count": {
        +                          "type": "number"
        +                        },
        +                        "date": {
        +                          "type": "string"
        +                        }
        +                      },
        +                      "required": [
        +                        "date",
        +                        "count"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "type": "array"
        +                  }
        +                },
        +                "type": "object"
        +              },
        +              "poller": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "last_run_at": {
        +                    "description": "An RFC 3339 instant.",
        +                    "type": "string"
        +                  },
        +                  "running": {
        +                    "type": "boolean"
        +                  }
        +                },
        +                "required": [
        +                  "running",
        +                  "last_run_at"
        +                ],
        +                "type": "object"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "kev_exposure",
        +          "exposed_databases",
        +          "leaked_credentials",
        +          "shadow_ai",
        +          "mcp_servers"
        +        ],
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "exposed_databases": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "last_run_at": {
        +                    "anyOf": [
        +                      {
        +                        "description": "An RFC 3339 instant.",
        +                        "type": "string"
        +                      },
        +                      {
        +                        "type": "null"
        +                      }
        +                    ]
        +                  }
        +                },
        +                "required": [
        +                  "last_run_at"
        +                ],
        +                "type": "object"
        +              },
        +              "kev_exposure": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "last_run_at": {
        +                    "anyOf": [
        +                      {
        +                        "description": "An RFC 3339 instant.",
        +                        "type": "string"
        +                      },
        +                      {
        +                        "type": "null"
        +                      }
        +                    ]
        +                  }
        +                },
        +                "required": [
        +                  "last_run_at"
        +                ],
        +                "type": "object"
        +              },
        +              "leaked_credentials": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "last_run_at": {
        +                    "anyOf": [
        +                      {
        +                        "description": "An RFC 3339 instant.",
        +                        "type": "string"
        +                      },
        +                      {
        +                        "type": "null"
        +                      }
        +                    ]
        +                  }
        +                },
        +                "required": [
        +                  "last_run_at"
        +                ],
        +                "type": "object"
        +              },
        +              "mcp_servers": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "enabled": {
        +                    "type": [
        +                      "boolean",
        +                      "null"
        +                    ]
        +                  },
        +                  "last_run_at": {
        +                    "anyOf": [
        +                      {
        +                        "description": "An RFC 3339 instant.",
        +                        "type": "string"
        +                      },
        +                      {
        +                        "type": "null"
        +                      }
        +                    ]
        +                  }
        +                },
        +                "required": [
        +                  "last_run_at",
        +                  "enabled"
        +                ],
        +                "type": "object"
        +              },
        +              "shadow_ai": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "last_run_at": {
        +                    "anyOf": [
        +                      {
        +                        "description": "An RFC 3339 instant.",
        +                        "type": "string"
        +                      },
        +                      {
        +                        "type": "null"
        +                      }
        +                    ]
        +                  },
        +                  "running": {
        +                    "type": [
        +                      "boolean",
        +                      "null"
        +                    ]
        +                  }
        +                },
        +                "required": [
        +                  "last_run_at",
        +                  "running"
        +                ],
        +                "type": "object"
        +              }
        +            },
        +            "required": [
        +              "kev_exposure",
        +              "exposed_databases",
        +              "leaked_credentials",
        +              "shadow_ai",
        +              "mcp_servers"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "The producing radar's last completed check (last_run_at), where the API serves one."
        +      },
        +      "measured_at": {
        +        "anyOf": [
        +          {
        +            "description": "An RFC 3339 instant.",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        +      },
        +      "method": {
        +        "description": "How the numbers were produced.",
        +        "type": "string"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        +        "enum": [
        +          "measured",
        +          "not_assessed"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "data"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "answered": {
        +                "description": "The radars that answered. On a failure their answers are withheld.",
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              },
        +              "failed": {
        +                "description": "The radars that could not be read.",
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              },
        +              "radars": {
        +                "description": "The radars this tool reads.",
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            },
        +            "required": [
        +              "radars",
        +              "answered",
        +              "failed"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "error": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "kind": {
        +            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        +            "enum": [
        +              "network",
        +              "timeout",
        +              "http",
        +              "not_json",
        +              "not_object",
        +              "invalid_input",
        +              "internal",
        +              "unexpected_shape",
        +              "radars"
        +            ],
        +            "type": "string"
        +          },
        +          "message": {
        +            "description": "The cause: the API's own message, or what went wrong.",
        +            "type": "string"
        +          },
        +          "path": {
        +            "description": "The API path requested, when a request was made.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "radars": {
        +            "description": "Each radar that could not be read, and why.",
        +            "items": {
        +              "additionalProperties": false,
        +              "properties": {
        +                "kind": {
        +                  "enum": [
        +                    "network",
        +                    "timeout",
        +                    "http",
        +                    "not_json",
        +                    "not_object",
        +                    "unexpected_shape"
        +                  ],
        +                  "type": "string"
        +                },
        +                "message": {
        +                  "type": "string"
        +                },
        +                "path": {
        +                  "type": "string"
        +                },
        +                "radar": {
        +                  "type": "string"
        +                },
        +                "status": {
        +                  "anyOf": [
        +                    {
        +                      "maximum": 9007199254740991,
        +                      "minimum": -9007199254740991,
        +                      "type": "integer"
        +                    },
        +                    {
        +                      "type": "null"
        +                    }
        +                  ]
        +                }
        +              },
        +              "required": [
        +                "radar",
        +                "kind",
        +                "path",
        +                "status",
        +                "message"
        +              ],
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "status": {
        +            "anyOf": [
        +              {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "The HTTP status, when the API answered one."
        +          }
        +        },
        +        "required": [
        +          "kind",
        +          "path",
        +          "status",
        +          "message"
        +        ],
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "type": "null"
        +      },
        +      "method": {
        +        "type": "null"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        +        "enum": [
        +          "failed",
        +          "invalid_input"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "error"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedget_vendor_advisory1 field changed
      • changedOutput schema / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "description": "What the answer covers; null where the answer says nothing about it.",
        -        "type": "null"
        -      },
        -      "data": {
        -        "additionalProperties": {},
        -        "properties": {
        -          "advisory_id": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "affected_products": {
        -            "anyOf": [
        -              {
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ]
        -          },
        -          "cve_ids": {
        -            "anyOf": [
        -              {
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ]
        -          },
        -          "cvss_v3_score": {
        -            "type": [
        -              "number",
        -              "null"
        -            ]
        -          },
        -          "description": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "known_cve_ids": {
        -            "anyOf": [
        -              {
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ],
        -            "description": "The CVE IDs of cve_ids that have a record in EchelonGraph's CVE feed."
        -          },
        -          "our_first_seen_at": {
        -            "description": "When EchelonGraph first recorded the advisory; not the vendor's date.",
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "references": {},
        -          "remediation": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "severity": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "summary": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "title": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "vendor": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "vendor_advisory_id": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "vendor_display_name": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "vendor_modified_at": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "vendor_published_at": {
        -            "description": "The date the vendor gives for the advisory.",
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "withdrawn": {
        -            "description": "true: the vendor withdrew (rescinded) this advisory; report it as withdrawn.",
        -            "type": [
        -              "boolean",
        -              "null"
        -            ]
        -          },
        -          "withdrawn_at": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "withdrawn_reason": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          }
        -        },
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "anyOf": [
        -          {
        -            "description": "An RFC 3339 instant.",
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        -      },
        -      "method": {
        -        "description": "How the numbers were produced.",
        -        "type": "string"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        -        "enum": [
        -          "measured",
        -          "not_assessed"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "data"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "type": "null"
        -      },
        -      "error": {
        -        "additionalProperties": false,
        -        "properties": {
        -          "kind": {
        -            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        -            "enum": [
        -              "network",
        -              "timeout",
        -              "http",
        -              "not_json",
        -              "not_object",
        -              "invalid_input",
        -              "internal",
        -              "unexpected_shape",
        -              "radars"
        -            ],
        -            "type": "string"
        -          },
        -          "message": {
        -            "description": "The cause: the API's own message, or what went wrong.",
        -            "type": "string"
        -          },
        -          "path": {
        -            "description": "The API path requested, when a request was made.",
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "status": {
        -            "anyOf": [
        -              {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ],
        -            "description": "The HTTP status, when the API answered one."
        -          }
        -        },
        -        "required": [
        -          "kind",
        -          "path",
        -          "status",
        -          "message"
        -        ],
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "type": "null"
        -      },
        -      "method": {
        -        "type": "null"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        -        "enum": [
        -          "failed",
        -          "invalid_input"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "error"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "vendor_window": {
        +                "anyOf": [
        +                  {
        +                    "additionalProperties": false,
        +                    "properties": {
        +                      "advisories": {
        +                        "description": "How many advisories EchelonGraph holds from this vendor, withdrawn ones not counted.",
        +                        "type": [
        +                          "number",
        +                          "null"
        +                        ]
        +                      },
        +                      "earliest_vendor_published_at": {
        +                        "description": "The earliest vendor_published_at among them; null when none is held. An advisory this vendor published before it is not held.",
        +                        "type": [
        +                          "string",
        +                          "null"
        +                        ]
        +                      },
        +                      "history_backfill": {
        +                        "anyOf": [
        +                          {
        +                            "anyOf": [
        +                              {
        +                                "enum": [
        +                                  "complete",
        +                                  "in_progress",
        +                                  "not_started",
        +                                  "not_supported"
        +                                ],
        +                                "type": "string"
        +                              },
        +                              {
        +                                "type": "string"
        +                              }
        +                            ]
        +                          },
        +                          {
        +                            "type": "null"
        +                          }
        +                        ],
        +                        "description": "history_backfill: complete (the vendor's published history has been read back as far as its source goes), in_progress or not_started (it is still being read, so the vendor's older advisories are not all held yet), or not_supported (EchelonGraph has no history read for that vendor, so what it holds is what the vendor's feed has carried)."
        +                      },
        +                      "latest_vendor_published_at": {
        +                        "description": "The latest vendor_published_at among them; null when none is held.",
        +                        "type": [
        +                          "string",
        +                          "null"
        +                        ]
        +                      },
        +                      "vendor": {
        +                        "description": "The vendor slug.",
        +                        "type": "string"
        +                      },
        +                      "vendor_display_name": {
        +                        "type": [
        +                          "string",
        +                          "null"
        +                        ]
        +                      }
        +                    },
        +                    "required": [
        +                      "vendor",
        +                      "vendor_display_name",
        +                      "advisories",
        +                      "earliest_vendor_published_at",
        +                      "latest_vendor_published_at",
        +                      "history_backfill"
        +                    ],
        +                    "type": "object"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "This advisory's vendor's window in what EchelonGraph holds; null when the windows could not be read or carry none for this vendor."
        +              }
        +            },
        +            "required": [
        +              "vendor_window"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "What the answer covers; null where the answer says nothing about it."
        +      },
        +      "data": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "advisory_id": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "affected_products": {
        +            "anyOf": [
        +              {
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ]
        +          },
        +          "cve_ids": {
        +            "anyOf": [
        +              {
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ]
        +          },
        +          "cvss_v3_score": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "description": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "known_cve_ids": {
        +            "anyOf": [
        +              {
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "The CVE IDs of cve_ids that have a record in EchelonGraph's CVE feed."
        +          },
        +          "our_first_seen_at": {
        +            "description": "When EchelonGraph first recorded the advisory; not the vendor's date.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "references": {},
        +          "remediation": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "severity": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "summary": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "title": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "vendor": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "vendor_advisory_id": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "vendor_display_name": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "vendor_modified_at": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "vendor_published_at": {
        +            "description": "The date the vendor gives for the advisory.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "withdrawn": {
        +            "description": "true: the vendor withdrew (rescinded) this advisory; report it as withdrawn.",
        +            "type": [
        +              "boolean",
        +              "null"
        +            ]
        +          },
        +          "withdrawn_at": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "withdrawn_reason": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "anyOf": [
        +          {
        +            "description": "An RFC 3339 instant.",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        +      },
        +      "method": {
        +        "description": "How the numbers were produced.",
        +        "type": "string"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        +        "enum": [
        +          "measured",
        +          "not_assessed"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "data"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "vendor_window": {
        +                "anyOf": [
        +                  {
        +                    "additionalProperties": false,
        +                    "properties": {
        +                      "advisories": {
        +                        "description": "How many advisories EchelonGraph holds from this vendor, withdrawn ones not counted.",
        +                        "type": [
        +                          "number",
        +                          "null"
        +                        ]
        +                      },
        +                      "earliest_vendor_published_at": {
        +                        "description": "The earliest vendor_published_at among them; null when none is held. An advisory this vendor published before it is not held.",
        +                        "type": [
        +                          "string",
        +                          "null"
        +                        ]
        +                      },
        +                      "history_backfill": {
        +                        "anyOf": [
        +                          {
        +                            "anyOf": [
        +                              {
        +                                "enum": [
        +                                  "complete",
        +                                  "in_progress",
        +                                  "not_started",
        +                                  "not_supported"
        +                                ],
        +                                "type": "string"
        +                              },
        +                              {
        +                                "type": "string"
        +                              }
        +                            ]
        +                          },
        +                          {
        +                            "type": "null"
        +                          }
        +                        ],
        +                        "description": "history_backfill: complete (the vendor's published history has been read back as far as its source goes), in_progress or not_started (it is still being read, so the vendor's older advisories are not all held yet), or not_supported (EchelonGraph has no history read for that vendor, so what it holds is what the vendor's feed has carried)."
        +                      },
        +                      "latest_vendor_published_at": {
        +                        "description": "The latest vendor_published_at among them; null when none is held.",
        +                        "type": [
        +                          "string",
        +                          "null"
        +                        ]
        +                      },
        +                      "vendor": {
        +                        "description": "The vendor slug.",
        +                        "type": "string"
        +                      },
        +                      "vendor_display_name": {
        +                        "type": [
        +                          "string",
        +                          "null"
        +                        ]
        +                      }
        +                    },
        +                    "required": [
        +                      "vendor",
        +                      "vendor_display_name",
        +                      "advisories",
        +                      "earliest_vendor_published_at",
        +                      "latest_vendor_published_at",
        +                      "history_backfill"
        +                    ],
        +                    "type": "object"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "This advisory's vendor's window in what EchelonGraph holds; null when the windows could not be read or carry none for this vendor."
        +              }
        +            },
        +            "required": [
        +              "vendor_window"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "error": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "kind": {
        +            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        +            "enum": [
        +              "network",
        +              "timeout",
        +              "http",
        +              "not_json",
        +              "not_object",
        +              "invalid_input",
        +              "internal",
        +              "unexpected_shape",
        +              "radars"
        +            ],
        +            "type": "string"
        +          },
        +          "message": {
        +            "description": "The cause: the API's own message, or what went wrong.",
        +            "type": "string"
        +          },
        +          "path": {
        +            "description": "The API path requested, when a request was made.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "status": {
        +            "anyOf": [
        +              {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "The HTTP status, when the API answered one."
        +          }
        +        },
        +        "required": [
        +          "kind",
        +          "path",
        +          "status",
        +          "message"
        +        ],
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "type": "null"
        +      },
        +      "method": {
        +        "type": "null"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        +        "enum": [
        +          "failed",
        +          "invalid_input"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "error"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedsearch_cves1 field changed
      • addedInput schema / properties / offset
        Added value: +{
        +  "description": "rows to skip (default 0)",
        +  "maximum": 10000,
        +  "minimum": 0,
        +  "type": "integer"
        +}
    • Changedsearch_vendor_advisories2 fields changed
      • changedInput schema / properties / query / description
        Previous value: -"free text, at most 100 bytes: a product, an advisory ID, a CVE ID or a keyword, e.g. 'exchange server'"New value: +"free text, at most 100 bytes: a product, an advisory ID, a CVE ID or a keyword, e.g. 'exchange server'; 1 or 2 characters match whole words only"
      • changedOutput schema / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "limit": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "offset": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "returned": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "search_applied": {
        -                "type": [
        -                  "boolean",
        -                  "null"
        -                ]
        -              },
        -              "total": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              }
        -            },
        -            "required": [
        -              "total",
        -              "returned",
        -              "limit",
        -              "offset",
        -              "search_applied"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "What the answer covers; null where the answer says nothing about it."
        -      },
        -      "data": {
        -        "additionalProperties": {},
        -        "properties": {
        -          "advisories": {
        -            "anyOf": [
        -              {
        -                "items": {
        -                  "additionalProperties": {},
        -                  "properties": {
        -                    "advisory_id": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "affected_products": {
        -                      "anyOf": [
        -                        {
        -                          "items": {
        -                            "type": "string"
        -                          },
        -                          "type": "array"
        -                        },
        -                        {
        -                          "type": "null"
        -                        }
        -                      ]
        -                    },
        -                    "cve_ids": {
        -                      "anyOf": [
        -                        {
        -                          "items": {
        -                            "type": "string"
        -                          },
        -                          "type": "array"
        -                        },
        -                        {
        -                          "type": "null"
        -                        }
        -                      ]
        -                    },
        -                    "cvss_v3_score": {
        -                      "type": [
        -                        "number",
        -                        "null"
        -                      ]
        -                    },
        -                    "our_first_seen_at": {
        -                      "description": "When EchelonGraph first recorded the advisory; not the vendor's date.",
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "severity": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "summary": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "title": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "vendor": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "vendor_advisory_id": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "vendor_display_name": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "vendor_published_at": {
        -                      "description": "The date the vendor gives for the advisory.",
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "withdrawn": {
        -                      "description": "true: the vendor withdrew (rescinded) this advisory; report it as withdrawn.",
        -                      "type": [
        -                        "boolean",
        -                        "null"
        -                      ]
        -                    }
        -                  },
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ]
        -          },
        -          "limit": {
        -            "type": [
        -              "number",
        -              "null"
        -            ]
        -          },
        -          "offset": {
        -            "type": [
        -              "number",
        -              "null"
        -            ]
        -          },
        -          "search_applied": {
        -            "description": "Whether a free-text search filtered this answer.",
        -            "type": [
        -              "boolean",
        -              "null"
        -            ]
        -          },
        -          "total": {
        -            "type": [
        -              "number",
        -              "null"
        -            ]
        -          }
        -        },
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "anyOf": [
        -          {
        -            "description": "An RFC 3339 instant.",
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        -      },
        -      "method": {
        -        "description": "How the numbers were produced.",
        -        "type": "string"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        -        "enum": [
        -          "measured",
        -          "not_assessed"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "data"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "limit": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "offset": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "returned": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "search_applied": {
        -                "type": [
        -                  "boolean",
        -                  "null"
        -                ]
        -              },
        -              "total": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              }
        -            },
        -            "required": [
        -              "total",
        -              "returned",
        -              "limit",
        -              "offset",
        -              "search_applied"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "error": {
        -        "additionalProperties": false,
        -        "properties": {
        -          "kind": {
        -            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        -            "enum": [
        -              "network",
        -              "timeout",
        -              "http",
        -              "not_json",
        -              "not_object",
        -              "invalid_input",
        -              "internal",
        -              "unexpected_shape",
        -              "radars"
        -            ],
        -            "type": "string"
        -          },
        -          "message": {
        -            "description": "The cause: the API's own message, or what went wrong.",
        -            "type": "string"
        -          },
        -          "path": {
        -            "description": "The API path requested, when a request was made.",
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "status": {
        -            "anyOf": [
        -              {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ],
        -            "description": "The HTTP status, when the API answered one."
        -          }
        -        },
        -        "required": [
        -          "kind",
        -          "path",
        -          "status",
        -          "message"
        -        ],
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "type": "null"
        -      },
        -      "method": {
        -        "type": "null"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        -        "enum": [
        -          "failed",
        -          "invalid_input"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "error"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "limit": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "offset": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "returned": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "search_applied": {
        +                "type": [
        +                  "boolean",
        +                  "null"
        +                ]
        +              },
        +              "search_match": {
        +                "anyOf": [
        +                  {
        +                    "enum": [
        +                      "word",
        +                      "substring"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "word: a query of 1 or 2 characters, matched as a whole word only; substring: a longer query; null without a query."
        +              },
        +              "total": {
        +                "description": "The API's total; when total_capped is true, a lower bound, not the count.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "total_capped": {
        +                "description": "true: total is the API's cap on a search's count, so 1,000 or more match.",
        +                "type": [
        +                  "boolean",
        +                  "null"
        +                ]
        +              },
        +              "vendor_windows": {
        +                "anyOf": [
        +                  {
        +                    "items": {
        +                      "additionalProperties": false,
        +                      "properties": {
        +                        "advisories": {
        +                          "description": "How many advisories EchelonGraph holds from this vendor, withdrawn ones not counted.",
        +                          "type": [
        +                            "number",
        +                            "null"
        +                          ]
        +                        },
        +                        "earliest_vendor_published_at": {
        +                          "description": "The earliest vendor_published_at among them; null when none is held. An advisory this vendor published before it is not held.",
        +                          "type": [
        +                            "string",
        +                            "null"
        +                          ]
        +                        },
        +                        "history_backfill": {
        +                          "anyOf": [
        +                            {
        +                              "anyOf": [
        +                                {
        +                                  "enum": [
        +                                    "complete",
        +                                    "in_progress",
        +                                    "not_started",
        +                                    "not_supported"
        +                                  ],
        +                                  "type": "string"
        +                                },
        +                                {
        +                                  "type": "string"
        +                                }
        +                              ]
        +                            },
        +                            {
        +                              "type": "null"
        +                            }
        +                          ],
        +                          "description": "history_backfill: complete (the vendor's published history has been read back as far as its source goes), in_progress or not_started (it is still being read, so the vendor's older advisories are not all held yet), or not_supported (EchelonGraph has no history read for that vendor, so what it holds is what the vendor's feed has carried)."
        +                        },
        +                        "latest_vendor_published_at": {
        +                          "description": "The latest vendor_published_at among them; null when none is held.",
        +                          "type": [
        +                            "string",
        +                            "null"
        +                          ]
        +                        },
        +                        "vendor": {
        +                          "description": "The vendor slug.",
        +                          "type": "string"
        +                        },
        +                        "vendor_display_name": {
        +                          "type": [
        +                            "string",
        +                            "null"
        +                          ]
        +                        }
        +                      },
        +                      "required": [
        +                        "vendor",
        +                        "vendor_display_name",
        +                        "advisories",
        +                        "earliest_vendor_published_at",
        +                        "latest_vendor_published_at",
        +                        "history_backfill"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "type": "array"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Each vendor's window in what EchelonGraph holds; null when the windows could not be read. An advisory a vendor published before its earliest_vendor_published_at is not held, so no advisory from a vendor is not a finding that it published none."
        +              }
        +            },
        +            "required": [
        +              "total",
        +              "total_capped",
        +              "returned",
        +              "limit",
        +              "offset",
        +              "search_applied",
        +              "search_match",
        +              "vendor_windows"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "What the answer covers; null where the answer says nothing about it."
        +      },
        +      "data": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "advisories": {
        +            "anyOf": [
        +              {
        +                "items": {
        +                  "additionalProperties": {},
        +                  "properties": {
        +                    "advisory_id": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "affected_products": {
        +                      "anyOf": [
        +                        {
        +                          "items": {
        +                            "type": "string"
        +                          },
        +                          "type": "array"
        +                        },
        +                        {
        +                          "type": "null"
        +                        }
        +                      ]
        +                    },
        +                    "cve_ids": {
        +                      "anyOf": [
        +                        {
        +                          "items": {
        +                            "type": "string"
        +                          },
        +                          "type": "array"
        +                        },
        +                        {
        +                          "type": "null"
        +                        }
        +                      ]
        +                    },
        +                    "cvss_v3_score": {
        +                      "type": [
        +                        "number",
        +                        "null"
        +                      ]
        +                    },
        +                    "our_first_seen_at": {
        +                      "description": "When EchelonGraph first recorded the advisory; not the vendor's date.",
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "severity": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "summary": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "title": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "vendor": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "vendor_advisory_id": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "vendor_display_name": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "vendor_published_at": {
        +                      "description": "The date the vendor gives for the advisory.",
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "withdrawn": {
        +                      "description": "true: the vendor withdrew (rescinded) this advisory; report it as withdrawn.",
        +                      "type": [
        +                        "boolean",
        +                        "null"
        +                      ]
        +                    }
        +                  },
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ]
        +          },
        +          "limit": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "offset": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "search_applied": {
        +            "description": "Whether a free-text search filtered this answer.",
        +            "type": [
        +              "boolean",
        +              "null"
        +            ]
        +          },
        +          "search_match": {
        +            "description": "How the query was matched: word (a query of 1 or 2 characters, whole words only) or substring; null without a query.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "total": {
        +            "description": "The matches; when total_capped is true, a lower bound: 1,000 or more.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "total_capped": {
        +            "description": "true: the search stopped counting at total, so total is a lower bound (1,000+), not the count.",
        +            "type": [
        +              "boolean",
        +              "null"
        +            ]
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "anyOf": [
        +          {
        +            "description": "An RFC 3339 instant.",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        +      },
        +      "method": {
        +        "description": "How the numbers were produced.",
        +        "type": "string"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        +        "enum": [
        +          "measured",
        +          "not_assessed"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "data"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "limit": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "offset": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "returned": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "search_applied": {
        +                "type": [
        +                  "boolean",
        +                  "null"
        +                ]
        +              },
        +              "search_match": {
        +                "anyOf": [
        +                  {
        +                    "enum": [
        +                      "word",
        +                      "substring"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "word: a query of 1 or 2 characters, matched as a whole word only; substring: a longer query; null without a query."
        +              },
        +              "total": {
        +                "description": "The API's total; when total_capped is true, a lower bound, not the count.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "total_capped": {
        +                "description": "true: total is the API's cap on a search's count, so 1,000 or more match.",
        +                "type": [
        +                  "boolean",
        +                  "null"
        +                ]
        +              },
        +              "vendor_windows": {
        +                "anyOf": [
        +                  {
        +                    "items": {
        +                      "additionalProperties": false,
        +                      "properties": {
        +                        "advisories": {
        +                          "description": "How many advisories EchelonGraph holds from this vendor, withdrawn ones not counted.",
        +                          "type": [
        +                            "number",
        +                            "null"
        +                          ]
        +                        },
        +                        "earliest_vendor_published_at": {
        +                          "description": "The earliest vendor_published_at among them; null when none is held. An advisory this vendor published before it is not held.",
        +                          "type": [
        +                            "string",
        +                            "null"
        +                          ]
        +                        },
        +                        "history_backfill": {
        +                          "anyOf": [
        +                            {
        +                              "anyOf": [
        +                                {
        +                                  "enum": [
        +                                    "complete",
        +                                    "in_progress",
        +                                    "not_started",
        +                                    "not_supported"
        +                                  ],
        +                                  "type": "string"
        +                                },
        +                                {
        +                                  "type": "string"
        +                                }
        +                              ]
        +                            },
        +                            {
        +                              "type": "null"
        +                            }
        +                          ],
        +                          "description": "history_backfill: complete (the vendor's published history has been read back as far as its source goes), in_progress or not_started (it is still being read, so the vendor's older advisories are not all held yet), or not_supported (EchelonGraph has no history read for that vendor, so what it holds is what the vendor's feed has carried)."
        +                        },
        +                        "latest_vendor_published_at": {
        +                          "description": "The latest vendor_published_at among them; null when none is held.",
        +                          "type": [
        +                            "string",
        +                            "null"
        +                          ]
        +                        },
        +                        "vendor": {
        +                          "description": "The vendor slug.",
        +                          "type": "string"
        +                        },
        +                        "vendor_display_name": {
        +                          "type": [
        +                            "string",
        +                            "null"
        +                          ]
        +                        }
        +                      },
        +                      "required": [
        +                        "vendor",
        +                        "vendor_display_name",
        +                        "advisories",
        +                        "earliest_vendor_published_at",
        +                        "latest_vendor_published_at",
        +                        "history_backfill"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "type": "array"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Each vendor's window in what EchelonGraph holds; null when the windows could not be read. An advisory a vendor published before its earliest_vendor_published_at is not held, so no advisory from a vendor is not a finding that it published none."
        +              }
        +            },
        +            "required": [
        +              "total",
        +              "total_capped",
        +              "returned",
        +              "limit",
        +              "offset",
        +              "search_applied",
        +              "search_match",
        +              "vendor_windows"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "error": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "kind": {
        +            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        +            "enum": [
        +              "network",
        +              "timeout",
        +              "http",
        +              "not_json",
        +              "not_object",
        +              "invalid_input",
        +              "internal",
        +              "unexpected_shape",
        +              "radars"
        +            ],
        +            "type": "string"
        +          },
        +          "message": {
        +            "description": "The cause: the API's own message, or what went wrong.",
        +            "type": "string"
        +          },
        +          "path": {
        +            "description": "The API path requested, when a request was made.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "status": {
        +            "anyOf": [
        +              {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "The HTTP status, when the API answered one."
        +          }
        +        },
        +        "required": [
        +          "kind",
        +          "path",
        +          "status",
        +          "message"
        +        ],
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "type": "null"
        +      },
        +      "method": {
        +        "type": "null"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        +        "enum": [
        +          "failed",
        +          "invalid_input"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "error"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedvendor_advisories_for_cve1 field changed
      • changedOutput schema / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "at_cap": {
        -                "description": "true: the answer is full, so the vendor feeds may hold more advisories for this CVE than it lists.",
        -                "type": [
        -                  "boolean",
        -                  "null"
        -                ]
        -              },
        -              "cap": {
        -                "description": "The most the API returns for one CVE, newest first.",
        -                "type": "number"
        -              },
        -              "returned": {
        -                "description": "The advisories in this answer.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              }
        -            },
        -            "required": [
        -              "returned",
        -              "cap",
        -              "at_cap"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "What the answer covers; null where the answer says nothing about it."
        -      },
        -      "data": {
        -        "additionalProperties": {},
        -        "properties": {
        -          "advisories": {
        -            "anyOf": [
        -              {
        -                "items": {
        -                  "additionalProperties": {},
        -                  "properties": {
        -                    "advisory_id": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "affected_products": {
        -                      "anyOf": [
        -                        {
        -                          "items": {
        -                            "type": "string"
        -                          },
        -                          "type": "array"
        -                        },
        -                        {
        -                          "type": "null"
        -                        }
        -                      ]
        -                    },
        -                    "cve_ids": {
        -                      "anyOf": [
        -                        {
        -                          "items": {
        -                            "type": "string"
        -                          },
        -                          "type": "array"
        -                        },
        -                        {
        -                          "type": "null"
        -                        }
        -                      ]
        -                    },
        -                    "cvss_v3_score": {
        -                      "type": [
        -                        "number",
        -                        "null"
        -                      ]
        -                    },
        -                    "our_first_seen_at": {
        -                      "description": "When EchelonGraph first recorded the advisory; not the vendor's date.",
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "severity": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "summary": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "title": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "vendor": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "vendor_advisory_id": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "vendor_display_name": {
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "vendor_published_at": {
        -                      "description": "The date the vendor gives for the advisory.",
        -                      "type": [
        -                        "string",
        -                        "null"
        -                      ]
        -                    },
        -                    "withdrawn": {
        -                      "description": "true: the vendor withdrew (rescinded) this advisory; report it as withdrawn.",
        -                      "type": [
        -                        "boolean",
        -                        "null"
        -                      ]
        -                    }
        -                  },
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ]
        -          },
        -          "cve_id": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "total": {
        -            "type": [
        -              "number",
        -              "null"
        -            ]
        -          }
        -        },
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "anyOf": [
        -          {
        -            "description": "An RFC 3339 instant.",
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        -      },
        -      "method": {
        -        "description": "How the numbers were produced.",
        -        "type": "string"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        -        "enum": [
        -          "measured",
        -          "not_assessed"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "data"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "at_cap": {
        -                "description": "true: the answer is full, so the vendor feeds may hold more advisories for this CVE than it lists.",
        -                "type": [
        -                  "boolean",
        -                  "null"
        -                ]
        -              },
        -              "cap": {
        -                "description": "The most the API returns for one CVE, newest first.",
        -                "type": "number"
        -              },
        -              "returned": {
        -                "description": "The advisories in this answer.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              }
        -            },
        -            "required": [
        -              "returned",
        -              "cap",
        -              "at_cap"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "error": {
        -        "additionalProperties": false,
        -        "properties": {
        -          "kind": {
        -            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        -            "enum": [
        -              "network",
        -              "timeout",
        -              "http",
        -              "not_json",
        -              "not_object",
        -              "invalid_input",
        -              "internal",
        -              "unexpected_shape",
        -              "radars"
        -            ],
        -            "type": "string"
        -          },
        -          "message": {
        -            "description": "The cause: the API's own message, or what went wrong.",
        -            "type": "string"
        -          },
        -          "path": {
        -            "description": "The API path requested, when a request was made.",
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "status": {
        -            "anyOf": [
        -              {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ],
        -            "description": "The HTTP status, when the API answered one."
        -          }
        -        },
        -        "required": [
        -          "kind",
        -          "path",
        -          "status",
        -          "message"
        -        ],
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "type": "null"
        -      },
        -      "method": {
        -        "type": "null"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        -        "enum": [
        -          "failed",
        -          "invalid_input"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "error"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "at_cap": {
        +                "description": "true: the answer is full, so the vendor feeds may hold more advisories for this CVE than it lists.",
        +                "type": [
        +                  "boolean",
        +                  "null"
        +                ]
        +              },
        +              "cap": {
        +                "description": "The most the API returns for one CVE, newest first.",
        +                "type": "number"
        +              },
        +              "cve_year": {
        +                "description": "The year in the CVE ID.",
        +                "type": "number"
        +              },
        +              "returned": {
        +                "description": "The advisories in this answer.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "vendor_windows": {
        +                "anyOf": [
        +                  {
        +                    "items": {
        +                      "additionalProperties": false,
        +                      "properties": {
        +                        "advisories": {
        +                          "description": "How many advisories EchelonGraph holds from this vendor, withdrawn ones not counted.",
        +                          "type": [
        +                            "number",
        +                            "null"
        +                          ]
        +                        },
        +                        "earliest_vendor_published_at": {
        +                          "description": "The earliest vendor_published_at among them; null when none is held. An advisory this vendor published before it is not held.",
        +                          "type": [
        +                            "string",
        +                            "null"
        +                          ]
        +                        },
        +                        "history_backfill": {
        +                          "anyOf": [
        +                            {
        +                              "anyOf": [
        +                                {
        +                                  "enum": [
        +                                    "complete",
        +                                    "in_progress",
        +                                    "not_started",
        +                                    "not_supported"
        +                                  ],
        +                                  "type": "string"
        +                                },
        +                                {
        +                                  "type": "string"
        +                                }
        +                              ]
        +                            },
        +                            {
        +                              "type": "null"
        +                            }
        +                          ],
        +                          "description": "history_backfill: complete (the vendor's published history has been read back as far as its source goes), in_progress or not_started (it is still being read, so the vendor's older advisories are not all held yet), or not_supported (EchelonGraph has no history read for that vendor, so what it holds is what the vendor's feed has carried)."
        +                        },
        +                        "latest_vendor_published_at": {
        +                          "description": "The latest vendor_published_at among them; null when none is held.",
        +                          "type": [
        +                            "string",
        +                            "null"
        +                          ]
        +                        },
        +                        "vendor": {
        +                          "description": "The vendor slug.",
        +                          "type": "string"
        +                        },
        +                        "vendor_display_name": {
        +                          "type": [
        +                            "string",
        +                            "null"
        +                          ]
        +                        }
        +                      },
        +                      "required": [
        +                        "vendor",
        +                        "vendor_display_name",
        +                        "advisories",
        +                        "earliest_vendor_published_at",
        +                        "latest_vendor_published_at",
        +                        "history_backfill"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "type": "array"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Each vendor's window in what EchelonGraph holds; null when the windows could not be read. An advisory a vendor published before its earliest_vendor_published_at is not held, so no advisory from a vendor is not a finding that it published none."
        +              },
        +              "vendors_not_fully_held": {
        +                "anyOf": [
        +                  {
        +                    "items": {
        +                      "type": "string"
        +                    },
        +                    "type": "array"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "The vendors with no advisory in this answer that may have published one EchelonGraph does not hold: none held, the earliest held dated after 1 January of cve_year, or history_backfill in_progress or not_started. No advisory from them is not a finding that they published none. null when the windows could not be read."
        +              }
        +            },
        +            "required": [
        +              "returned",
        +              "cap",
        +              "at_cap",
        +              "cve_year",
        +              "vendor_windows",
        +              "vendors_not_fully_held"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "What the answer covers; null where the answer says nothing about it."
        +      },
        +      "data": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "advisories": {
        +            "anyOf": [
        +              {
        +                "items": {
        +                  "additionalProperties": {},
        +                  "properties": {
        +                    "advisory_id": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "affected_products": {
        +                      "anyOf": [
        +                        {
        +                          "items": {
        +                            "type": "string"
        +                          },
        +                          "type": "array"
        +                        },
        +                        {
        +                          "type": "null"
        +                        }
        +                      ]
        +                    },
        +                    "cve_ids": {
        +                      "anyOf": [
        +                        {
        +                          "items": {
        +                            "type": "string"
        +                          },
        +                          "type": "array"
        +                        },
        +                        {
        +                          "type": "null"
        +                        }
        +                      ]
        +                    },
        +                    "cvss_v3_score": {
        +                      "type": [
        +                        "number",
        +                        "null"
        +                      ]
        +                    },
        +                    "our_first_seen_at": {
        +                      "description": "When EchelonGraph first recorded the advisory; not the vendor's date.",
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "severity": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "summary": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "title": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "vendor": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "vendor_advisory_id": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "vendor_display_name": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "vendor_published_at": {
        +                      "description": "The date the vendor gives for the advisory.",
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "withdrawn": {
        +                      "description": "true: the vendor withdrew (rescinded) this advisory; report it as withdrawn.",
        +                      "type": [
        +                        "boolean",
        +                        "null"
        +                      ]
        +                    }
        +                  },
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ]
        +          },
        +          "cve_id": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "total": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "anyOf": [
        +          {
        +            "description": "An RFC 3339 instant.",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        +      },
        +      "method": {
        +        "description": "How the numbers were produced.",
        +        "type": "string"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        +        "enum": [
        +          "measured",
        +          "not_assessed"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "data"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "at_cap": {
        +                "description": "true: the answer is full, so the vendor feeds may hold more advisories for this CVE than it lists.",
        +                "type": [
        +                  "boolean",
        +                  "null"
        +                ]
        +              },
        +              "cap": {
        +                "description": "The most the API returns for one CVE, newest first.",
        +                "type": "number"
        +              },
        +              "cve_year": {
        +                "description": "The year in the CVE ID.",
        +                "type": "number"
        +              },
        +              "returned": {
        +                "description": "The advisories in this answer.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "vendor_windows": {
        +                "anyOf": [
        +                  {
        +                    "items": {
        +                      "additionalProperties": false,
        +                      "properties": {
        +                        "advisories": {
        +                          "description": "How many advisories EchelonGraph holds from this vendor, withdrawn ones not counted.",
        +                          "type": [
        +                            "number",
        +                            "null"
        +                          ]
        +                        },
        +                        "earliest_vendor_published_at": {
        +                          "description": "The earliest vendor_published_at among them; null when none is held. An advisory this vendor published before it is not held.",
        +                          "type": [
        +                            "string",
        +                            "null"
        +                          ]
        +                        },
        +                        "history_backfill": {
        +                          "anyOf": [
        +                            {
        +                              "anyOf": [
        +                                {
        +                                  "enum": [
        +                                    "complete",
        +                                    "in_progress",
        +                                    "not_started",
        +                                    "not_supported"
        +                                  ],
        +                                  "type": "string"
        +                                },
        +                                {
        +                                  "type": "string"
        +                                }
        +                              ]
        +                            },
        +                            {
        +                              "type": "null"
        +                            }
        +                          ],
        +                          "description": "history_backfill: complete (the vendor's published history has been read back as far as its source goes), in_progress or not_started (it is still being read, so the vendor's older advisories are not all held yet), or not_supported (EchelonGraph has no history read for that vendor, so what it holds is what the vendor's feed has carried)."
        +                        },
        +                        "latest_vendor_published_at": {
        +                          "description": "The latest vendor_published_at among them; null when none is held.",
        +                          "type": [
        +                            "string",
        +                            "null"
        +                          ]
        +                        },
        +                        "vendor": {
        +                          "description": "The vendor slug.",
        +                          "type": "string"
        +                        },
        +                        "vendor_display_name": {
        +                          "type": [
        +                            "string",
        +                            "null"
        +                          ]
        +                        }
        +                      },
        +                      "required": [
        +                        "vendor",
        +                        "vendor_display_name",
        +                        "advisories",
        +                        "earliest_vendor_published_at",
        +                        "latest_vendor_published_at",
        +                        "history_backfill"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "type": "array"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Each vendor's window in what EchelonGraph holds; null when the windows could not be read. An advisory a vendor published before its earliest_vendor_published_at is not held, so no advisory from a vendor is not a finding that it published none."
        +              },
        +              "vendors_not_fully_held": {
        +                "anyOf": [
        +                  {
        +                    "items": {
        +                      "type": "string"
        +                    },
        +                    "type": "array"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "The vendors with no advisory in this answer that may have published one EchelonGraph does not hold: none held, the earliest held dated after 1 January of cve_year, or history_backfill in_progress or not_started. No advisory from them is not a finding that they published none. null when the windows could not be read."
        +              }
        +            },
        +            "required": [
        +              "returned",
        +              "cap",
        +              "at_cap",
        +              "cve_year",
        +              "vendor_windows",
        +              "vendors_not_fully_held"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "error": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "kind": {
        +            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        +            "enum": [
        +              "network",
        +              "timeout",
        +              "http",
        +              "not_json",
        +              "not_object",
        +              "invalid_input",
        +              "internal",
        +              "unexpected_shape",
        +              "radars"
        +            ],
        +            "type": "string"
        +          },
        +          "message": {
        +            "description": "The cause: the API's own message, or what went wrong.",
        +            "type": "string"
        +          },
        +          "path": {
        +            "description": "The API path requested, when a request was made.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "status": {
        +            "anyOf": [
        +              {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "The HTTP status, when the API answered one."
        +          }
        +        },
        +        "required": [
        +          "kind",
        +          "path",
        +          "status",
        +          "message"
        +        ],
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "type": "null"
        +      },
        +      "method": {
        +        "type": "null"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        +        "enum": [
        +          "failed",
        +          "invalid_input"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "error"
        +    ],
        +    "type": "object"
        +  }
        +]
  3. 2 tool updates
    • Changedcve_summary1 field changed
      • changedOutput schema / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "description": "What the answer covers; null where the answer says nothing about it.",
        -        "type": "null"
        -      },
        -      "data": {
        -        "additionalProperties": {},
        -        "properties": {
        -          "summary": {
        -            "additionalProperties": {},
        -            "properties": {
        -              "critical": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "high": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "last_updated": {
        -                "type": [
        -                  "string",
        -                  "null"
        -                ]
        -              },
        -              "low": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "medium": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "none": {
        -                "description": "The active CVEs with no severity band from any source: CVEs not yet scored, not a severity rating of None.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "nvd_critical": {
        -                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Critical: NVD's label, as provenance, never EchelonGraph's severity band.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "nvd_high": {
        -                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is High: NVD's label, as provenance, never EchelonGraph's severity band.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "nvd_low": {
        -                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Low: NVD's label, as provenance, never EchelonGraph's severity band.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "nvd_medium": {
        -                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Medium: NVD's label, as provenance, never EchelonGraph's severity band.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "nvd_none": {
        -                "description": "Of the active CVEs total counts, those with no Critical, High, Medium or Low NVD CVSS severity label, many of them with an NVD CVSS v2 score instead: neither a count of CVEs rated None nor the count of CVEs with no severity, which is none.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "rejected": {
        -                "description": "The CVE records rejected (withdrawn) by their numbering authority, which total and every other count here leave out: withdrawn records, never vulnerabilities.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "total": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "unscored": {
        -                "description": "The same count as none, under its own name.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "anyOf": [
        -          {
        -            "description": "An RFC 3339 instant.",
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        -      },
        -      "method": {
        -        "description": "How the numbers were produced.",
        -        "type": "string"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        -        "enum": [
        -          "measured",
        -          "not_assessed"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "data"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "type": "null"
        -      },
        -      "error": {
        -        "additionalProperties": false,
        -        "properties": {
        -          "kind": {
        -            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        -            "enum": [
        -              "network",
        -              "timeout",
        -              "http",
        -              "not_json",
        -              "not_object",
        -              "invalid_input",
        -              "internal",
        -              "unexpected_shape",
        -              "radars"
        -            ],
        -            "type": "string"
        -          },
        -          "message": {
        -            "description": "The cause: the API's own message, or what went wrong.",
        -            "type": "string"
        -          },
        -          "path": {
        -            "description": "The API path requested, when a request was made.",
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "status": {
        -            "anyOf": [
        -              {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ],
        -            "description": "The HTTP status, when the API answered one."
        -          }
        -        },
        -        "required": [
        -          "kind",
        -          "path",
        -          "status",
        -          "message"
        -        ],
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "type": "null"
        -      },
        -      "method": {
        -        "type": "null"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        -        "enum": [
        -          "failed",
        -          "invalid_input"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "error"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "description": "What the answer covers; null where the answer says nothing about it.",
        +        "type": "null"
        +      },
        +      "data": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "poller": {
        +            "anyOf": [
        +              {
        +                "additionalProperties": {},
        +                "properties": {
        +                  "cves_ingested": {
        +                    "description": "CVE records this instance's NVD poller wrote since the instance last started: never the feed's size or intake.",
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  },
        +                  "cves_skipped": {
        +                    "description": "CVE records this instance's NVD poller skipped since the instance last started.",
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  },
        +                  "http_retries": {
        +                    "description": "HTTP retries this instance's NVD poller made since the instance last started.",
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  },
        +                  "interval": {
        +                    "description": "How often this instance's NVD poller polls.",
        +                    "type": [
        +                      "string",
        +                      "null"
        +                    ]
        +                  },
        +                  "last_poll_at": {
        +                    "description": "When this instance's NVD poller last polled: never the feed's freshness.",
        +                    "type": [
        +                      "string",
        +                      "null"
        +                    ]
        +                  },
        +                  "last_poll_dur_ms": {
        +                    "description": "How long that poll took, in milliseconds.",
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  },
        +                  "poll_count": {
        +                    "description": "Polls this instance's NVD poller made since the instance last started.",
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  },
        +                  "poll_errors": {
        +                    "description": "Polls of this instance's NVD poller that failed since the instance last started: never the feed's reliability.",
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  }
        +                },
        +                "type": "object"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "poller holds the in-memory counters of the NVD poller of the one API instance that answered (cves_ingested, cves_skipped, http_retries, poll_count, poll_errors, last_poll_at, last_poll_dur_ms, interval), counted since that instance last started and zeroed on every restart: they describe that instance, never the feed's size, intake, reliability or freshness. Whenever the answer carries poller the note says so."
        +          },
        +          "summary": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "critical": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "high": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "last_updated": {
        +                "type": [
        +                  "string",
        +                  "null"
        +                ]
        +              },
        +              "low": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "medium": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "none": {
        +                "description": "The active CVEs with no severity band from any source: CVEs not yet scored, not a severity rating of None.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "nvd_critical": {
        +                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Critical: NVD's label, as provenance, never EchelonGraph's severity band.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "nvd_high": {
        +                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is High: NVD's label, as provenance, never EchelonGraph's severity band.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "nvd_low": {
        +                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Low: NVD's label, as provenance, never EchelonGraph's severity band.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "nvd_medium": {
        +                "description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Medium: NVD's label, as provenance, never EchelonGraph's severity band.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "nvd_none": {
        +                "description": "Of the active CVEs total counts, those with no Critical, High, Medium or Low NVD CVSS severity label, many of them with an NVD CVSS v2 score instead: neither a count of CVEs rated None nor the count of CVEs with no severity, which is none.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "rejected": {
        +                "description": "The CVE records rejected (withdrawn) by their numbering authority, which total and every other count here leave out: withdrawn records, never vulnerabilities.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "total": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "unscored": {
        +                "description": "The same count as none, under its own name.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "anyOf": [
        +          {
        +            "description": "An RFC 3339 instant.",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        +      },
        +      "method": {
        +        "description": "How the numbers were produced.",
        +        "type": "string"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        +        "enum": [
        +          "measured",
        +          "not_assessed"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "data"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "type": "null"
        +      },
        +      "error": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "kind": {
        +            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        +            "enum": [
        +              "network",
        +              "timeout",
        +              "http",
        +              "not_json",
        +              "not_object",
        +              "invalid_input",
        +              "internal",
        +              "unexpected_shape",
        +              "radars"
        +            ],
        +            "type": "string"
        +          },
        +          "message": {
        +            "description": "The cause: the API's own message, or what went wrong.",
        +            "type": "string"
        +          },
        +          "path": {
        +            "description": "The API path requested, when a request was made.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "status": {
        +            "anyOf": [
        +              {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "The HTTP status, when the API answered one."
        +          }
        +        },
        +        "required": [
        +          "kind",
        +          "path",
        +          "status",
        +          "message"
        +        ],
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "type": "null"
        +      },
        +      "method": {
        +        "type": "null"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        +        "enum": [
        +          "failed",
        +          "invalid_input"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "error"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedkev_recent2 fields changed
      • changedInput schema / properties / since / description
        Previous value: -"earliest kev_added_date to include, YYYY-MM-DD (an RFC 3339 timestamp is read as its UTC date)"New value: +"earliest kev_added_date to include, YYYY-MM-DD (an RFC 3339 timestamp is read as the date written in it)"
      • changedInput schema / properties / until / description
        Previous value: -"latest kev_added_date to include, YYYY-MM-DD (an RFC 3339 timestamp is read as its UTC date)"New value: +"latest kev_added_date to include, YYYY-MM-DD (an RFC 3339 timestamp is read as the date written in it)"
  4. 2 tool updates
    • Changedcheck_sbom2 fields changed
      • changedInput schema / properties / purls / description
        Previous value: -"package URLs to check, e.g. pkg:npm/lodash@4.17.20 or pkg:deb/debian/openssl@3.0.11-1~deb12u1?distro=debian-12 (up to 200)"New value: +"package URLs to check, e.g. pkg:npm/lodash@4.17.20 or pkg:deb/debian/openssl@3.0.11-1~deb12u1?distro=debian-12 (up to 2,000 distinct, sent in batches of 200)"
      • changedOutput schema / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "components_in_document": {
        -                "anyOf": [
        -                  {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ],
        -                "description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
        -              },
        -              "duplicates_removed": {
        -                "description": "Purls that appeared more than once and were sent once.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "input": {
        -                "description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document.",
        -                "enum": [
        -                  "purls",
        -                  "cyclonedx",
        -                  "spdx"
        -                ],
        -                "type": "string"
        -              },
        -              "not_assessed": {
        -                "anyOf": [
        -                  {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ],
        -                "description": "Of those sent, the components with no verdict, as the answer counts them."
        -              },
        -              "partial": {
        -                "description": "The answer's summary.partial: true when the time budget ran out first.",
        -                "type": [
        -                  "boolean",
        -                  "null"
        -                ]
        -              },
        -              "sent": {
        -                "description": "Distinct purls sent and checked.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "with_purl": {
        -                "description": "Of those, the ones carrying a purl.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "without_purl": {
        -                "description": "The ones without a purl: not checked, and not clean.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              }
        -            },
        -            "required": [
        -              "input",
        -              "components_in_document",
        -              "with_purl",
        -              "without_purl",
        -              "duplicates_removed",
        -              "sent",
        -              "not_assessed",
        -              "partial"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "What the answer covers; null where the answer says nothing about it."
        -      },
        -      "data": {
        -        "additionalProperties": {},
        -        "properties": {
        -          "answered_at": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "components": {
        -            "type": [
        -              "number",
        -              "null"
        -            ]
        -          },
        -          "match_layer": {
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "results": {
        -            "items": {
        -              "additionalProperties": {},
        -              "properties": {
        -                "advisories_considered": {
        -                  "type": [
        -                    "number",
        -                    "null"
        -                  ]
        -                },
        -                "assessed": {
        -                  "description": "Whether the matcher produced a verdict for this component. false is never clean.",
        -                  "type": [
        -                    "boolean",
        -                    "null"
        -                  ]
        -                },
        -                "candidates_capped": {
        -                  "type": [
        -                    "boolean",
        -                    "null"
        -                  ]
        -                },
        -                "capped": {
        -                  "type": [
        -                    "boolean",
        -                    "null"
        -                  ]
        -                },
        -                "code": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "count": {
        -                  "type": [
        -                    "number",
        -                    "null"
        -                  ]
        -                },
        -                "cve_ids": {
        -                  "anyOf": [
        -                    {
        -                      "items": {
        -                        "type": "string"
        -                      },
        -                      "type": "array"
        -                    },
        -                    {
        -                      "type": "null"
        -                    }
        -                  ]
        -                },
        -                "ecosystem": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "error": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "index": {
        -                  "type": [
        -                    "number",
        -                    "null"
        -                  ]
        -                },
        -                "input_kind": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "matches": {
        -                  "anyOf": [
        -                    {
        -                      "items": {
        -                        "additionalProperties": {},
        -                        "properties": {
        -                          "cve_id": {
        -                            "type": [
        -                              "string",
        -                              "null"
        -                            ]
        -                          }
        -                        },
        -                        "type": "object"
        -                      },
        -                      "type": "array"
        -                    },
        -                    {
        -                      "type": "null"
        -                    }
        -                  ]
        -                },
        -                "not_affected_count": {
        -                  "type": [
        -                    "number",
        -                    "null"
        -                  ]
        -                },
        -                "not_assessed_reason": {
        -                  "description": "Why assessed is false: package_not_in_advisory_corpus, no_decidable_advisory, advisory_lookup_failed, candidate_window_truncated, time_budget, distro_release_unknown, purl_type_unsupported, version_missing or invalid_component.",
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "package": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "purl": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "undetermined": {
        -                  "anyOf": [
        -                    {
        -                      "items": {
        -                        "additionalProperties": {},
        -                        "properties": {
        -                          "cve_id": {
        -                            "type": [
        -                              "string",
        -                              "null"
        -                            ]
        -                          }
        -                        },
        -                        "type": "object"
        -                      },
        -                      "type": "array"
        -                    },
        -                    {
        -                      "type": "null"
        -                    }
        -                  ]
        -                },
        -                "undetermined_count": {
        -                  "type": [
        -                    "number",
        -                    "null"
        -                  ]
        -                },
        -                "verdict": {
        -                  "description": "affected (count > 0); not_affected (assessed, no match, nothing undetermined: the only clean verdict); undetermined (advisories name the package, at least one could not be decided, none matched: not clean); not_assessed (no verdict: not clean).",
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                },
        -                "version": {
        -                  "type": [
        -                    "string",
        -                    "null"
        -                  ]
        -                }
        -              },
        -              "type": "object"
        -            },
        -            "type": "array"
        -          },
        -          "summary": {
        -            "additionalProperties": {},
        -            "properties": {
        -              "affected": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "components": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "corpus_cache_max_age_ms": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "elapsed_ms": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "lookups": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "not_affected": {
        -                "description": "Components with a decided, clean verdict.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "not_assessed": {
        -                "description": "Components with no verdict: not clean.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "not_assessed_by_reason": {
        -                "anyOf": [
        -                  {
        -                    "additionalProperties": {},
        -                    "properties": {
        -                      "advisory_lookup_failed": {
        -                        "type": "number"
        -                      },
        -                      "candidate_window_truncated": {
        -                        "type": "number"
        -                      },
        -                      "distro_release_unknown": {
        -                        "description": "deb, apk or rpm purls without a distro qualifier naming the release, which EchelonGraph does not guess.",
        -                        "type": "number"
        -                      },
        -                      "invalid_component": {
        -                        "type": "number"
        -                      },
        -                      "no_decidable_advisory": {
        -                        "type": "number"
        -                      },
        -                      "package_not_in_advisory_corpus": {
        -                        "type": "number"
        -                      },
        -                      "purl_type_unsupported": {
        -                        "type": "number"
        -                      },
        -                      "time_budget": {
        -                        "description": "Components the batch's time budget ran out before: not clean; check them again.",
        -                        "type": "number"
        -                      },
        -                      "version_missing": {
        -                        "type": "number"
        -                      }
        -                    },
        -                    "type": "object"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ],
        -                "description": "The not_assessed components, counted by not_assessed_reason."
        -              },
        -              "partial": {
        -                "description": "true when the time budget ran out before every component was looked up.",
        -                "type": [
        -                  "boolean",
        -                  "null"
        -                ]
        -              },
        -              "time_budget_ms": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "undetermined": {
        -                "description": "Components whose advisories could not all be decided and none matched: not clean.",
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "anyOf": [
        -          {
        -            "description": "An RFC 3339 instant.",
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        -      },
        -      "method": {
        -        "description": "How the numbers were produced.",
        -        "type": "string"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        -        "enum": [
        -          "measured",
        -          "not_assessed"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "data"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "coverage": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "components_in_document": {
        -                "anyOf": [
        -                  {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ],
        -                "description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
        -              },
        -              "duplicates_removed": {
        -                "description": "Purls that appeared more than once and were sent once.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "input": {
        -                "description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document.",
        -                "enum": [
        -                  "purls",
        -                  "cyclonedx",
        -                  "spdx"
        -                ],
        -                "type": "string"
        -              },
        -              "not_assessed": {
        -                "anyOf": [
        -                  {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ],
        -                "description": "Of those sent, the components with no verdict, as the answer counts them."
        -              },
        -              "partial": {
        -                "description": "The answer's summary.partial: true when the time budget ran out first.",
        -                "type": [
        -                  "boolean",
        -                  "null"
        -                ]
        -              },
        -              "sent": {
        -                "description": "Distinct purls sent and checked.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "with_purl": {
        -                "description": "Of those, the ones carrying a purl.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "without_purl": {
        -                "description": "The ones without a purl: not checked, and not clean.",
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              }
        -            },
        -            "required": [
        -              "input",
        -              "components_in_document",
        -              "with_purl",
        -              "without_purl",
        -              "duplicates_removed",
        -              "sent",
        -              "not_assessed",
        -              "partial"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "error": {
        -        "additionalProperties": false,
        -        "properties": {
        -          "kind": {
        -            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        -            "enum": [
        -              "network",
        -              "timeout",
        -              "http",
        -              "not_json",
        -              "not_object",
        -              "invalid_input",
        -              "internal",
        -              "unexpected_shape",
        -              "radars"
        -            ],
        -            "type": "string"
        -          },
        -          "message": {
        -            "description": "The cause: the API's own message, or what went wrong.",
        -            "type": "string"
        -          },
        -          "path": {
        -            "description": "The API path requested, when a request was made.",
        -            "type": [
        -              "string",
        -              "null"
        -            ]
        -          },
        -          "status": {
        -            "anyOf": [
        -              {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              {
        -                "type": "null"
        -              }
        -            ],
        -            "description": "The HTTP status, when the API answered one."
        -          }
        -        },
        -        "required": [
        -          "kind",
        -          "path",
        -          "status",
        -          "message"
        -        ],
        -        "type": "object"
        -      },
        -      "freshness": {
        -        "type": "null"
        -      },
        -      "measured_at": {
        -        "type": "null"
        -      },
        -      "method": {
        -        "type": "null"
        -      },
        -      "notes": {
        -        "description": "Caveats, one sentence each.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "state": {
        -        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        -        "enum": [
        -          "failed",
        -          "invalid_input"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "state",
        -      "measured_at",
        -      "method",
        -      "coverage",
        -      "freshness",
        -      "notes",
        -      "error"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "batch_size": {
        +                "description": "The most purls one request carries (the API's cap per request).",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "batches": {
        +                "description": "Requests the distinct purls make, at batch_size each.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "batches_sent": {
        +                "description": "Of those, the ones the API answered.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "components_in_document": {
        +                "anyOf": [
        +                  {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
        +              },
        +              "distinct_purls": {
        +                "description": "Distinct purls to check: sent plus not_sent.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "duplicates_removed": {
        +                "description": "Purls that appeared more than once and were sent once.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "input": {
        +                "description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document.",
        +                "enum": [
        +                  "purls",
        +                  "cyclonedx",
        +                  "spdx"
        +                ],
        +                "type": "string"
        +              },
        +              "not_assessed": {
        +                "anyOf": [
        +                  {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Of those sent, the components with no verdict, as the answer counts them."
        +              },
        +              "not_sent": {
        +                "description": "Distinct purls not sent, listed in data.not_sent_purls: not checked, and not clean.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "not_sent_reason": {
        +                "anyOf": [
        +                  {
        +                    "enum": [
        +                      "time_budget",
        +                      "rate_limited",
        +                      "request_failed"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Why not_sent is above 0: time_budget (the call's 50 s budget ran out, or waiting out the API's Retry-After would pass it), rate_limited (a 429 without Retry-After, or a 429 after 10 waits), request_failed (a batch after the first failed; the note quotes how). null when every purl was sent."
        +              },
        +              "partial": {
        +                "description": "true when not every purl was sent (not_sent above 0) or any batch's summary.partial was true (its time budget ran out first); otherwise the answer's summary.partial.",
        +                "type": [
        +                  "boolean",
        +                  "null"
        +                ]
        +              },
        +              "rate_limit_waits": {
        +                "description": "How many times the API answered 429 and the tool waited its Retry-After before sending the batch again.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "sent": {
        +                "description": "Distinct purls sent and answered.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "waited_ms": {
        +                "description": "Milliseconds spent in those waits.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "with_purl": {
        +                "description": "Of those, the ones carrying a purl.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "without_purl": {
        +                "description": "The ones without a purl: not checked, and not clean.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              }
        +            },
        +            "required": [
        +              "input",
        +              "components_in_document",
        +              "with_purl",
        +              "without_purl",
        +              "duplicates_removed",
        +              "distinct_purls",
        +              "batch_size",
        +              "batches",
        +              "batches_sent",
        +              "sent",
        +              "not_sent",
        +              "not_sent_reason",
        +              "rate_limit_waits",
        +              "waited_ms",
        +              "not_assessed",
        +              "partial"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "What the answer covers; null where the answer says nothing about it."
        +      },
        +      "data": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "answered_at": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "components": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "match_layer": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "not_sent_purls": {
        +            "anyOf": [
        +              {
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "The distinct purls not sent (coverage.not_sent_reason says why): not checked, and not clean. Present only when some were not sent."
        +          },
        +          "results": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "advisories_considered": {
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "assessed": {
        +                  "description": "Whether the matcher produced a verdict for this component. false is never clean.",
        +                  "type": [
        +                    "boolean",
        +                    "null"
        +                  ]
        +                },
        +                "candidates_capped": {
        +                  "type": [
        +                    "boolean",
        +                    "null"
        +                  ]
        +                },
        +                "capped": {
        +                  "type": [
        +                    "boolean",
        +                    "null"
        +                  ]
        +                },
        +                "code": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "count": {
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "cve_ids": {
        +                  "anyOf": [
        +                    {
        +                      "items": {
        +                        "type": "string"
        +                      },
        +                      "type": "array"
        +                    },
        +                    {
        +                      "type": "null"
        +                    }
        +                  ]
        +                },
        +                "ecosystem": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "error": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "index": {
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "input_kind": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "matches": {
        +                  "anyOf": [
        +                    {
        +                      "items": {
        +                        "additionalProperties": {},
        +                        "properties": {
        +                          "cve_id": {
        +                            "type": [
        +                              "string",
        +                              "null"
        +                            ]
        +                          }
        +                        },
        +                        "type": "object"
        +                      },
        +                      "type": "array"
        +                    },
        +                    {
        +                      "type": "null"
        +                    }
        +                  ]
        +                },
        +                "not_affected_count": {
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "not_assessed_reason": {
        +                  "description": "Why assessed is false: package_not_in_advisory_corpus, no_decidable_advisory, advisory_lookup_failed, candidate_window_truncated, time_budget, distro_release_unknown, purl_type_unsupported, version_missing or invalid_component.",
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "package": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "purl": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "undetermined": {
        +                  "anyOf": [
        +                    {
        +                      "items": {
        +                        "additionalProperties": {},
        +                        "properties": {
        +                          "cve_id": {
        +                            "type": [
        +                              "string",
        +                              "null"
        +                            ]
        +                          }
        +                        },
        +                        "type": "object"
        +                      },
        +                      "type": "array"
        +                    },
        +                    {
        +                      "type": "null"
        +                    }
        +                  ]
        +                },
        +                "undetermined_count": {
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "verdict": {
        +                  "description": "affected (count > 0); not_affected (assessed, no match, nothing undetermined: the only clean verdict); undetermined (advisories name the package, at least one could not be decided, none matched: not clean); not_assessed (no verdict: not clean).",
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "version": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "summary": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "affected": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "components": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "corpus_cache_max_age_ms": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "elapsed_ms": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "lookups": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "not_affected": {
        +                "description": "Components with a decided, clean verdict.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "not_assessed": {
        +                "description": "Components with no verdict: not clean.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "not_assessed_by_reason": {
        +                "anyOf": [
        +                  {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "advisory_lookup_failed": {
        +                        "type": "number"
        +                      },
        +                      "candidate_window_truncated": {
        +                        "type": "number"
        +                      },
        +                      "distro_release_unknown": {
        +                        "description": "deb, apk or rpm purls without a distro qualifier naming the release, which EchelonGraph does not guess.",
        +                        "type": "number"
        +                      },
        +                      "invalid_component": {
        +                        "type": "number"
        +                      },
        +                      "no_decidable_advisory": {
        +                        "type": "number"
        +                      },
        +                      "package_not_in_advisory_corpus": {
        +                        "type": "number"
        +                      },
        +                      "purl_type_unsupported": {
        +                        "type": "number"
        +                      },
        +                      "time_budget": {
        +                        "description": "Components the batch's time budget ran out before: not clean; check them again.",
        +                        "type": "number"
        +                      },
        +                      "version_missing": {
        +                        "type": "number"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "The not_assessed components, counted by not_assessed_reason."
        +              },
        +              "partial": {
        +                "description": "true when the time budget ran out before every component was looked up.",
        +                "type": [
        +                  "boolean",
        +                  "null"
        +                ]
        +              },
        +              "time_budget_ms": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "undetermined": {
        +                "description": "Components whose advisories could not all be decided and none matched: not clean.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "description": "The producing radar's last completed check (last_run_at), where the API serves one.",
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "anyOf": [
        +          {
        +            "description": "An RFC 3339 instant.",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
        +      },
        +      "method": {
        +        "description": "How the numbers were produced.",
        +        "type": "string"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
        +        "enum": [
        +          "measured",
        +          "not_assessed"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "data"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "coverage": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "batch_size": {
        +                "description": "The most purls one request carries (the API's cap per request).",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "batches": {
        +                "description": "Requests the distinct purls make, at batch_size each.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "batches_sent": {
        +                "description": "Of those, the ones the API answered.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "components_in_document": {
        +                "anyOf": [
        +                  {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
        +              },
        +              "distinct_purls": {
        +                "description": "Distinct purls to check: sent plus not_sent.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "duplicates_removed": {
        +                "description": "Purls that appeared more than once and were sent once.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "input": {
        +                "description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document.",
        +                "enum": [
        +                  "purls",
        +                  "cyclonedx",
        +                  "spdx"
        +                ],
        +                "type": "string"
        +              },
        +              "not_assessed": {
        +                "anyOf": [
        +                  {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Of those sent, the components with no verdict, as the answer counts them."
        +              },
        +              "not_sent": {
        +                "description": "Distinct purls not sent, listed in data.not_sent_purls: not checked, and not clean.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "not_sent_reason": {
        +                "anyOf": [
        +                  {
        +                    "enum": [
        +                      "time_budget",
        +                      "rate_limited",
        +                      "request_failed"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Why not_sent is above 0: time_budget (the call's 50 s budget ran out, or waiting out the API's Retry-After would pass it), rate_limited (a 429 without Retry-After, or a 429 after 10 waits), request_failed (a batch after the first failed; the note quotes how). null when every purl was sent."
        +              },
        +              "partial": {
        +                "description": "true when not every purl was sent (not_sent above 0) or any batch's summary.partial was true (its time budget ran out first); otherwise the answer's summary.partial.",
        +                "type": [
        +                  "boolean",
        +                  "null"
        +                ]
        +              },
        +              "rate_limit_waits": {
        +                "description": "How many times the API answered 429 and the tool waited its Retry-After before sending the batch again.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "sent": {
        +                "description": "Distinct purls sent and answered.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "waited_ms": {
        +                "description": "Milliseconds spent in those waits.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "with_purl": {
        +                "description": "Of those, the ones carrying a purl.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "without_purl": {
        +                "description": "The ones without a purl: not checked, and not clean.",
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              }
        +            },
        +            "required": [
        +              "input",
        +              "components_in_document",
        +              "with_purl",
        +              "without_purl",
        +              "duplicates_removed",
        +              "distinct_purls",
        +              "batch_size",
        +              "batches",
        +              "batches_sent",
        +              "sent",
        +              "not_sent",
        +              "not_sent_reason",
        +              "rate_limit_waits",
        +              "waited_ms",
        +              "not_assessed",
        +              "partial"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "error": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "kind": {
        +            "description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
        +            "enum": [
        +              "network",
        +              "timeout",
        +              "http",
        +              "not_json",
        +              "not_object",
        +              "invalid_input",
        +              "internal",
        +              "unexpected_shape",
        +              "radars"
        +            ],
        +            "type": "string"
        +          },
        +          "message": {
        +            "description": "The cause: the API's own message, or what went wrong.",
        +            "type": "string"
        +          },
        +          "path": {
        +            "description": "The API path requested, when a request was made.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "status": {
        +            "anyOf": [
        +              {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "The HTTP status, when the API answered one."
        +          }
        +        },
        +        "required": [
        +          "kind",
        +          "path",
        +          "status",
        +          "message"
        +        ],
        +        "type": "object"
        +      },
        +      "freshness": {
        +        "type": "null"
        +      },
        +      "measured_at": {
        +        "type": "null"
        +      },
        +      "method": {
        +        "type": "null"
        +      },
        +      "notes": {
        +        "description": "Caveats, one sentence each.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "state": {
        +        "description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
        +        "enum": [
        +          "failed",
        +          "invalid_input"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "state",
        +      "measured_at",
        +      "method",
        +      "coverage",
        +      "freshness",
        +      "notes",
        +      "error"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedkev_recent2 fields changed
      • changedInput schema / properties / since / description
        Previous value: -"earliest kev_added_date to include, YYYY-MM-DD"New value: +"earliest kev_added_date to include, YYYY-MM-DD (an RFC 3339 timestamp is read as its UTC date)"
      • changedInput schema / properties / until / description
        Previous value: -"latest kev_added_date to include, YYYY-MM-DD"New value: +"latest kev_added_date to include, YYYY-MM-DD (an RFC 3339 timestamp is read as its UTC date)"
  5. 14 tool updates
    • First observedcheck_affected
    • First observedcheck_sbom
    • First observedcve_exposure
    • First observedcve_intel
    • First observedcve_summary
    • First observedepss_history
    • First observedexposure_radar
    • First observedget_cve
    • First observedget_cwe
    • First observedget_vendor_advisory
    • First observedkev_recent
    • First observedsearch_cves
    • First observedsearch_vendor_advisories
    • First observedvendor_advisories_for_cve

Related MCP Connectors

Related MCP Servers

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.