GMI · TECHNOLOGY OBSERVATORY // ALL SYSTEMS NOMINAL
ENGINEERED BY LEOPARD DATA

Report Generator Beta

The macro engine — one shared dataset, built on a schedule, read by everyone. The opposite shape to Alpha, and deliberately so.

ENGINE PIPELINE
rendering diagram…
flowchart TB
    subgraph TRIG[Triggers]
      T1[Daily baseline]
      T2[Release-aware<br/>minutes after a print]
      T3[Admin-queued run]
    end
    F[Fetch ~38 economic series]
    C[Classify regime<br/>growth x inflation]
    G[Score the macro grade<br/>against published bands]
    subgraph DER[Derived in the same pass]
      D1[ML forecasts]
      D2[Sector playbook]
      D3[Grade-by-regime study]
      D4[Commodities]
      D5[Release calendar]
      D6[Scorecard]
    end
    TMP[(Write temp blob)]
    LIVE[(Atomic copy<br/>onto the live path)]
    R[Three apps + every shared link]
    TRIG --> F --> C --> G --> DER --> TMP --> LIVE --> R
    F -. run fails: write NOTHING,<br/>readers keep the previous<br/>snapshot and its age .-> R
One run: fetch every series, classify the regime, score the grade, derive the dependent products, then swap the snapshot atomically so no reader ever sees a half-built document.

Two Engines, Opposite Shapes

Alpha and Beta are both .NET console applications on the same virtual machine, and they are built on opposite assumptions. Alpha is per-user, on demand, fan-out: a job arrives, it fetches everything for the symbols in that job, and produces an artifact for one account. Beta is one dataset, on a schedule, fan-in: it runs whether or not anyone is watching, and every reader gets the same snapshot.

AlphaBeta
TriggerA user requests a reportA schedule, a data release, or an admin queueing a run
ScopeThe symbols in one jobThe whole economy — one snapshot for everyone
OutputAn Excel workbook per symbol, owned by an accountA single JSON snapshot read by three apps and every shared link
Cost shapeScales with usersFlat — one run serves one reader or ten thousand
FailureThat report fails; the user is toldNothing is written; readers keep the previous snapshot and are told its age

That last row is the design decision that matters most, and it is covered below.

What One Run Produces

A single run walks roughly 38 economic series and turns them into every derived product the macro features need. These are not independent jobs — each is computed from the same inputs in the same pass, which is what keeps them consistent with one another.

ComponentProduces
RegimeClassifierWhich of four macro seasons the economy is in, from blended growth and inflation impulses — plus the margin to the line, so "how firm is this call" is answerable
MacroGradeScorerThe economy graded out of 100 against published bands — the same grading contract used for companies, applied to the whole economy
MacroForecastServiceML.NET SSA projections one, two and six months out for each indicator
RegimePlaybookServiceHow sectors have historically behaved in conditions like these — descriptive, never a recommendation
GradeRegimeStudyServiceWhether company quality holds up when the tide goes out, across ~484 index constituents
CommoditiesServiceThe commodity complex read for risk-on and risk-off signals
ReleaseCalendarServiceA 90-day projected calendar of upcoming government data releases
ScorecardServiceThe platform's own record: every past projection scored against what actually printed
ClaudeNarrativeServicePlain-English outlook text — the only model-written part; everything else is arithmetic
MacroAlertServiceNotifications when the regime or grade actually changes, not on every run

Release-Aware Scheduling, Not a Fixed Cron

Economic data does not arrive on a tidy daily rhythm. Payrolls land on a Friday morning, CPI mid-month, PCE at month end — and between releases, re-running the engine computes the identical answer from identical inputs.

So the daemon runs on three triggers rather than one: a daily baseline so the snapshot is never stale by more than a day; release-aware runs shortly after a scheduled government release, so the dashboard reflects a new print within minutes rather than by luck of the clock; and an admin-queued run for when someone needs a rebuild now. A fixed hourly cron would have done more work and still been late to the only moments that matter.

Stale but Honest Beats Empty, and Both Beat Wrong

Every reader of this platform's macro features — three applications, plus every shared link ever sent — reads one blob. That concentration is what makes the engine cheap, and it is also what makes a bad write catastrophic: a half-written document would break the dashboard for everyone at once.

So the engine never writes the live snapshot. It writes a temporary blob, and only when that write has completed does it issue a server-side copy onto the live path. From a reader's perspective the swap is atomic: the previous snapshot is served in full until the instant the new one is, and no byte of a partial document is ever visible.

And when a run fails, nothing is written at all. The dashboard keeps serving the previous snapshot and states how old it is. A reader looking at yesterday's numbers, clearly labelled yesterday's, is better served than one looking at an error page — and far better served than one looking at half of today's.

Four Modes, One Binary

ModePurpose
runA single engine run. The unit of work everything else schedules.
daemonThe scheduler loop that runs in production — daily, release-aware, and admin-queue polling.
backtestRebuilds the historical regime and grade timeline, which is what makes the scorecard possible: past claims can only be scored if they were recorded.
backfillSeeds regime history from the frozen backtest timeline. Deliberately gated until the grading bands were frozen, so history could not be rewritten by a later change of method.

One binary with modes rather than four executables: the classification, scoring and derivation logic must be identical whether it is producing today's snapshot or replaying 2008, or the backtest would be scoring a different engine than the one that runs.

Related Reading