An independent program checks our published API against the networks and venues themselves, every few hours. Findings are published whole, including our own errors.Note 11
A check that could not run is counted separately and never as a pass. An API nobody could reach must not look like an API that answered correctly.
Failing means both sides measure the same thing and they disagree, and that is the only kind that stops a deploy. Everything under to read is real information and not a defect: a coverage gap we publish deliberately, a plausibility bound against a source whose universe differs from ours, or a comparison whose two sides are not the same quantity, where no tolerance between them would mean anything.
failing
ran 15.0 minutes against a 15-minute ceiling. The scheduler stopped waiting and the job carried on, so its own record and the scheduler's disagree about the same run.
GET /v1/freshness · mcp-verify · expected 15, got 15
failing
/v1/collateral/{symbol} answered 404 for all 9 identifiers tried, every one taken from /v1/vaults moments earlier. That is either a route that cannot look anything up — both operator routes were exactly this, dead for every operator alive — or a measurement 9 subjects happen not to have. This check cannot tell which from a sample, and does not claim to: what it can say is that a caller iterating /v1/vaults would have met 9 404s in a row, and 404 is declared here for identifiers a caller invents rather than for ours.
GET /v1/openapi.json · /v1/collateral/BTC · expected 200, got 404
failing
measured share is not the measurable weight over the reachable weight
GET /v1/vaults/:slug (risk) · monad-hyperithm-usdc-apex-78999c · expected 0.787878787878788, got 1
failing
score is not the weighted average of its components
GET /v1/vaults/:slug (risk) · monad-hyperithm-usdc-apex-78999c · expected 17, got 18
failing
measured share is not the measurable weight over the reachable weight
GET /v1/vaults/:slug (risk) · ethereum-wintermute-usdc-select-a2eaad · expected 0.787878787878788, got 1
failing
score is not the weighted average of its components
GET /v1/vaults/:slug (risk) · ethereum-wintermute-usdc-select-a2eaad · expected 25, got 20
failing
measured share is not the measurable weight over the reachable weight
GET /v1/vaults/:slug (risk) · ethereum-pendle-ecosystem-high-yield-usdc-cf609f · expected 0.690909090909091, got 0.9030303030303031
failing
score is not the weighted average of its components
GET /v1/vaults/:slug (risk) · ethereum-pendle-ecosystem-high-yield-usdc-cf609f · expected 27, got 21
failing
measured share is not the measurable weight over the reachable weight
GET /v1/vaults/:slug (risk) · ethereum-steakhouse-prime-eth-beef00 · expected 0.787878787878788, got 1
failing
score is not the weighted average of its components
GET /v1/vaults/:slug (risk) · ethereum-steakhouse-prime-eth-beef00 · expected 28, got 22
failing
measured share is not the measurable weight over the reachable weight
GET /v1/vaults/:slug (risk) · ethereum-steakhouse-eth-BEEf05 · expected 0.787878787878788, got 1
failing
score is not the weighted average of its components
GET /v1/vaults/:slug (risk) · ethereum-steakhouse-eth-BEEf05 · expected 34, got 26
failing
measured share is not the measurable weight over the reachable weight
GET /v1/vaults/:slug (risk) · ethereum-3jane-ecosystem-vault-e05fad · expected 0.787878787878788, got 1
failing
score is not the weighted average of its components
GET /v1/vaults/:slug (risk) · ethereum-3jane-ecosystem-vault-e05fad · expected 17, got 13
failing
measured share is not the measurable weight over the reachable weight
GET /v1/vaults/:slug (risk) · ethereum-vault-bridge-weth-31A568 · expected 0.787878787878788, got 1
failing
score is not the weighted average of its components
GET /v1/vaults/:slug (risk) · ethereum-vault-bridge-weth-31A568 · expected 30, got 24
failing
measured share is not the measurable weight over the reachable weight
GET /v1/vaults/:slug (risk) · arbitrum-steakhouse-usdg-pro-beeff7 · expected 0.690909090909091, got 0.9030303030303031
failing
score is not the weighted average of its components
GET /v1/vaults/:slug (risk) · arbitrum-steakhouse-usdg-pro-beeff7 · expected 37, got 28
failing
one half of the lending split is present and the other absent
GET /v1/vaults/:slug (lending) · concrete-ctdeltaweeth-2393da
failing
one half of the lending split is present and the other absent
GET /v1/vaults/:slug (lending) · concrete-ctbtccxprime-ccc79b
failing
one half of the lending split is present and the other absent
GET /v1/vaults/:slug (lending) · concrete-ctwlficx-prime-51bd33
failing
one half of the lending split is present and the other absent
GET /v1/vaults/:slug (lending) · concrete-ctepoch-993039
failing
one half of the lending split is present and the other absent
GET /v1/vaults/:slug (lending) · concrete-ctrwa-usd1-c47fc8
failing
one half of the lending split is present and the other absent
GET /v1/vaults/:slug (lending) · avant-aveth-saveth-b2c050
failing
one half of the lending split is present and the other absent
GET /v1/vaults/:slug (lending) · ember-protocol-usdc-4ae1f4
failing
1 of 30 Ember Protocol vaults publish capital last re-read over 36h ago — $4,486,707 in total, the oldest 110h (ember-protocol-usdc-9e9ed2)
GET /v1/vaults · Ember Protocol · expected 0, got 1
failing
3 of 4 ForgeYields vaults publish capital last re-read over 36h ago — $1,255,058 in total, the oldest 484h (forgeyields-eth-4973f9)
GET /v1/vaults · ForgeYields · expected 0, got 3
failing
57 of 2197 Krystal Auto-Farm Vault vaults publish capital last re-read over 36h ago — $115,062 in total, the oldest 165h (krystal-cryptonomy-weth-cbbtc-47bc53)
GET /v1/vaults · Krystal Auto-Farm Vault · expected 0, got 57
failing
1 of 1 Snowbl Capital vaults publish capital last re-read over 36h ago — $55,448 in total, the oldest 521h (snowbl-capital-weth-13530d)
GET /v1/vaults · Snowbl Capital · expected 0, got 1
failing
1 of 11 Neutral Trade vaults publish capital last re-read over 36h ago — $51,374 in total, the oldest 123h (neutral-trade-usdc-7197de)
GET /v1/vaults · Neutral Trade · expected 0, got 1
failing
27 of 518 Hyperliquid vaults publish capital last re-read over 36h ago — $3,947 in total, the oldest 1023h (trader-d-0c4933)
GET /v1/vaults · Hyperliquid · expected 0, got 27
failing
the FREE public endpoint for this chain refused logs 1,000,000 blocks back and at every shallower depth tried. This is the free-tier floor, NOT a statement about our own readers, which use keys this check does not hold: anybody reading this chain without a key gets that much history and no more.
GET /v1/vaults · base · expected 1000000, got null
failing
the CSV has no "risk score" column while the JSON carries it
GET /v1/vaults?format=csv · header
failing
the CSV has no "withdrawable" column while the JSON carries it
GET /v1/vaults?format=csv · header
failing
the CSV has no "lent out" column while the JSON carries it
GET /v1/vaults?format=csv · header
failing
the CSV has no "observations" column while the JSON carries it
GET /v1/vaults?format=csv · header
failing
the CSV has no "return basis" column while the JSON carries it
GET /v1/vaults?format=csv · header
failing
the CSV has no "capital read at" column while the JSON carries it
GET /v1/vaults?format=csv · header
failing
the CSV has no "provenance" column while the JSON carries it
GET /v1/vaults?format=csv · header
failing
the CSV has no "closed" column while the JSON carries it
GET /v1/vaults?format=csv · header
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · identify
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · preflight_payment
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · vault_risk_dimensions
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · portfolio_screen
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · capital_coverage
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · evaluate_action
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · test_purchase
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · knock_on_endpoint
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · endpoint_disagreements
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · list_x402_endpoints
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · counterparty_check
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · agent_changes
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · agent_dependencies
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · agent_business
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · agent_economic_profile
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · exit_screen
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · vault_exit_confidence
failing
this tool is called by nothing and is not in NEVER_CALL, so nothing would notice if it stopped answering. Give derive() an argument for it, or name it in NEVER_CALL with a reason.
/mcp · check_action
failing
promises meta, warnings and did not return them. An agent is being told to read fields that are not there.
/mcp · check_service_endpoint · expected endpoint,declaredBy,latest,history,drift,unpaidProbe,price,measured,handshake,manifest,changes,outcomes,says,meta,warnings, got endpoint,host,declaredBy,latest,history,drift,price,measured,unpaidProbe,manifest,changes,handshake,says,outcomes,check,limits
failing
promises meta, warnings and did not return them. An agent is being told to read fields that are not there.
/mcp · vault_exits · expected settlementObserved,snapshotAlignment,slug,redemption,sharesLeft,venueWithdrawable,redemptionIntelligence,queueWaiting,exitPhases,exitCapacity,reconciliation,exitCap,capacityRefusal,declaredWithdrawableUsd,tvlUsd,windows,windowsEndAt,haveFlowHistory,flowsNewestAt,flowsNewestAnywhereAt,lastReadAt,readBy,readToBlock,capitalAsOf,declaredAsOf,largestEverUsd,largestEverAt,cannotSee,says,meta,warnings, got slug,declaredWithdrawableUsd,exitCap,reconciliation,snapshotAlignment,tvlUsd,windows,largestEverUsd,largestEverAt,firstWithdrawalAt,windowsEndAt,capitalAsOf,declaredAsOf,haveFlowHistory,flowsNewestAt,flowsNewestAnywhereAt,lastReadAt,readBy,readToBlock,says,cannotSee,exitCapacity,capacityRefusal,queueWaiting,boringVault,hyperliquidVault,kaminoStrategy,settlementObserved,emberSui,sharesLeft,exitPhases,redemptionIntelligence,redemption,venueWithdrawable,limits
failing
promises meta, warnings and did not return them. An agent is being told to read fields that are not there.
/mcp · evidence_for · expected subject,subjectKind,edges,lookedForAndMissing,counts,kinds,says,limits,meta,warnings, got subject,subjectKind,edges,lookedForAndMissing,counts,says,limits,kinds
failing
promises meta, warnings and did not return them. An agent is being told to read fields that are not there.
/mcp · list_policies · expected data,default,says,meta,warnings, got data,default,says
failing
promises meta, warnings and did not return them. An agent is being told to read fields that are not there.
/mcp · vault_check · expected redemption,slug,name,operator,capitalUsd,earned,risk,keys,changedHands,exitHistory,collateralCrowd,depositorEarned,cannotSee,says,meta,warnings, got slug,name,platform,chain,keys,changedHands,operator,alsoHere,agentManaged,closed,acceptsDeposits,capitalUsd,capitalAsOf,redemption,collateralCrowd,depositorEarned,exitHistory,earned,risk,cannotSee,says,full
failing
promises meta, warnings and did not return them. An agent is being told to read fields that are not there.
/mcp · operator_check · expected name,strategies,capitalUsd,ownShare,agentManaged,cannotSee,says,meta,warnings, got slug,name,kind,managementMode,website,strategies,capitalUsd,ownShare,agentManaged,cannotSee,says,full
failing
promises meta, warnings and did not return them. An agent is being told to read fields that are not there.
/mcp · find_agents · expected items,filters,asOf,meta,warnings, got asOf,filters,items
failing
promises meta, warnings and did not return them. An agent is being told to read fields that are not there.
/mcp · vaults_earned · expected alsoMeasured,byVenue,survivorship,comparable,shortOfAdvertised,shortOfAdvertisedShare,population,advertisedBand,losingShare,returned,withheld,items,limits,meta,warnings, got asOf,depositors,considered,refused,venuesSupplying,venuesNotSupplying,byVenue,alsoMeasured,survivorship,emptyBecause,comparable,shortOfAdvertised,shortOfAdvertisedShare,population,advertisedBand,losingShare,capitalWeightedReturn,withComparison,returned,withheld,capability,items,method,limits
failing
promises meta, warnings and did not return them. An agent is being told to read fields that are not there.
/mcp · inspect_payment · expected verdict,call,recipient,spender,againstEndpoint,actualTransfer,selector,amountAtomic,unlimitedAllowance,findings,limits,meta,warnings, got verdict,call,selector,recipient,againstEndpoint,spender,actualTransfer,amountAtomic,unlimitedAllowance,findings,limits
warning
18 of 30 Ember Protocol vaults carry no contract address — $40,089,241 that cannot be confirmed on a chain
GET /v1/vaults · Ember Protocol · expected 0, got 18
warning
11 of 11 Neutral Trade vaults carry no contract address — $13,853,014 that cannot be confirmed on a chain
GET /v1/vaults · Neutral Trade · expected 0, got 11
warning
4 of 36 Fusion by IPOR vaults carry no contract address — $13,796,688 that cannot be confirmed on a chain
GET /v1/vaults · Fusion by IPOR · expected 0, got 4
warning
4 of 8 D2 Finance vaults carry no contract address — $11,970,253 that cannot be confirmed on a chain
GET /v1/vaults · D2 Finance · expected 0, got 4
warning
1 of 2 Agua vaults carry no contract address — $9,080,592 that cannot be confirmed on a chain
GET /v1/vaults · Agua · expected 0, got 1
warning
4 of 17 Makina vaults carry no contract address — $6,056,874 that cannot be confirmed on a chain
GET /v1/vaults · Makina · expected 0, got 4
warning
2 of 8 Upshift vaults carry no contract address — $3,076,395 that cannot be confirmed on a chain
GET /v1/vaults · Upshift · expected 0, got 2
warning
1 of 4 ether.fi Liquid vaults carry no contract address — $2,745,499 that cannot be confirmed on a chain
GET /v1/vaults · ether.fi Liquid · expected 0, got 1
warning
1 of 1 dYdX vaults carry no contract address — $1,842,020 that cannot be confirmed on a chain
GET /v1/vaults · dYdX · expected 0, got 1
warning
4 of 4 ForgeYields vaults carry no contract address — $1,255,058 that cannot be confirmed on a chain
GET /v1/vaults · ForgeYields · expected 0, got 4
warning
2 of 2 Bracket Vaults vaults carry no contract address — $472,162 that cannot be confirmed on a chain
GET /v1/vaults · Bracket Vaults · expected 0, got 2
warning
1 of 1 Sherpa vaults carry no contract address — $468,774 that cannot be confirmed on a chain
GET /v1/vaults · Sherpa · expected 0, got 1
warning
1 of 59 Lagoon vaults carry no contract address — $448,731 that cannot be confirmed on a chain
GET /v1/vaults · Lagoon · expected 0, got 1
warning
2 of 34 Concrete vaults carry no contract address — $250,137 that cannot be confirmed on a chain
GET /v1/vaults · Concrete · expected 0, got 2
warning
4 of 4 MaxShot vaults carry no contract address — $240,867 that cannot be confirmed on a chain
GET /v1/vaults · MaxShot · expected 0, got 4
warning
1 of 1 Theoriq AlphaVault ETH vaults carry no contract address — $194,547 that cannot be confirmed on a chain
GET /v1/vaults · Theoriq AlphaVault ETH · expected 0, got 1
warning
1 of 1 Arkonix vaults carry no contract address — $111,834 that cannot be confirmed on a chain
GET /v1/vaults · Arkonix · expected 0, got 1
warning
1 of 1 Snowbl Capital vaults carry no contract address — $55,448 that cannot be confirmed on a chain
GET /v1/vaults · Snowbl Capital · expected 0, got 1
investigating
1 open vault(s) publish a capital figure with no reading time — $100,316 between them, largest $100,316. Our own Lista check refuses to compare such a figure against a venue; a customer is given it without comment. They sit under the minimum-capital filters of every reader that would refresh them. Found across the 2000 open vaults read of 3803.
GET /v1/vaults · kamino-edectcgf · expected 0, got 1
not comparable
our 5.49% a year against the venue's published 2.24%. Scaled linearly to our 29-day window that is 0.26% apart — but that scaling assumes their figure is simple rather than compounded, and that they measured the same window, and neither is established. NOT COMPARABLE until the venue confirms what its number is: APR or APY, gross or net of management, performance, entry and exit fees, over which exact blocks, and whether it describes the vault, the strategy, the NAV or the share price. Our own side is sound — read back off the chain at four historical blocks and matched to eight decimal places — and an async vault's share price is genuinely flat between settlements, with the fall at settlement being a fee a holder paid. That points at gross-against-net, which is a difference in metric rather than in data, and no tolerance between two different metrics means anything. Reported, not asserted.
GET /v1/vaults · lagoon-dammeth-a853c2 (DAMM Ethereum Fund) · expected 2.2414, got 5.4877
not comparable
our 20.43% a year against the venue's published 5.54%. Scaled linearly to our 29-day window that is 1.19% apart — but that scaling assumes their figure is simple rather than compounded, and that they measured the same window, and neither is established. NOT COMPARABLE until the venue confirms what its number is: APR or APY, gross or net of management, performance, entry and exit fees, over which exact blocks, and whether it describes the vault, the strategy, the NAV or the share price. Our own side is sound — read back off the chain at four historical blocks and matched to eight decimal places — and an async vault's share price is genuinely flat between settlements, with the fall at settlement being a fee a holder paid. That points at gross-against-net, which is a difference in metric rather than in data, and no tolerance between two different metrics means anything. Reported, not asserted.
GET /v1/vaults · lagoon-hubcap-usdc-dc5ccb (Hub Capital USDC vault) · expected 5.5443, got 20.4333
not comparable
our 8.85% a year against the venue's published 12.58%. Scaled linearly to our 30-day window that is 0.31% apart — but that scaling assumes their figure is simple rather than compounded, and that they measured the same window, and neither is established. NOT COMPARABLE until the venue confirms what its number is: APR or APY, gross or net of management, performance, entry and exit fees, over which exact blocks, and whether it describes the vault, the strategy, the NAV or the share price. Our own side is sound — read back off the chain at four historical blocks and matched to eight decimal places — and an async vault's share price is genuinely flat between settlements, with the fall at settlement being a fee a holder paid. That points at gross-against-net, which is a difference in metric rather than in data, and no tolerance between two different metrics means anything. Reported, not asserted.
GET /v1/vaults · lagoon-9sicusdc-33fe6e (9Summits Short Duration Institutional Credit — Powered by Rekord) · expected 12.5756, got 8.8463
| Check | Reaches | Examined | Result |
|---|---|---|---|
| a vault we could barely measure is not scored as dangerous | identity | 276 | clean |
| every field is the type the published schema says it is | shape | 25 | clean |
| every declared response shape still matches what the operation answers | shape | 70 | clean |
| identifiers are unique, quantities that cannot be negative are not, and nothing is observed after it is computed | identity | 101 | clean |
| a filter and its negation add up to the whole corpus |
| identity |
| 4 |
| clean |
| a vault reads the same on the list as it does on its own page | identity | 8 | clean |
| every scheduled job has code, runs, and finishes inside its ceiling | identity | 204 | 1 finding |
| figures that should change are still changing | identity | 203 | clean |
| no single chain falls far behind the rest on payment coverage | identity | 6 | clean |
| a figure does not borrow a coverage from a different field | identity | 1 | clean |
| an unreadable parameter is refused rather than dropped | identity | 4 | clean |
| every documented route answers | shape | 82 | 1 finding |
| no NaN, Infinity or unparseable timestamp in any payload | shape | 12 | clean |
| pagination arithmetic holds and pages do not overlap | shape | 3 | clean |
| nonsense parameters are refused, not crashed on or silently ignored | shape | 10 | clean |
| risk score is the weighted average of its own published components | identity | 100 | 16 findings |
| supplied equals lent out plus left, and none of the three is a zero standing in for unknown | identity | 40 | 7 findings |
| every flag carries an observation and its innocent reading, and never a verdict | identity | 100 | clean |
| counts and capital agree between the list, the detail and /v1/meta | identity | 4 | clean |
| an absent measurement is null, never a zero that reads as a value | identity | 100 | clean |
| every figure says when it was read, and nothing is stale without saying so | identity | 20 | clean |
| capital we publish is capital we have re-read | identity | 4011 | 6 findings |
| capital we publish can be checked against a chain | identity | 4011 | 18 findings |
| an identifier a consumer would look up on a chain is either an address or is labelled as not one | identity | 100 | clean |
| capital the API reports matches the vault contract read directly | source | 14 | clean |
| Morpho vaults match what Morpho publishes about them | source | 25 | clean |
| Lista vaults reconcile against what Lista publishes, itemised | source | 25 | clean |
| platform capital is the right order of magnitude against DefiLlama | source | 2 | clean |
| the block rate behind every historical window still matches the chain | source | 7 | clean |
| the alerting is still running, and nothing is stuck in the delivery queue | source | 2 | clean |
| the data consumer is still reporting, so its quiet is real quiet | source | 1 | clean |
| an endpoint asked about a block before a contract existed refuses, rather than answering | source | 4 | clean |
| log history reaches as far back as the readers assume it does | source | 4 | 1 finding |
| our realised return agrees with the venue that computes the same figure | source | 49 | 3 findings |
| the same quantity asked for two ways answers the same both times | identity | 241 | clean |
| a key that holds a capability actually receives the field it pays for | identity | 12 | clean |
| a capability the key lacks is refused with a 402 that names it | shape | 7 | clean |
| POST /v1/risk names the holdings its shock ladder cannot speak for | identity | 3 | clean |
| a redemption that cannot be paid says so rather than that nothing must be sold | identity | 8 | clean |
| the CSV export carries what the JSON carries | identity | 9 | 8 findings |
| a vault reported closed says so, and a dead one is not still counted as live | identity | 200 | clean |
| a value is in the unit its field name claims | shape | 13 | clean |
| a published capital figure says when it was read | identity | 2000 | 1 finding |
| the freshness block covers the readings actually in the payload | identity | 5 | clean |
| a residual correlation is only reported where the raw one could be measured | identity | 120 | clean |
| an availability status and the data beside it say the same thing | identity | 18 | clean |
| two adjacent pages share no row, and a traversal repeats itself | identity | 3 | clean |
| the plan a key names, the quota it reports, and the price list agree | identity | 1 | clean |
| the free surface answers an unkeyed caller | shape | 4 | clean |
| no paid field reaches a caller without a key | identity | 3 | clean |
| a key gets what it paid for | identity | 3 | clean |
| the API says which key it recognised | shape | 3 | clean |
| the website and the API agree about whether we are charging | source | 2 | clean |
| the website does not give away what the API charges for | source | 2 | clean |
| the API publishes what it withholds | shape | 18 | clean |
| a vault profile withholds the same rows for a stranger as the limits promise | source | — | could not run |
| the website withholds what the API says it withholds | source | 5 | clean |
| every tool is either exercised or deliberately excluded | shape | 33 | 18 findings |
| the tool surface answers and every tool describes itself | shape | 33 | clean |
| every tool returns the fields its own schema promises | identity | 11 | 9 findings |
| the hand-checked sample still says what it said | source | 127 | clean |