Before an earnings call, the system predicts the questions analysts will ask and who will ask them — an evidence pack, a ranked slate, then a grade against the real transcript. Across 18 held-out calls, the slates covered roughly 75% of what analysts actually asked, under a partial-credit rubric, not exact-match accuracy.
Investor-relations and CFO prep for a public insurer is still tribal. A week before the call, a small group sits with last quarter’s deck, one sell-side preview, and whatever someone remembers from the last five Q&As. The guesses become a briefing book, management rehearses the book — and then the first analyst on the line asks about the one thing that never made the list. That miss is public: on the transcript, in the follow-up notes, and often in the afternoon tape.
The archive is sitting there. Every past call, every peer call in the same quarter, every 10-Q and 8-K, every sell-side note is the actual distribution of questions. Themes recur; individual analysts have signatures — one always opens on capital, another never lets a new product go without a persistency follow-up. Nobody had turned that archive into a ranked slate, an asker prediction, and a scoreboard after the call.
A prep desk, not a chat demo. The evidence store is versioned per ticker and quarter — management presentations, prior-quarter Q&A, peer-insurer transcripts, 10-Q and 8-K text, sell-side notes — and the pack builder assembles what a human IR team would have the morning of the call. It refuses the target call’s own Q&A: that leakage firewall is unit-tested, and packs are immutable once locked.
On the locked pack, a coverage panel of independent agents proposes questions across the theme map so one agent’s blind spot cannot drop a topic, and a persona desk models the named analysts who actually cover the stock from their historical ask patterns. A deterministic merge produces the ranked slate with a likely asker on every row. After the call, the slate is graded against the real transcript, and misses feed the next quarter’s pack.
The run is a LangGraph graph over the locked pack, with model calls routed through LiteLLM so nothing is welded to one provider. The slate streams into a React app over SSE as NDJSON events — rank, question, likely asker, evidence chips, confidence — and if an agent fails, the app shows the failure; there is no canned fallback that invents a clean result. Postgres holds the versioned evidence store, and pytest holds the leakage firewall: if a pack includes a sentence from the held-out transcript, the build fails.
Grading is an LLM-as-judge with a partial-credit rubric — same topic and same operational ask scores, wording aside — plus a human spot-check so the judge cannot drift. A single-shot prompt baseline runs on the same packs, and the graph has to beat it, or the extra agents are theater. Traces land in LangSmith; Promptfoo holds the pack-builder prompts and the judge rubric as CI regressions.
Python, FastAPI, LangGraph, LiteLLM, LangSmith, Promptfoo, React, SSE / NDJSON streaming, Postgres, pytest.
Eighteen held-out calls, life and annuity names, is the current book. Roughly 75% of what analysts actually asked was covered by the locked slates, under the partial-credit rubric — I say it that way on purpose. The night before a call, IR reads who is likely to open, which follow-up comes if management hedges, and which theme is still uncovered; after the call, it is a grade, not a feeling.
It is being offered to the CFOs of two major insurers. Not sold, not signed — offered. That is the honest status.