Engineering notes · 2026-09-14
The one number in our newsletter that wasn't grounded in filed data
Every figure in an Edge Thirteen value pick — price, P/E, book value, Graham fair value, margin of safety, ROE, earnings stability — is computed by a Python script straight from SEC EDGAR before the write-up model ever sees it. Except one. Here's the dividend yield we got wrong, the actual numbers, and why we caught it ourselves instead of a reader.
The gap
The write-up prompt tells the model to include dividend yield as a key number for every pick, the same way it includes P/E and Graham fair value. But the structured NUMBERSblock fed to the model never actually carried a dividend figure — every other metric was a real computed value; dividend yield was just a label with nothing behind it. The model did what any capable model does when asked for a number it doesn't have: it estimated one from what it remembered about the company, formatted identically to every grounded figure next to it.
The real error, in the already-sent issue
Cross-checking the 2026-09-10 issue against EDGAR's own CommonStockDividendsPerShareDeclared field: Arch Capital (ACGL) was labeled "Div n/a," as if it paid no dividend at all. It has a real, filed $5/share declared dividend against that week's price — a yield of roughly 5.1%, not nothing. Southern First Bancshares (SFBS) was stated at "~1.9%"; the actual filed $0.38/share works out to roughly 0.9% — off by more than 2x, in the direction that makes the stock look like a better income play than it is. Every other number on both of those picks — P/E, P/B, Graham fair value, margin of safety, ROE — was independently recomputed against the same filings and matched exactly. The failure was isolated to the one field with no source data behind it.
That's the same shape of bug as the table-of-contents parsing bug: the output wasn't obviously broken. A dividend yield formatted like every other number, sitting next to eight other numbers that were all correct, doesn't look like an error — it looks like data. Nothing about reading the issue would tell you which one field, out of nine, had nothing real behind it.
The fix
Not a prompt tweak — a data-pipeline fix. The dividend field now gets computed the same mechanical way as every other metric and placed in the block the model reads, so there is no gap left for the model to fill from its own memory:
def div_yield_pct(dps, px):
"""Trailing declared-dividend yield, as a percent. None if no dividend or no price."""
if not dps or not px or dps <= 0 or px <= 0:
return None
return round(dps / px * 100, 1)
def fundamentals(tk):
...
dps, _ = pick(facts, ["CommonStockDividendsPerShareDeclared"], unit="USD/shares")
px = price(tk)
dy = div_yield_pct(dps, px)
if dy is not None:
m["div_yield_pct"] = dy # now always in the data block the write-up model readsIf a company genuinely has no declared dividend on file, the block now says so explicitly ("none declared / not tagged in filings") instead of leaving the field blank — a model asked to fill in a blank will fill it in. An explicit "there is nothing here" is not a gap. We also went back and corrected the already-sent 2026-09-10 issue in the public archive record rather than leave the wrong numbers standing once the embargo lifts.
Then we built a tool so this isn't just a one-time fix
The underlying risk isn't specific to dividend yield — it's any numeric claim sitting next to a ticker that isn't checked against what the company actually filed. We built NumberCheck to catch exactly this: paste any piece of financial writing with $TICKERcashtags, and it finds numeric claims — EPS, book value per share, revenue, market cap, total assets, total liabilities — and compares each one to that company's actual most-recent-10-K XBRL figures from SEC EDGAR. Deterministic lookups against filed data, not another model guessing whether a number sounds right. It's free, and it's the same check we now run against our own issues before they go out.
The general lesson
If a pipeline hands a model eight grounded numbers and one label with nothing behind it, the ninth number will come back formatted exactly like the other eight — and every review step built around "does this look right" will pass it. The only defense is checking that every field claiming to be data actually has a source behind it, not reading the output and judging whether it's plausible. Same lesson as the FFIEC field-mapping bug and the table-of-contents parsing bug before it — the fix is never "read the output more carefully," it's "remove the step where a plausible-looking number can exist without a citation."
Share:X / TwitterLinkedIn
See the pipeline this feeds
Every week, Edge Thirteen screens roughly 5,000 U.S. stocks, reads the 10-K on every name that clears the numbers, and sends the genuine value picks — for $13/month. Cancel anytime.
Secure checkout via Stripe · cancel anytime · terms & refund policy.
Not ready for $13/month?
Get one real issue free, no card required — the same research, sent straight to your inbox.