DocumentationUnder the hood

Regime dashboard contract

Updated: 2026-09-06

The daemon's Regime engine classifies the broad-market stress lifecycle as quiet, early_warning, confirmed_stress, panic, stabilization, opportunity, or data_quality. It is an evidence-balance read, not a prediction, trading system, portfolio planner, or investment recommendation.

Use it to answer one question: are several independent market-risk indicators confirming each other, or is the market still broadly calm?

The daemon's Stress engine may consume this output, but Stress owns account and portfolio action. A portfolio concentration problem can be real even while the broad market regime is calm. Since v3.4, canary regime [--explain] [--json] and canary stress [--details] [--json] restore the detailed reads, alongside MCP canary_regime and canary_stress. Brief keeps the summary; the app keeps its existing detailed projections. Regime JSON omits large gamma profile arrays unless --profiles (MCP include_profiles=true) is requested. Regime/Stress history and forced-refresh controls remain retired.

Output shape

Each row carries:

The compact app monitor also carries gamma_insights[], preserving each underlying's explanation and quality. The daily Brief exposes canonical SPX under ready.gamma (or a degraded, explicitly named SPY proxy). CLI and canary_brief MCP render this daemon-authored contract; app snapshot/bootstrap and SSE retain the same evidence. A retained app authority labels these as last-known observations rather than promoting their historical rankability.

The top-level envelope also carries:

Missing, stale, computing, and degraded data must stay visible. A quiet reading with missing critical inputs is not the same thing as a confirmed calm regime.

Indicator sources

Historical replays may substitute point-in-time equivalents for these live sources; the row meaning should stay the same.

Row Actual symbols or series Live source
VIX/VIX3M VIX and VIX3M, Cboe equity-volatility indexes IBKR index market data in session; outside Cboe's VIX3M publication window the served VIX3M is Cboe's official dated daily close, which also cross-checks the broker leg. Backtests use Cboe official historical CSVs.
VVIX VVIX, Cboe's VIX-of-VIX index Cboe official daily VVIX time series.
HYG/SPY HYG, a high-yield corporate bond ETF, and SPY, an S&P 500 ETF IBKR quotes plus HMDS daily bars; SPY 52-week high uses IBKR Misc Stats tick 165 when available, daily-bar fallback otherwise. Backtests use Nasdaq public ETF history.
HY OAS FRED BAMLH0A0HYM2 for high-yield OAS and BAMLC0A0CM for investment-grade corporate OAS FRED/St. Louis Fed CSVs for ICE BofA option-adjusted spread series.
CP 90-day AA financial minus 13-week T-bill Federal Reserve RIFSPPFAAD90_N.B and U.S. Treasury ROUND_B1_CLOSE_13WK_2; cached under legacy series keys RIFSPPFAAD90NB / DTB3 for wire compatibility Federal Reserve Commercial Paper Data Download Program plus U.S. Treasury Daily Treasury Bill Rates.
USD/JPY weekly change USD.JPY, routed as IBKR CASH on IDEALPRO with currency JPY IBKR FX tick plus HMDS midpoint history for the seven-trading-day comparison; Tier 1 historical replay uses FRED DEXJPUS.
SPX-canonical dealer gamma SPX/SPXW index options with SPY ETF options as context IBKR option chains, open interest, option quotes/model-computation ticks, and the daemon's gamma cache.
S&P 500 breadth Current S&P 500 constituent stock tickers; there is no single breadth symbol used live Local daemon compute from IBKR HMDS constituent daily bars and the generated S&P 500 membership list.

Clusters

A cluster is a group of related indicators. The composite regime counts clusters, not raw rows, so one market theme cannot vote twice.

Within each cluster, the worst ranked row wins: red beats yellow, yellow beats green. Unavailable, computing, and error rows are unranked.

Equity volatility

This cluster watches option-market fear. VIX is Cboe's 30-day implied-volatility index for the S&P 500 and VIX3M is the same measure over roughly three months, so the ratio asks whether near-term fear is priced above longer-term fear. VVIX, how volatile VIX itself is expected to be, asks whether traders are paying up for large volatility moves. When both worsen, equity stress is usually becoming more urgent.

VIX/VIX3M backwardation is stress-level evidence by itself. An isolated VVIX red between 110 and 120 is noisier: the VVIX row remains red and visible, but the equity-volatility cluster counts as yellow unless VVIX is at least 120, VIX is up at least 20% on the day, SPY is down at least 1% on the day, or another independent cluster is red.

Isolated red equity-volatility clusters are the main source of repeated false alarms in the expanded Tier 1 backtest. They are not dropped, because major stress often starts in volatility before credit, funding, or FX confirms. The downgrade keeps volatility warnings visible without letting a standalone vol-of-vol pop dominate the broad-market read.

Row Green Yellow Red
VIX/VIX3M < 0.92 0.92-1.00 > 1.00
VVIX < 90, or at level but not rising >= 90 and +3% over 5 sessions >= 110

VVIX's yellow is a transition, not a zone (vvix_daily_v2). The index has a structural floor near 85-90, so the earlier static 90-110 band was amber on 47% of calm days in a ten-year replay; requiring the level plus a 3% rise over five sessions cut that to 17% while every labeled 2015-2024 stress onset still lit ahead of its date. Red at 110 is unchanged, and a missing five-session change holds yellow at level rather than softening the warning.

Credit

The question here is whether corporate credit is weakening before or alongside stocks. HYG holds high-yield corporate bonds, meaning lower-rated company debt that behaves more like risk assets than Treasuries; SPY is the stock-market side of the comparison.

HYG/SPY is the faster market proxy. The Credit spreads row is the slower official cash-credit read, comparing high-yield and investment-grade corporate bond spreads, where OAS means the extra yield investors demand over Treasuries after adjusting for bond options. Credit stress matters because equity rallies are less sturdy when lenders are already demanding more compensation for risk.

HYG/SPY can still show a red row by itself. For the cluster count, that single proxy red is treated as a yellow watch only when the official cash gauge affirmatively disagrees: a recent OAS read (within 5 calendar days) that is neither red nor widening 0.50 pp or more over 20 observations. Cash that is red, cash that is widening at that pace, an absent or stale official read, or another independent red cluster all leave the proxy red standing — unknown cash evidence never softens a live warning. The row stays visible either way; it just does not get to call broad stress alone.

Row Green Yellow Red
HYG/SPY HYG healthy HYG below 50-DMA HYG weak while SPY is near highs
HY OAS < 4.0 and not widening 4.0-5.5 or widening > 0.50 pp > 5.5 or widening > 1.00 pp

The HYG 50-DMA and SPY historical annual-high fallback must reach the last completed equity session. A live quote cannot freshen an outdated historical baseline. Missing/stale history is disclosed before confirmation eligibility; the SPY annual fallback requires at least 252 observations.

Funding

Funding tracks stress in short-term money markets. Commercial paper is short-term company borrowing; T-bills are short-term U.S. Treasury borrowing. The spread between 90-day AA financial commercial paper and 3-month T-bills is a simple check on whether financial firms are paying noticeably more than the government to borrow over a similar short horizon.

Row Green Yellow Red
CP 90-day AA financial minus 3-month T-bill < 25 bp, or at level but not widening >= 25 bp and +10 bp over 5 publications >= 75 bp

Funding's yellow is a transition, not a zone (funding_cp_tbill_v2). The spread's calm level ranged 6-31 bp across rate regimes, so the earlier static 25 bp gate was amber on 26.6% of calm days in an eleven-year replay; requiring the level plus a 10 bp rise over the last five commercial-paper publications cut that to 5.3%. No definition, the static band included, showed real onset lead for the 2020-2024 stress events — funding confirms late by nature — so the quieter definition costs no warning. Red at 75 bp is unchanged (ten days in eleven years, eight of them March 2020), and a missing five-publication change holds yellow at level rather than softening the warning.

The current funding spread pairs the latest commercial-paper publication with the latest T-bill observation on or before that date, at most three calendar days earlier. The five-publication change uses the same date join, so a newer Treasury print cannot silently shift only one endpoint.

The previous and current Treasury months fetch concurrently and merge only when both succeed. Month selection starts from day one so short months cannot cause the same month to be fetched twice. Treasury gets a 25-second HTTP timeout within a 30-second series budget: valid monthly XML responses can take about 20 seconds. CP and cash-credit series retain their 10-second HTTP and 12-second series budgets. Parent cancellation and the 45-second overall refresh deadline remain binding; the allowance changes neither publication freshness nor funding thresholds.

FX carry

USD/JPY stands in for global carry-trade pressure. It is quoted as yen per U.S. dollar, so a falling rate means the yen is strengthening. When the yen strengthens quickly, yen-funded carry trades and other leveraged risk positions can unwind at the same time. That does not predict every selloff, but it is useful confirmation when other clusters are also deteriorating.

USD/JPY can still show a red row by itself. For the cluster count, an isolated FX red is treated as a yellow watch until another independent cluster confirms stress. The stress read may still act on a fast carry unwind when direct SPY/VIX tape or breadth confirms the move. On official non-trading dates (weekend or holiday) frozen last-session SPY/VIX prints cannot supply that tape confirmation. Inside the stress read only the breadth arm can, until live prints return at the next open, and its direct tape-shock row demotes to observe with confirm-at-next-open guidance.

Row Green Yellow Red
USD/JPY weekly change yen move < 1% yen strengthens 1-2% yen strengthens > 2%

Dealer gamma

This row models whether hedging would dampen or amplify index moves under the calls-positive/puts-negative OI assumption. The sign is measured at actual spot; above/below a crossing is only a geometric distance and can imply the wrong sign on a non-monotone profile. Treat this as conditional market structure, not a directional forecast or observed dealer inventory.

SPX/SPXW index options are the canonical production signal for S&P 500 dealer gamma. SPY's option book trades separately and is used as corroborating context when fresh and high quality. Missing or throttled SPY does not downgrade an otherwise fresh, rankable SPX gamma result. SPY-only gamma is a proxy, not the canonical S&P dealer-gamma row.

Row Green Yellow Red
SPX zero-gamma positive modeled GEX beyond transition distance within +/-2% of nearest crossing, or balanced signed GEX negative modeled GEX beyond transition distance

The v4 profile includes exact spot and narrow expiry kernels, refines sign changes, and reports all detected crossings, selecting the nearest. Same-date SPX and SPXW fits stay separate. Per-index insight carries the 0DTE, 1–7 DTE and term readings, partial coverage, feed, observation time and rankability. option_skews compares bracketed same-expiry 25-delta put and call IV; insight.selected_skew selects a covered 7–60 day expiry nearest 30 days. Positive values mean richer downside pricing, not bearish positioning. The Gamma concepts document assumptions and sources.

Gamma is ranked only when gamma_zero.envelope.result.quality.rankability is rankable. Non-rankable gamma remains visible in the row/envelope, but it does not become the active gamma market-structure read:

Rankability Meaning
rankable Fresh and covered enough to treat as the active market-structure signal. Rankable SPX is stable and production-ready even when SPY is unavailable and disclosed as context.
context_only Awareness-only market-structure context.
blocked Payload exists but a freshness, coverage, OI, model, cache, farm, entitlement, pacing, or partial-chain gate blocks ranking.
unavailable No usable OI-weighted gamma payload exists.

Missing 0DTE is disclosed in the horizon coverage and warning details, but it does not by itself make an otherwise healthy SPX read context-only when the 1-7DTE and term buckets are present. After the expiring SPXW series closes, the 0DTE bucket can be absent while the broader SPX surface remains usable.

Model-quality gates judge each underlying on its own slice, never pooled: derived-IV share, top-strike concentration, and median per-expiry skew-fit R². The skew bars are preferred ≥ 0.75 SPX, ≥ 0.70 SPY, with a hard block below 0.50. A median between the block and preferred bars still ranks, with the gate's reason disclosing the sub-preferred fit: median R² is amplitude-relative and tracks intraday smile noise rather than coverage health, so it is disclosure-worthy but not rank-blocking on its own.

The combined node carries no pooled model gates: its pooled derived-IV share is leg-count weighted across both chains and its cross-book concentration ratio matches no per-slice calibration, so gating there would let a present-but-degraded SPY downgrade a rankable SPX. Pooled numbers stay visible in quality.coverage as diagnostics, and the SPX slice's own verdict reaches the combined node through the spx_coverage gate. One consequence: a SPY slice ranking inside the disclosed skew window votes in the combined band weighting.

Successful computes retain immutable typed gamma payload observations in $XDG_STATE_HOME/ibkr/daemon.db, including fit and coverage measurements. Serving annotates current rankability afterward. The separate ranked skew calibration stream is inactive under production storage; a populated, ranked calibration corpus is not established. Existing quality bars remain heuristic.

Breadth

Breadth counts how many S&P 500 stocks are participating. A rally led by many stocks is healthier than a rally carried by a few mega-caps. Weak breadth near index highs warns that the headline index may be hiding fragility.

No live IBKR symbol carries this row: the retail feed does not provide the official S&P breadth series directly. The daemon computes it from S&P 500 member-stock daily bars and caches the post-close result; reads should not trigger a 500-name fanout.

Row Green Yellow Red
S&P 500 breadth > 55% above 50-DMA 40-55%, or weakening near highs < 40%, especially while SPX is near highs

Breadth v3 retains the latest plus 252 preceding closes and fetches enough calendar history to populate them. coverage_50, coverage_200 and coverage_highs_lows disclose separate denominators against member_count, including in history. Uncovered secondary values are null/absent; measured zero remains zero. The existing 80% 50-DMA publication requirement is unchanged.

How inputs report currency

Every regime input reports one typed currency class, and one policy says what each class may do. The class is per evidence unit — the measurement a consumer actually reads — because consumers differ: the tape arms read the VIX day-change leg, while the term-structure ratio needs the VIX3M leg beside it. Cluster currency is the worst of its rows, never the primitive.

Class Meaning May confirm Visible / bands Cost to the read
fresh current under the row's own cadence yes yes none
not_due the publication window is closed, so no newer observation can exist no yes none
pending the current period's refresh is in flight, typed and inside a bounded window anchored to the period start no yes none
stale a known value older than its window, or a due refresh that failed, inside an explicit tolerance no yes degrades readiness
overdue a newer observation should exist and no bounded excuse applies; also the class for missing or untyped evidence no policy per row data-quality defect

Confirmation is an allowlist on fresh, so a class added later cannot inherit authority. Both scheduled classes are bounded by the cluster's served max_age_seconds, so a dead subscription still serving its last value reaches overdue rather than reading healthy off-hours.

The two bounded states each have one owner. Dealer gamma is pending for 30 minutes from the options open while the session's first compute is in flight (measured compute ≈ 9 minutes; the window covers a slow open including a retry), and overdue the moment the typed in-flight marker or the window goes away — so a hung compute still surfaces. S&P 500 breadth is pending inside its 90-minute post-close publication window. A VIX3M poll missed while the index is publishing carries the previous print as stale, only while live VIX has moved under 1% since that print and for at most 15 minutes: VIX3M is the slower leg, so a 1% VIX move bounds the printed-ratio distortion near 0.01, keeping a true 1.02 away from the 1.05 that would read as backwardation.

