How the numbers are checked
Four gates between a vendor row and your inbox.
Each gate is plain Python with fixed constants. No model decides whether a figure passes.
Problem
A number can trace to a real field and still be impossible.
The FMP price field sometimes holds the trade total instead of a unit price. Shares times price then gives a figure that traces to the filing and is false.
Both rows are fixtures in the test suite.
Solution
Check provenance and plausibility separately.
"Provenance only" is a pipeline that only asks where a number came from. "Whale Agent" is this pipeline. Select a gate to see its constants and source.
stopped at gate 1 price 40,000,000 is "above the 1,000,000 per-share ceiling; the field most likely holds a transaction total rather than a unit price". The price becomes unknown (None). The share count is kept.
Hover, focus or tap a gate.
Gate 1 / parse-time coercion
ingestion/vendor_types.py: coerce_price_per_share, coerce_share_count, coerce_usd_amount
- price per share
- $0.01 to $1,000,000, else field refused
- share count
- > 0 and ≤ 1e13
- stated USD amount
- ≤ $250,000,000,000
- integer sentinels
- 2^63 - 1, -2^63, -1
On failure: field set to None, reason written to the row.
Gate 2 / plausibility
enrichment/plausibility.py: check_event, screen
- value vs market cap
- ≤ cap x 1.5
- shares vs outstanding
- ≤ outstanding x 1.5
- stated vs shares x price
- ratio ≤ 10
- absolute ceiling
- $250,000,000,000
- ceiling with no market cap
- $25,000,000,000
- sentinel
- |x| ≥ 2^62, or -1
- placeholder issuer
- "", NONE, NULL, N/A, UNKNOWN, -, --
On failure: row quarantined with reasons. Storage reads (Store.events_since) run screen() and leave it out.
Gate 3 / figure check
summarization/provenance.py: allowed_numeric_tokens, find_unsourced_numbers, assert_no_hallucinated_numbers
- allowed set
- tokens built from stored event fields and their aggregates
- scope
- every material number in the text, URLs removed first
On failure: a summary sentence with an unsourced number is dropped. If the full render still fails, the prose is dropped and the digest is rendered from the template. A template render that fails raises an error.
Gate 4 / egress screen
delivery/email.py: find_egress_violations
- rendered figures
- subject, text and HTML: each $ figure ≤ $250,000,000,000
- source rows
- check_event runs again on every event behind the email
On failure: the email is not sent, the send reports failure, and the reason is written to quarantine.
Defence in depth
Gates, code and tests
| Gate | Checks | Code | On failure | Tests |
|---|---|---|---|---|
| 1 Coercion | Price band, share count ceiling, USD ceiling, sentinels | ingestion.vendor_types | Field becomes None | test_quadrillion.py: 12 |
| 2 Plausibility | Market cap, shares outstanding, value ratio, ceilings, sentinels, placeholders | enrichment.plausibility | Row quarantined, left out of reads | test_output_safety.py: 51 test_valuation.py: 10 |
| 3 Figure check | Every number in the text is in the allowed token set | summarization.provenance | Sentence dropped, then template render, then error | test_pipeline.py: 5 |
| 4 Egress | Rendered $ figures and source rows | delivery.email | Send blocked, quarantine record | test_email_themes.py: 15 |
Counts are grep -c "def test_" per file in the public repository, checked 28 Sep 2026. Several files test more than one gate, so the counts overlap and do not add up to a gate total. test_quadrillion.py pins the MetLife row at the adapter, valuation, storage read and send.
The only model in the pipeline is the optional summary writer. Gate 3 filters its sentences. These gates stop figures that are impossible. A figure that is wrong but possible still gets through.