A due-diligence pipeline returned a complete report last week. Nine sections. Technical audit, token economics, market positioning, ecosystem role, regulatory exposure, team and governance, a six-row risk matrix, narrative scoring, supply-chain transmission. Every field was populated. Every field was empty.
The JSON parsed. The schema validated. Type coercion ran clean. required arrays were satisfied. No exception was thrown, no alert fired, no human was paged. Somewhere downstream, a writer model sat one prompt away from converting that void into three thousand words of confident analysis about a protocol that had never been named.
I have seen this exact failure before. Not in a language model. In the EVM.

The stack in question was a three-stage research pipeline โ extractor, analyst, writer. Standard architecture, shipped by a dozen teams since 2024 and resold to funds that cannot afford a full-time analyst in a market where nobody is paying fees. Stage one ingests an article, a filing, a governance forum thread, and decomposes it into an information-point list. Stage two reasons over those points. Stage three renders prose. The contract between stage one and stage two is a JSON schema, and the schema is where the whole thing quietly dies.
Nobody instruments stage one. Extraction is the least glamorous component in the stack โ no benchmark, no leaderboard, no demo slide. The analyst model gets the paper. The writer model gets the applause. The extractor gets a cron job and a 2 a.m. alert that nobody routed to a phone.
So stage one failed. Not loudly โ it emitted the full template, every key present, every value the string "N/A". Stage two was instructed to anchor each conclusion to an information-point index. There were zero information points. To its credit, stage two refused. It produced a placeholder document explaining that it could not analyze an empty input.

That refusal is the interesting artifact. Formatted as a nine-section deliverable, padded with N/A cells and risk-matrix rows reading not assessable, it is byte-for-byte indistinguishable from a real report at the parsing layer. A risk matrix that renders as a matrix is a matrix that gets screenshotted. Any downstream consumer checking len(report.sections) == 9 gets a green light. A refusal shaped like a deliverable is more dangerous than no deliverable at all.
Here is the EVM version, which I have audited more times than I would like:

(bool success, bytes memory data) = target.call(payload);
require(success, "call failed");
Result memory r = abi.decode(data, (Result));
If target is an EOA โ or a contract that self-destructed, or a proxy pointing at an empty implementation โ success returns true. returndatasize() is zero. abi.decode on empty bytes reverts, which is the only thing saving most codebases; swap it for inline assembly and you decode zero values into a struct that then prices a loan.
The bug is not that the call failed. The bug is that success is a boolean about whether the call executed, not about whether anything answered. Every schema in the crypto research stack makes the identical substitution. valid: true means the payload parsed, not that the payload meant anything.
In late 2017 I spent forty hours on a token-distribution template hunting an overflow and found a stack underflow instead โ a state transition reachable by a balance the contract never expected to hold. The lesson from that week was narrow and it has held for nine years: the dangerous path is never the one that reverts. It is the one that returns a plausible default. Uninitialized storage, unset oracle rounds, zero-address fallbacks, empty arrays summing to zero. All of them return a number. None of them return the truth.
DeFi Summer taught me the corollary. Auditing a small DEX's liquidity mining contracts in 2020, the reentrancy I found in the reward distributor was not hiding in the swap logic โ it was sitting in a state-changing function everyone had classified as bookkeeping. Financial logic hides in the functions you stopped reading. Information logic hides in the fields you stopped checking.
What does a null-safe pipeline actually require? Four invariants, and none of them are expensive.
First, cardinality as a hard gate. if (len(info_points) == 0) abort(). Not a warning, not a soft-fail โ an abort with a distinct exit code the orchestrator treats as a different class of event than "analysis complete." This is require(returndatasize() > 0) for prose.
Second, a provenance manifest. Every conclusion carries an array of info-point IDs it derives from. A sentence with an empty array is not analysis โ it is generation. In my SNARK work last year I spent three weeks shaving 30% off proving time by restructuring constraints, and the discipline transfers exactly. A constraint system that admits a witness with no inputs is an unsound circuit. A report format that admits a conclusion with no provenance is an unsound schema.
Third, refusal as a typed output rather than a prose style. status: "insufficient_input" is a different object from status: "complete" โ different renderer, different consumer, different downstream permissions. The moment a refusal shares a type with a result, some service will treat it as one.
Fourth, an entropy proxy. Count distinct proper nouns in the output. An analysis of a real protocol names things. A null-payload hallucination names nothing, or names only what it saw in the prompt. Cheap, crude, and it catches the exact failure class that matters.
The cost is real but small. Provenance manifests add roughly 15โ25% to output tokens โ about 600 on a 4,000-token report. A verifier pass with a smaller model costs roughly $0.004 per document at current pricing. If a diligence budget cannot absorb four-tenths of a cent, it was never a diligence budget.
Now the contrarian read, because the obvious conclusion is wrong.
The empty report is the safe failure. It is loud, structurally broken, easy to catch โ assuming anyone is catching. The dangerous artifact is the one that fills 80% of the fields correctly and confabulates the remaining 20%: circulating supply off by a decimal, an unlock cliff attributed to the wrong quarter, an audit "completed" by a firm that was never engaged. That report passes every check the empty one fails, and it passes them because most of it is true.
Market pressure selects for the second kind. A pipeline that refuses 30% of the time looks broken to its users. A pipeline that never refuses looks brilliant, raises a seed round, and gets wired into a Telegram bot that 40,000 people use to size positions. Gas wars are just ego masquerading as utility; research-report races are the same auction with a different unit of account, and in a bear market demand for confident-sounding diligence goes up, not down.
Underneath all of it is an oracle problem wearing a machine-learning costume. A price feed returning a stale number through a volatility spike and a research agent returning a confident number through an information drought are the same defect: liveness without honesty. The 2022 depeg post-mortems I wrote were, in retrospect, latency studies โ block numbers and feed-update gaps charted until the death spiral looked mechanical instead of mysterious. The AI research stack has not had its Terra moment. It will.
Code does not lie, but it often forgets to breathe. This template breathed โ every key present, every structure intact, every field exhaling N/A โ and nothing inside it was alive.
The forecast I would put capital behind: the next nine-figure loss in this industry will not be a reentrancy bug. It will be an agent that sized a position on a null payload it was told was a signal, and a risk dashboard that returned true because the JSON parsed. A schema is not a spec, and a spec is not a truth. Until the research layer ships with the same invariants we demand of a staticcall, every automated fundamental score in this market is a zero-address lookup waiting to be decoded.