Skip to content

feat(norgate): data-driven --require-final gate (drop the fragile wall-clock cutoff) - #77

Merged
mspinola merged 3 commits into
mainfrom
claude/cotdata-finals-ready-data-driven
Jul 28, 2026
Merged

mspinola merged 3 commits into
mainfrom
claude/cotdata-finals-ready-data-driven

Conversation

@mspinola

Copy link
Copy Markdown
Owner

What

Replaces the fragile wall-clock --require-final gate with a data-driven one: defer until Norgate has a newer settled continuous bar than the store already holds, across a liquid reference quorum (ES, CL, ZC).

Why

The clock cutoff (--final-cutoff, default 20:55) required both the Futures and Continuous Futures databases to be refreshed at/after a fixed local time. That is fragile by construction — the cutoff must sit below the earliest evening final yet above any daytime interim, and Norgate's publish time drifts night to night.

It broke in production on 2026-07-27: Norgate finalized the Futures DB at 8:49pm and never touched it again that night, so 8:49 < 20:55 never satisfied the gate, every retry deferred, the chained store sync was skipped, and prices went stale on Friday's bar. It also has no single safe value — finalize at 20:44 and a 20:45 cutoff misses it; lower the cutoff and you risk capturing a pre-settlement bar.

Investigation (probe on the Windows producer)

scripts/probe_norgate_finals.py established:

  • norgatedata exposes no holiday/trading-calendar API.
  • last_quoted_date is None for continuous symbols (it's for expiring instruments), so the signal must come from price_timeseries.
  • Norgate (EOD) never shows an in-progress session's bar — at 11am Tue the latest continuous bar was Mon 7/27 (final OHLC, OI=0 marking the newest bar). No Tuesday bar existed intraday.

So a bar date newer than the store's is a clean "a new session settled" signal, needing no clock and no calendar.

Change

finals_ready := every reference symbol's latest Norgate bar date  >  its stored date
  • _finals_ready_by_date (pure per-symbol core) + _finals_ready_quorum (pure combiner, requires the whole quorum so a session is captured once and complete) + finals_ready (thin norgatedata I/O: trailing price_timeseries window for the Norgate date, prices manifest for the store date).
  • CLI: --require-final uses it; --final-cutoff is accepted but ignored (deprecated) so existing schedulers don't break. Legacy _finals_ready clock core retained, unused, for rollback.
  • Immune to publish-time drift (early → ready early; late → a retry catches it); weekends/holidays produce no new bar. The 2026-07-27 stall cannot recur — Monday's settled bar would have been captured Monday evening.

Tests

norgatedata-free: pure core, quorum (all-advance vs one lagging), finals_ready wiring via mocks, and the ignored cutoff arg. 23 passing, ruff clean. The --require-final CLI-exit tests (which mock finals_ready) are unchanged and pass.

Rollout

Data-driven is the default (the old path is broken, so there's nothing to fall back to). Remaining step: a few nights of live validation on the Windows producer — confirm it flips to ready when the new settled bar lands and stays not-ready on a same-session re-run. Spec: docs/design/finals_ready_data_driven.md.

🤖 Generated with Claude Code

mspinola and others added 3 commits July 28, 2026 06:53
…lock cutoff)

The --require-final gate uses a fixed local-clock cutoff (--final-cutoff, default
20:55). It broke on 2026-07-27: Norgate finalized the Futures DB at 8:49 PM, the
check requires both Futures and Continuous >= 20:55, so 8:49 < 8:55 deferred all
night and prices went stale. A wall-clock cutoff is fragile by construction (must
sit below the earliest evening final yet above any daytime interim; Norgate drifts).

norgatedata has no calendar API but exposes last_quoted_date(symbol) — the latest
bar date — which lets finals_ready ask "has the latest bar advanced to the expected
session?" instead of "was the file touched after a magic minute?", immune to
publish-time drift.

Adds:
- docs/design/finals_ready_data_driven.md — problem, available API, proposed
  data + session design, the calendar-source options, and the one open question
  (does Norgate expose a provisional current-day bar pre-settlement?).
- scripts/probe_norgate_finals.py — Windows probe to answer that question and
  confirm no calendar function in the installed build.

Spec only; implementation follows once the probe result is in.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… tests

Daytime probe settled the design: norgatedata has no calendar API,
last_quoted_date is None for continuous symbols, and Norgate (EOD) never shows an
in-progress session's bar (at 11am Tue the latest continuous bar was Mon 7/27,
final OHLC, OI=0 marking the newest bar). So the finals gate needs neither a
trading calendar nor a wall-clock cutoff:

    finals_ready := norgate_latest_bar_date > store_latest_bar_date

Add the pure, norgatedata-free core `_finals_ready_by_date(norgate_last, store_last)`
with unit tests (newer session ready; store-current not ready; empty store ready;
no-bar defers; datetimes normalized to date). Weekends/holidays produce no new bar
so no capture; publish-time drift is absorbed by retries; the 2026-07-27 stall
could not recur.

Not yet wired into the CLI: pending a two-point evening probe to confirm Norgate
never shows the session bar provisionally pre-settlement, then finals_ready() I/O
+ keep --final-cutoff as a deprecated fallback. Spec: docs/design/finals_ready_data_driven.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…k cutoff

--require-final now defers until Norgate holds a NEWER settled continuous bar than
the store already has, across a liquid reference quorum (ES, CL, ZC), instead of
waiting for a fixed local-clock cutoff on the DB refresh time.

Why: the clock cutoff (--final-cutoff, default 20:55) is fragile by construction and
broke on 2026-07-27 — Norgate finalized the Futures DB at 8:49pm, the check requires
both Futures and Continuous >= 20:55, so 8:49 < 8:55 deferred all night and prices
went stale. A wall-clock cutoff must sit below the earliest evening final yet above
any daytime interim, and Norgate's publish time drifts. The daytime probe showed
norgatedata has no calendar API, last_quoted_date is None for continuous symbols, and
Norgate (EOD) never exposes an in-progress session's bar — so "newer settled bar than
the store" is a clean, robust signal.

- finals_ready(): thin norgatedata I/O (_norgate_last_bar_date via a short trailing
  price_timeseries window; _store_last_bar_date from the prices manifest) delegating
  to the pure _finals_ready_quorum over _finals_ready_by_date. Guards on
  _require_norgate_service().
- CLI: --require-final uses it; --final-cutoff accepted-but-ignored (deprecated) so
  no scheduler breaks. Legacy _finals_ready clock core retained, unused, for rollback.
- Tests (norgatedata-free): pure core, quorum (all-advance vs one lagging), wiring via
  mocks, ignored cutoff arg. 23 passing; ruff clean.

Immune to publish-time drift (early → ready early, late → a retry catches it) and needs
no trading calendar (weekends/holidays produce no new bar). Live validation on the
Windows producer is the remaining rollout step. Spec: docs/design/finals_ready_data_driven.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mspinola
mspinola merged commit 1ec7bdc into main Jul 28, 2026
5 checks passed
@mspinola
mspinola deleted the claude/cotdata-finals-ready-data-driven branch July 28, 2026 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant