recon_gen.common.l2.tg_cache
In-memory TestGeneratorConfig cache for Studio’s data-shaping panel.
X.4.h.2 introduces this cache as the in-memory authority for the
trainer’s knob state (plants / scope / end_date / seed). Mirrors the
L2InstanceCache shape: constructed once at Studio startup from
cfg.test_generator; mutated in-place by the /data/knobs/* PUT
routes (h.2-h.5); read by the Studio /deploy route which patches a
fresh Config clone with cache.get() before calling
run_deploy_pipeline.
No disk persistence here — h.7 layers cfg.yaml save on top via the
same atomic-write primitive L2InstanceCache.save uses.
Severability: Studio-only. Dashboards (recon-gen dashboards)
does NOT instantiate this cache — it has no knobs to mutate. The
absent-cache path is the unit-test surface (make_studio_routes with
tg_cache=None); routes that mutate it are mounted only when the
cache exists.
Classes
|
- class recon_gen.common.l2.tg_cache.TestGeneratorCache(state, window=None, *, etl_hook_enabled=True, state_path=None)[source]
Bases:
object- Parameters:
state (TestGeneratorConfig)
window (DateInterval | None)
etl_hook_enabled (bool)
state_path (Path | None)
- classmethod from_cfg_with_state(cfg, cfg_path)[source]
X.4.h.7 — Studio-CLI factory. Load the sidefile if present, merge its overrides on top of cfg.test_generator defaults, wire the cache to write to that sidefile on every mutation.
Sidefile path is
<cfg_path.parent>/.studio-state.yaml(sibling of cfg.yaml). Missing sidefile ⇒ pristine cfg defaults + empty Studio state. Malformed sidefile ⇒ same fallback with a warning to stderr (perload_studio_state).- Return type:
- Parameters:
cfg (Config)
cfg_path (Path | str)
- classmethod from_config(cfg)[source]
Snapshot
cfg.test_generator+ materialize default window.Window default =
[today - (DEFAULT_BASELINE_WINDOW_DAYS - 1), today]— the last 90 days. Trainer-mode UI is not a determinism path, so the wall-clock anchor is honest here.No sidefile persistence — see
from_cfg_with_statefor the Studio-CLI flow that loads + saves to disk.- Return type:
- Parameters:
cfg (Config)
- get()[source]
Return the current generator state.
TestGeneratorConfigis frozen, so the returned reference is safe to share without defensive-copy concerns.- Return type:
- get_frame()[source]
BD.5 — return the trainer’s frame as a single AsOfFrame.
The trainer’s three temporal-and-determinism pieces — scrub head (get_up_to()), scenario window (get_window()), and RNG seed (get().seed) — bundle naturally into the post-BD.1 AsOfFrame(as_of, window, seed) shape. Callers that need all three together (plant emit via scenario_to_generators(frame=…) per BD.3, dashboard defaults via DateView(frame=…) per BD.4) take the frame instead of three independent reads.
Derivation: as_of = get_up_to() (the scrub head — what the trainer is “looking at”); window = _window; seed = state.seed (None when the cfg hasn’t pinned one, same as AsOfFrame.live()).
- Return type:
- get_up_to()[source]
Resolve the “up to” / scrub-head date.
tg.end_dateis the cached value; when it’s None the cache falls back toself._window.end(the trainer’s intent: “render up through the right edge of my scenario window”).- Return type:
date
- is_etl_hook_enabled()[source]
Return whether
cfg.etl_hookwill run on the next Deploy.True (default) ⇒
patched_configkeepscfg.etl_hookas configured. False ⇒patched_configclears it to None for that deploy (the cfg’s stored command is unaffected — the operator can flip the toggle back on without re-typing).- Return type:
bool
- patched_config(cfg)[source]
Return a clone of
cfgwithtest_generatorswapped in.Trainer “scrub head” model —
end_dateandcutoff_dateplay different roles in the patched cfg:end_datebecomeswindow_end(the scenario anchor). Generator anchors at this date so plants land at fixed calendar positions regardless of where the trainer’s scrub head is. Stable scenario.cutoff_datebecomes the trainer’sup_to(the scrub head). Deploy’s_build_generator_sqlappends DELETE statements after the generator emits to truncate rows past this date. None when up_to == window_end (no truncation).
This decouples “what scenario am I rendering?” (anchor = window_end) from “how far through it am I?” (cutoff = up_to). Click in the timeline → up_to changes, plants stay put, emission cuts off at the new scrub head. Matches the trainer’s mental model end-to-end.
CLI invocations of
data applydon’t go through this method — they readcfg.test_generatordirectly, whereend_datekeeps its legacy “anchor” meaning andcutoff_datedefaults to None (no truncation, current byte-identical-to-locked-seeds behavior).
- replace(new_state)[source]
Swap the cached generator state (window untouched).
- Return type:
None- Parameters:
new_state (TestGeneratorConfig)
- set_etl_hook_enabled(enabled)[source]
Toggle
cfg.etl_hookexecution on the next Deploy.- Return type:
None- Parameters:
enabled (bool)
- update(*, scope=<object object>, end_date=<object object>, seed=<object object>, plants=<object object>)[source]
Partial update of the generator state — window is separate.
Noneis a valid value forend_dateandseed(it means “use the locked default”), so a _UNSET sentinel is the only way to express “leave this field alone”. Returns the new generator state for the caller to inspect / log.- Return type:
- Parameters:
scope (Literal['full', 'exceptions_only', 'uncovered_rails', 'only_template'] | object)
end_date (date | None | object)
seed (int | None | object)
plants (tuple[Literal['drift', 'overdraft', 'limit_breach', 'stuck_pending', 'stuck_unbundled', 'supersession'], ...] | object)
- update_derive_balances(enabled)[source]
X.4.i.3 — toggle the derive_balances post-step-3 flag.
- Return type:
None- Parameters:
enabled (bool)
- update_only_template(value)[source]
X.4.i.3 — set the only_template name (template-scope target).
Noneclears the field. Validation against the L2 instance’s actual templates happens at deploy time in _only_template_rails, not here — the UI accepts any string so the trainer can hold an inconsistent state mid-edit.- Return type:
None- Parameters:
value (str | None)
- update_window(*, start=<object object>, end=<object object>)[source]
Partial update of the trainer’s scenario window.
Both bounds optional — pass only what changed. After update if
start > end, swap them (operator typed in a confusing order; preserve the intent rather than reject). Returns the newDateIntervalfor caller logging.Window changes do NOT touch
end_date(the up_to scrub head) — it stays where the operator set it. The renderer clamps out-of-window up_to values for display; the next click in the panel will overwrite to a valid date anyway.- Return type:
- Parameters:
start (date | object)
end (date | object)