recon_gen.common.l2.demo_etl_gaps
BTa.8 — ETL-feed gap plants for the bundled-demo path.
When the operator runs Studio without an etl_hook configured,
the synthetic-data generator produces clean, L2-conformant rows.
That’s correct for production deployments — but it leaves the
/etl/triage page empty, so the BTa.4 accordion / volume
badges / per-kind color stripes never get exercised in the demo
experience.
This module exposes one plant function per demo-surfaced ETL
trust-killer, mirroring how add_broken_rail_plants /
boost_inv_fanout_plants in auto_scenario.py cover the
L1-invariant violation kinds. Each function below produces SQL
for ONE plant kind; emit_demo_etl_gap_sql composes them.
Two surfaces, two failure shapes:
Plant kind Surface Function —————————– —————- ———————————- phantom rail (INSERT) Triage add_phantom_rail_gap_rows phantom template (INSERT) Triage add_phantom_template_gap_rows missing metadata (INSERT) Triage add_missing_metadata_gap_rows uncovered rail (DELETE) Coverage add_uncovered_rail_gap_rows uncovered template (DELETE) Coverage add_uncovered_template_gap_rows missing_limit_schedule (NOT planted) — see note below
Cold-read v3 finding: planting only Triage gaps (the INSERT kind) left Coverage all-green while Triage went red. The operator’s mental model says “if Triage has gaps, Coverage should reflect the brokenness too” — otherwise a glance at Coverage misleads. DELETE-based plants surgically empty one L2 entity’s transaction set so its Coverage card flips to ✗ (“declared but no rows”).
The missing_limit_schedule gap kind isn’t planted here because
it’s an L2-shape gap (rail/role pair without a schedule), not a
transaction-stream gap; you can’t synthesize it via inserts.
Architectural note: L1-invariant plants ship as ScenarioPlant
dataclass entries that flow through emit_full_seed’s emitter
pipeline. ETL-feed gaps live in the transaction stream’s contract
layer (not the invariant layer), so they ship as raw INSERT overlays
invoked AFTER the generator finishes — same conceptual “plant”
pattern (deterministic, demo-only, lights up a specific dashboard
surface), different integration point.
Gated by cfg.etl_hook is None at the studio call site — a real
operator’s ETL feed is the source of truth; demo overlay would
corrupt it. Locked seeds are unaffected because they’re built from
the generator pipeline directly, never via this overlay.
Functions
|
Plant |
|
Empty all transactions for one L2-declared bundle_target (DELETE). |
|
Empty all Debit transactions for one L2-declared LimitSchedule cell (DELETE). |
|
Empty all transactions for one L2-declared (rail, metadata_key) pair (DELETE). |
|
Plant one transaction whose |
|
Plant |
|
Plant |
|
Empty all transactions for one L2-declared rail (DELETE). |
|
Empty all transactions for one L2-declared template (DELETE). |
|
Compose all demo ETL-feed gap plants into one SQL overlay. |
- recon_gen.common.l2.demo_etl_gaps.add_chain_orphan_gap_rows(instance, *, prefix, dialect, anchor, count=3)[source]
Plant
countparent firings for a Required (singleton-children, non-fan_in) chain WITHOUT matching child firings.Picks the alphabetically-first Required chain (singleton children, fan_in=False on the only child). Inserts
countrows whoserail_nameis the chain’s parent identifier; no row references these as atransfer_parent_id, so the L2FTbuild_exc_chain_orphans_datasetcheck fires (parent_firing_count > child_firing_count).Returns empty string when the L2 declares no Required chain — the BU.3 picker’s “satisfiability” guard.
- Return type:
str- Parameters:
instance (L2Instance)
prefix (str)
dialect (Dialect)
anchor (datetime)
count (int)
- recon_gen.common.l2.demo_etl_gaps.add_dead_bundles_activity_gap_rows(instance, *, prefix, dialect)[source]
Empty all transactions for one L2-declared bundle_target (DELETE).
Picks the alphabetically-first (aggregating_rail, bundle_target) pair declared on an L2 rail’s
bundles_activity; deletes every row whoserail_name = bundle_targetso thebuild_exc_dead_bundles_activity_datasetcheck’s NOT EXISTS matches. Returns empty string when no rail declaresbundles_activity.- Return type:
str- Parameters:
instance (L2Instance)
prefix (str)
dialect (Dialect)
- recon_gen.common.l2.demo_etl_gaps.add_dead_limit_schedule_gap_rows(instance, *, prefix, dialect)[source]
Empty all Debit transactions for one L2-declared LimitSchedule cell (DELETE).
The L2FT
dead_limit_schedulescheck fires when no Debit posting matches (parent_role, rail_name). Picks the alphabetically-first (parent_role, rail_name) cell declared ininstance.limit_schedules+ deletes every matching Debit row. Returns empty string when no LimitSchedule is declared.- Return type:
str- Parameters:
instance (L2Instance)
prefix (str)
dialect (Dialect)
- recon_gen.common.l2.demo_etl_gaps.add_dead_metadata_gap_rows(instance, *, prefix, dialect)[source]
Empty all transactions for one L2-declared (rail, metadata_key) pair (DELETE).
The L2FT
dead_metadatacheck fires per (rail, metadata_key) declared on an L2 Rail when no posting on that rail carries a non-null value for the key. Simplest plant: DELETE every row on the chosen rail — the NOT EXISTS guard then matches for every key the rail declared (rail-level), surfacing one or more rows on the L2FT Hygiene Exceptions sheet’s Dead Metadata Declarations branch.Picks the alphabetically-first rail with non-empty
metadata_keys. Returns empty string when no rail declares any.- Return type:
str- Parameters:
instance (L2Instance)
prefix (str)
dialect (Dialect)
- recon_gen.common.l2.demo_etl_gaps.add_missing_metadata_gap_rows(instance, *, prefix, dialect, anchor)[source]
Plant one transaction whose
template_nameresolves but whose metadata omits the template’s requiredtransfer_key.Triage’s
_detect_missing_metadata_keyspicks this up + renders amissing_metadata_keyaccordion section. Returns empty string when the L2 has no template with atransfer_key— the gap can’t be synthesized without a target template that declares one.- Return type:
str- Parameters:
instance (L2Instance)
prefix (str)
dialect (Dialect)
anchor (datetime)
- recon_gen.common.l2.demo_etl_gaps.add_phantom_rail_gap_rows(*, prefix, dialect, anchor, count=3, rail_name='legacy_card_swipe')[source]
Plant
counttransactions whoserail_namedoesn’t resolve in the L2.Triage’s
_detect_unmatched_railspicks these up + renders anunmatched_railaccordion section with the volume badge showing<count> rows. The default phantom name (legacy_card_swipe) is chosen to read like a plausible legacy rail an integrator might forget to declare — not a random sentinel.BU.1 —
rail_nameis now operator-overridable so the Trainer plant page can pre-populate it from the registry and let the operator type a custom name for the demo / cold-read scenario. Defaults to the bundled-demo sentinel for backward compatibility with the BTa.8 overlay caller.Parallels
add_broken_rail_plantsinauto_scenario.py(single plant kind, parameterized count, deterministic output).- Return type:
str- Parameters:
prefix (str)
dialect (Dialect)
anchor (datetime)
count (int)
rail_name (str)
- recon_gen.common.l2.demo_etl_gaps.add_phantom_template_gap_rows(*, prefix, dialect, anchor, count=2)[source]
Plant
counttransactions whosetemplate_namedoesn’t resolve in the L2.Triage’s
_detect_unmatched_templatespicks these up + renders anunmatched_templateaccordion section.rail_nameon these rows is a separate phantom so the row contributes to template detection but doesn’t double-count with the rail plant.- Return type:
str- Parameters:
prefix (str)
dialect (Dialect)
anchor (datetime)
count (int)
- recon_gen.common.l2.demo_etl_gaps.add_uncovered_rail_gap_rows(instance, *, prefix, dialect)[source]
Empty all transactions for one L2-declared rail (DELETE).
The Coverage card for Rails then renders that rail as ✗ (declared but no rows). Picks the alphabetically-last rail deterministically — a stable, demo-clear choice that doesn’t depend on row counts. Returns empty string when the L2 declares no rails (vacuous deployment).
Parallels
add_phantom_rail_gap_rowson the Triage side: same demo-shaping intent, opposite DML (INSERT vs DELETE).- Return type:
str- Parameters:
instance (L2Instance)
prefix (str)
dialect (Dialect)
- recon_gen.common.l2.demo_etl_gaps.add_uncovered_template_gap_rows(instance, *, prefix, dialect)[source]
Empty all transactions for one L2-declared template (DELETE).
The Coverage card for Templates then renders that template as ✗. Picks the alphabetically-last template deterministically. Returns empty string when the L2 declares no templates.
- Return type:
str- Parameters:
instance (L2Instance)
prefix (str)
dialect (Dialect)
- recon_gen.common.l2.demo_etl_gaps.emit_demo_etl_gap_sql(instance, *, prefix, dialect, anchor=None)[source]
Compose all demo ETL-feed gap plants into one SQL overlay.
Calls the three per-kind plant functions in order, joins the output, returns a single string of semicolon-terminated INSERTs safe to
execute_scriptagainst any supported dialect.anchorcontrols the wall-clock posting timestamp; defaults todatetime.now()so freshly-planted gaps surface in the default Triage / Probe windows. Pass an explicit datetime in tests for byte-stability.Composition matches
build_default_scenarioincli/_helpers.py(which chainsdefault_scenario_for→densify_scenario→add_broken_rail_plants→boost_inv_fanout_plants): each plant kind is its own function, called in a fixed sequence.- Return type:
str- Parameters:
instance (L2Instance)
prefix (str)
dialect (Dialect)
anchor (datetime | None)