recon_gen.common.as_of_frame
The owned temporal frame (D1; BD-extended).
AsOfFrame is the single anchor both the generator and the views read in
place of wall-clock now(). See docs/audits/date_range_model_audit.md
§5 (“step back — time is the unowned coordinate”) and the AP.0 spike
result for the reasoning. Promoted from tests/unit/test_ap0_as_of_frame.py
by Phase AQ; BD ships the three-leg (as_of, window, seed) shape on
the same class (no RunContext rename — see docs/audits/bd_0_asofframe_spike.md).
Three fields:
as_of: date— the calendar day this run anchors to. The “right edge” of the system’s temporal frame.
window: DateInterval— the closed-closed date range this run queries / plants into. NOT constrained to end atas_of(audit windows end yesterday; trainer windows span the operator’s scenario;as_ofis independent).
seed: int | None— RNG seed for deterministic outputs. None means “use the spine’s internal default” (production live mode).
Four named constructors (the recommended call shapes):
AsOfFrame.locked(window_days=N)— demo/test binding. Anchor pinned at LOCKED_ANCHOR.window_days=Nis an ergonomic shortcut that internally builds a closed-closed N-day window ending at the anchor.
AsOfFrame.live(window_days=N)— production binding. Anchor viadate.today()(the single blessed wall-clock read in this codebase). Samewindow_days=Nshortcut.
AsOfFrame.for_audit(today, *, lookback_days)— audit-CLI binding. Window =trailing_days_ending_yesterday(today, lookback_days)(today excluded, the audit-window convention).
AsOfFrame.for_test(*, window, seed, as_of=None)— test fixtures’ explicit shape.seedrequired because tests are deterministic by construction;as_ofdefaults towindow.end.
What is intentionally NOT here: renderer-specific derivations (QS RollingDate exprs, App2 sentinels, picker defaults). Those live on the View primitive (Phase AR) which takes an AsOfFrame as its anchor; one view object emits both QS and App2 bindings so the C1 dual-default split becomes unrepresentable.
BD.0 D6 (locked 2026-05-25 per the no-compat-shims principle): the v1
window_days: int field is GONE. Callers that read frame.window_days
migrate to frame.window.days (closed-closed count) or
frame.window.start (left edge — the dominant pattern, already
encapsulated by the window_start property which now derives from
frame.window.start). The window_days=N keyword arg stays on
live() / locked() as a construction-time ergonomic shortcut —
construction-time ergonomics ≠ runtime escape hatch.
LOCKED_ANCHOR is the single source of truth for the demo anchor (AQ.3 funneled the value here; BD.6 retired the cli/data.py::_CANONICAL_LOCK_ANCHOR alias kept for caller-compat). Every locked seed + every locked-binding frame anchors here.
Module Attributes
The canonical demo anchor — every locked seed + every locked-binding frame anchors here. |
Classes
|
The owned temporal frame: anchor (as_of) + queried window + seed. |
- class recon_gen.common.as_of_frame.AsOfFrame(as_of, window, seed=None)[source]
Bases:
objectThe owned temporal frame: anchor (as_of) + queried window + seed.
Every temporal predicate the system reads — the generator’s data-end day, a view’s window bounds, “latest” semantics, RNG determinism — derives from this one object instead of wall-clock
now(), parallel period: DateInterval args, or scattered seed: int kwargs. The locked-vs-live split is a single binding choice rather than three independent encodings (the C1 release-blocker shape).- Parameters:
as_of (date)
window (DateInterval)
seed (int | None)
- as_of: date
- contains(day)[source]
Is
dayinsideself.window(closed-closed)?BD.1 — the semantic is now “in the window,” not “in
[window_start, as_of].” For frames wherewindow.end == as_of(the dominant pre-BD pattern), the two are equivalent; for audit frames wherewindowends yesterday andas_ofis today, the new semantic is the right one — we’re checking whether the day falls in the QUERIED range, not the wall-clock epoch.- Return type:
bool- Parameters:
day (date)
- classmethod for_audit(today, *, lookback_days, seed=None)[source]
Audit-CLI binding. Window =
DateInterval.trailing_days_ending_yesterday(today, lookback_days)— N days ending yesterday, today EXCLUDED (the audit-window convention — “you can’t audit a day that hasn’t closed yet”).as_of = today(the day the audit runs).- Return type:
- Parameters:
today (date)
lookback_days (int)
seed (int | None)
- classmethod for_test(*, window, seed=0, as_of=None)[source]
Test-fixture binding — explicit window + seed.
seeddefaults to0(a known-good deterministic seed); passNoneto opt into the spine’s internal default.as_ofdefaults towindow.end(the most-recently-closed day in the window — matches the audit-window-end convention).- Return type:
- Parameters:
window (DateInterval)
seed (int)
as_of (date | None)
- classmethod live(*, window_days=0, seed=None)[source]
Production binding — anchor = today. Same derivations as locked(); only the bound anchor value differs (the §8 determinism story falls out of the frame for free).
window_daysergonomic shortcut — see locked for the construction shape.- Return type:
- Parameters:
window_days (int)
seed (int | None)
- classmethod locked(*, window_days=0, seed=None)[source]
Demo/test binding — anchor pinned at LOCKED_ANCHOR.
window_daysis an ergonomic shortcut: 0 means single-day, N>0 means a closed-closed N-day window ending at the anchor. (Internally builds the DateInterval — the FIELD on the resulting object is window, not the int.)- Return type:
- Parameters:
window_days (int)
seed (int | None)
- seed: int | None = None
- window: DateInterval
- property window_start: date
The window’s left edge —
self.window.start.Kept for backward compat with existing callers that read frame.window_start directly. New code prefers frame.window.start.
- recon_gen.common.as_of_frame.LOCKED_ANCHOR: Final[date] = datetime.date(2030, 1, 1)
The canonical demo anchor — every locked seed + every locked-binding frame anchors here. Single source of truth post-BD.6 (_CANONICAL_LOCK_ANCHOR alias in cli/data.py retired).