A defect no longer discards the whole read. One cluster that is defective or impaired degrades readiness, caps confidence, and is named in lifecycle.governors[] as readiness_degraded / input_currency. The read goes to data_quality when two clusters are affected, when a defect cannot be attributed to one cluster (authority health, a surface-wide degradation), or when the defect is in the evidence the current stage itself rests on — a confirming cluster, or the only red carrying an early_warning.

Confirmation eligibility and severity governance

Eligibility gates

A red row may CONFIRM stress only when its evidence is deep, persistent, and cadence-fresh. Otherwise it is PROVISIONAL: visible on the row, listed in lifecycle.unconfirmed, able to drive early_warning, but it never counts toward confirmed_stress/panic, never rescues another cluster from its isolated-red downgrade, and never reaches confirmed_by. This policy exists because of the 2026-06-12 false positive, where a 7 bps HYG break (one session old, thin pre-open tick) and a prior-evening gamma cache mutually confirmed "Broad stress regime / act" against a green tape (internal-docs/design/regime-calibration.md).

Gates per indicator (heuristic noise floors, pending_backtest like the band thresholds; values live in internal/rpc/history_index.go):

Indicator Min depth for eligible red Fast path (eligible day 1) Min streak (NY trading sessions) Cadence freshness Exit hysteresis (leave red)
VIX/VIX3M ratio >= 1.00 ratio >= 1.05 2 same-session tick (off-window the row is not_due at best, and only while Cboe's dated close vouches for the VIX3M leg) ratio < 0.98
VVIX >= 110 >= 120 2 latest official daily close (<= 4d) < 105
HYG/SPY HYG >= 0.25% below 50DMA >= 1.0% below 2 RTH tick or latest official close (off-hours banding input is the close, never a thin pre/post print; a missing spot tick falls back to the close and marks the row stale) HYG closes back above 50DMA
HY OAS band is the gate n/a 1 series <= 7d < 5.25 and widening < 0.85 pp
Funding band is the gate n/a 1 series <= 7d < 65 bp
USD/JPY band is the gate (speed is depth) n/a 1 live tick while IDEALPRO trades (Sunday 17:15 to Friday 17:00 ET); the weekend and the daily 17:00-17:15 ET changeover are not_due, not overdue yen move < 1.5%
Dealer gamma gamma-weighted SPY/SPX signed model depth >= 0.5% short-gamma depth >= 4.5%, or a wholly-short profile 1 compute within current NY trading date (prior-date cache = stale, warns only) signed depth < -0.5%
Breadth <= 38% <= 30% 2 last completed session's compute > 45%

Dealer gamma's depth averages the two indexes by each one's gross gamma exposure — the same weighting the combined row's band vote uses, so the index that decides the band is the index that decides whether the red is deep enough to count. Crossing distance takes its sign from local GEX: negative modeled GEX gives positive stress depth, and positive GEX gives negative depth. What is averaged is each index's depth, not its geometric gap: an index whose dealers are short gamma across the whole modelled range has no crossing, and so no gap, but that is the most amplifying reading gamma has and it enters the average at its full weight. An index with no crossing on the long side has no depth to contribute and is left out.

A session is banked only from evidence that is cadence-fresh under the row's own schedule. A mixed-vintage pre-open VIX/VIX3M ratio or a closed-venue FX tick still displays its band and its hysteresis hold, but the persistence counter freezes rather than spending one of the sessions the gate requires.

Two independent VIX3M sources

In frozen mode the broker re-sends its last known value on request, and an index carries no trade timestamp, so off-window arrival time says nothing about a value's age. A gateway that keeps answering with a stale VIX3M — a lapsed market-data entitlement, a contract id that no longer resolves — is therefore indistinguishable from a quiet market on the broker leg alone.

Cboe's published VIX3M daily close is read independently of the broker and carries a real session date. Outside the publication window it is the served VIX3M whenever it covers the last completed session, and vix3m_cross_check records what the two sources established:

Verdict Meaning Off-window cadence
agree Both described the last completed window and matched. not_due
official_only The broker produced no VIX3M; the official close is the leg. not_due
pending_publication Cboe has not published the last completed window yet (it lands after the session); the broker leg stands in, bounded to one session. not_due
disagree Both described the same window and differed beyond the tolerance: the broker leg is not the close it claims to be. overdue
unverified No usable official close within one session of the last completed window. overdue

Only a vouched leg may read not_due, because not_due exempts a row from every age bound. The served row carries vix3m_source, vix3m_official, vix3m_official_date, and — on a disagreement — the broker's own vix3m_gateway_last, so the discrepancy is inspectable rather than asserted. A disagreement also raises vix3m_source_disagreement.

The comparison tolerance is heuristic and operator-owned, like the band thresholds. In session the gateway remains the source and the check does not run: Cboe publishes closes, not intraday values.

Eligibility latches for the life of the red streak (a depth wobble back inside the floor does not flip it); freshness is never latched: any currency other than fresh drops eligibility immediately, disclosed as data_not_due, data_refresh_pending, data_stale, or data_overdue. Streaks count NY trading days; a weekend or holiday poll keys to the most recent trading day.

Severity governance

Applied after stage selection and disclosed in lifecycle.governors[]:

  1. While a confirming cluster's threshold set carries pending_backtest, heuristic evidence without a fresh tape co-sign (SPY <= -1.5%, VIX +10%, or a same-session term inversion) reads one severity rung down: confirmed_stress -> watch, 3-red panic -> act. Pure-tape panic (SPY <= -4%/-7%) always reaches urgent.
  2. If a confirming cluster's source health is stale/partial/degraded, severity caps at watch (evidence-keyed: an unrelated dead feed does not mute a fresh confirmation).

Display tone follows governed severity, not just stage: confirmed_stress with severity: watch remains an amber/watch headline, preserving red for act-grade stress and risk_off for full risk-off conditions. The condition label still stays "Confirmed stress regime" so the evidence balance is not watered down.

Closed-date tape gating

Every lifecycle term that reads the direct SPY/VIX day-change prints requires an official trading date (2026-07-19). The daemon stamps tape_session_state (embedded NYSE calendar) on each regime snapshot and journals it as tape_session; the backtest replay stamps the same classification from the observation clock. On a closed date (weekend or holiday), frozen last-session prints:

The tape evidence rows keep the frozen print's magnitude but read forward-warning / observe / unconfirmed. Cluster-driven terms are untouched, so real cluster reds still warn and confirm on any date. Weekday pre/post/overnight prints keep full effect because they are live, and dates outside embedded calendar coverage leave the state empty so tape terms fail open. The trading rulebook's regime-stage latch skips closed-date snapshots: the last trading-date stage governs weekend rule thresholds through the existing carried worse-of path instead of a frozen-print or cluster-only weekend stage re-latching fresh.

The day-change numbers themselves are pinned on those same dates. The gateway's last print and its tick-9 previous-close anchor can each reset independently while the market is closed. The live Sunday exhibit read SPY +0.00% beside VIX +12.19% while Friday truly closed SPY −0.99% / VIX +12.19%, a pair no market ever printed. So on official non-trading dates the daemon computes spy_change / spy_change_pct / vix_change_pct from the official daily closes of the last two completed sessions and names the span in spy_change_basis / vix_change_basis ("official closes 2026-07-16 → 2026-07-17 (weekend)"). Bars are matched by exact official session date; when the closes cannot be resolved the change fields are withheld (fields_missing: spy_day_change / vix_day_change) rather than backfilled from drifted snapshots. Price ticks, the VIX/VIX3M ratio, and banding inputs are unchanged. Only the day-change fields pin.

Composite logic

The headline label is a single wording table shared by composite.verdict and posture.label (rpc.RegimeHeadline); CLI, MCP, and SPA render the served string:

Cluster state Regime label
0 red and 0-2 yellow Normal regime
0 red and 3+ yellow Elevated stress watch
provisional (unconfirmed) red only Watch: one unconfirmed stress signal
any eligible red below confirmation Stress signal present
stage confirmed_stress/panic (2 eligible reds, or 1 + tape) Confirmed stress regime
3+ eligible red Broad stress regime
all ranked clusters eligible red Full risk-off conditions

Raw indicator counts may also appear. Cluster counts are the primary signal because related rows, such as VIX and VVIX, are not fully independent votes; cluster_eligible_red_count and cluster_provisional_red_count split the reds by confirmation eligibility.

Lifecycle is a second layer over the row and cluster evidence:

Lifecycle stage Broad-market meaning
quiet Enough data is ranked and no material stress or recovery/opportunity evidence is present.
early_warning Weak, isolated, provisional, or forward-looking evidence is visible, but eligible independent confirmation is not yet present.
confirmed_stress At least two ELIGIBLE stress clusters, or one eligible cluster plus confirming SPY/VIX tape, are active.
panic Three or more eligible stress clusters, or tape severe enough (SPY <= -4%/-7%) that the regime should be treated as acute.
stabilization Stress evidence is easing, but this is not yet a deployable opportunity by itself.
opportunity Constructive tape and low stress evidence are present; this is broad-market context only, not a trade instruction.
data_quality Missing, stale, computing, or degraded inputs prevent a confident lifecycle read.

readiness should be blocked or degraded when critical source health is stale, partial, computing, or degraded; the severity governor additionally caps the demanded response when the CONFIRMING clusters themselves are impaired.

The independence rescue that waives an isolated-red downgrade counts ELIGIBLE reds only, so two marginal reds can no longer confirm each other.

Method notes

The live gamma sweep uses the nearest 80 listed strikes per expiry inside the +/-10% candidate window to keep the IBKR fan-out bounded, especially for SPX/SPXW. Historical verification must preserve the same bounded selection and source-quality rules.

Open interest is a required input for OI-weighted dealer GEX, but missing OI is unknown, never zero. Priced legs without observed OI may still fit the IV/skew surface, but they must be omitted from OI-weighted GEX and surfaced through warning_details / data_quality. SPY option OI can be absent outside regular U.S. option hours. SPX option OI should normally be stable across session phases; missing SPX OI is unexpected data-quality evidence even pre-market, after-hours, overnight, or on closed-session cache reads.

MOVE/rates-vol is outside the live surface until a verified IBKR contract or licensed official connector exists. Do not proxy it with ETFs or futures.

Decision events

Every decision-relevant regime snapshot appends one typed event to the daemon's sole live authority, $XDG_STATE_HOME/ibkr/daemon.db: raw values, bands, depth metrics, streaks, freshness, eligibility, cluster tallies, lifecycle decision, and governor records. Events dedupe on the snapshot's semantic fingerprint with an hourly heartbeat. The append-only event corpus powers typed history queries and makes the pending_backtest thresholds calibratable; it is not a separate file or a delete-safe cache. Each event also carries currency_policy, the input-currency policy version it was decided under (regime-currency-v1 from 2026-07-31, when the model replaced four per-symptom freshness rules). Behaviour changes there move the daily fingerprint sequence, so a backtest partitions on this marker instead of blending days from either side of a cutover. A threshold set drops pending_backtest only with months of coverage, measured false-alarm/recall rates against labeled episodes, and a version-label bump documented here. Disable collection via canary settings set regime.journal.enabled=false.

Calibration evidence

The event history above is the replay input for future calibration. A policy change may replace pending_backtest only when its versioned evidence records coverage, false-alarm and recall rates, data-quality exclusions, and ordinary regression tests for the resulting thresholds. Canary no longer exposes a general-purpose user-facing backtest command.