Vesper Tasking — Anchor Error Per-Tick Telemetry¶
To: Orion (he/him)
From: Vesper (she/her)
CC: Katja (Captain), Atlas (he/him)
Date: 2026-04-21
Branch: feat/anchor-error-per-tick-telemetry
Priority: HIGH — Phase 7.3 gate 6, required before live sessions can be evaluated
Context¶
The anchor saturation guard is live and evaluates last_anchor_divergence_bps on every tick using a rolling 25-tick window. The guard triggers DEGRADED when the bias and prevalence thresholds are exceeded. What we do not have: any persistent record of what the anchor error was doing tick-by-tick during a session.
After live sessions resume, we need to be able to answer:
- Were the guard thresholds (6–8 bps mean, 40% prevalence) calibrated correctly?
- Was the guard too sensitive or not sensitive enough?
- What was the anchor error distribution over the full session?
- At what tick did the error first exceed the bias threshold?
Without per-tick anchor error in the DB, post-session calibration is guesswork. This branch closes that gap.
What Already Exists¶
The anchor_error_bps reliability stat was added in fix/cleanup-and-anchor-instrumentation (Apr 18, commit 469e5bb):
_log_anchor_divergence_summary()inmain_loop.pycomputespct_error_above_5at session summary timeengine_statekeyanchor.pct_error_above_5bpsis written at session closesummarize_paper_run.pyreads and displays it
That is a session-level aggregate. This branch adds the per-tick time series.
system_metrics is the existing per-tick telemetry table, written every tick, tagged with session_id. It is the correct home for per-tick anchor error. Adding a column there requires the _ensure_column additive migration pattern established on circuit_breaker_events (anchor saturation guard, D2.2).
Spec¶
One additive column on system_metrics:
Written on every tick when system_metrics is written. Value is self._strategy.last_anchor_divergence_bps — the same source the anchor saturation guard reads from. When that value is None (no market data this tick), write NULL (do not substitute 0.0).
No new table. system_metrics already has session_id and captures all per-tick state. One column is the right scope.
No guard logic. This branch is telemetry only — it does not change any guard behavior, thresholds, or DEGRADED transitions.
No strategy tuning. Config parameters are not touched.
Pre-Code Investigation Required¶
Before writing any code, investigate and report on the following:
Q1 — system_metrics write location. Where in main_loop.py is the system_metrics row written? What is the function or call site? At that point in the tick, is self._strategy.last_anchor_divergence_bps already computed and in scope? The anchor saturation guard reads this value at Step 8.5 (after Phase 3E anchor diagnostics). Confirm that the system_metrics write happens after Phase 3E — otherwise the value read will be from the previous tick.
Q2 — _ensure_column migration pattern. Confirm the additive column pattern: _ensure_column(conn, "system_metrics", "anchor_error_bps", "REAL") in initialize_database(). Is this the correct call site? Does state_manager.py already apply _ensure_column to system_metrics for any column, or is this the first use on that table? Check for any existing system_metrics schema setup that would need updating alongside the _ensure_column call.
Q3 — NULL vs 0.0 handling in system_metrics. Inspect how other nullable REAL columns in system_metrics are handled when their source value is None (e.g. distance_to_touch_bid_bps — added by Branch #6 and only populated in live mode). Confirm that passing None directly to the insert produces a SQL NULL (not a cast error or a 0.0 substitution). Identify the insert call so I know exactly where to add the new field.
Q4 — Existing anchor_error_bps references. Is there any existing column or field in system_metrics that already captures anchor error under a different name? Check state_manager.py, main_loop.py, and the schema migration history. We must not create a duplicate.
Report findings before writing any code.
Implementation Guidance¶
Migration: _ensure_column(conn, "system_metrics", "anchor_error_bps", "REAL") in initialize_database(). Existing rows will be NULL — correct, they predate this branch.
Write site: At the system_metrics insert, add anchor_error_bps = self._strategy.last_anchor_divergence_bps (or None if unavailable). Pass None directly — do not substitute 0.0.
No new infrastructure. No new writer function, no new config, no new guard state. One column, one value, one write per tick.
Test Requirements¶
Minimum 6 tests:
- Fresh DB —
anchor_error_bpscolumn present afterinitialize_database() - Existing DB missing column —
_ensure_columnadds it without error (idempotency) - Tick with valid
last_anchor_divergence_bps— correct float written to column - Tick with
last_anchor_divergence_bps = None— NULL written (not 0.0) - Multi-tick integration — two ticks written and read back, values match inputs,
session_idpopulated on both - Existing
system_metricscolumns unaffected — spot-check at least two other columns in a round-trip to confirm no regression
Windows teardown: if any integration test uses a real StateManager with a temp directory, apply the LIFO addCleanup pattern (sm.close() registered before tmpdir.cleanup()).
Commit Plan (suggested)¶
feat(db): add anchor_error_bps column to system_metrics (per-tick anchor telemetry)feat(main_loop): write anchor_error_bps to system_metrics on each ticktest(telemetry): anchor error per-tick telemetry — N tests
Regression Suite¶
After merge, the full regression suite will include this branch's new test file. Current count is 111 + new tests. Provide the updated pytest run command in your delivery.
Constraints¶
_ensure_columnmigration only — do not ALTER TABLE or DROP/RECREATE- No guard logic, no config changes, no strategy tuning
- NULL for missing mid — do not substitute 0.0
- No pre-creating the branch during investigation
- PowerShell apply instructions must use
Get-ChildItemform (not*.patchglob) - Always include defensive
git branch -Dbeforegit checkout -bin apply instructions - Windows teardown fix required in any integration tests using real
StateManager
Deliverable¶
Standard format: branch name, commit list with hashes and messages, test count and pass rate, pre-code investigation findings, any deviations flagged explicitly. Vesper reviews before merge.
— Vesper