recon_gen.common.spine.multi_xor_violation

Multi-XOR-violation family — Invariant + 2 `ViolationGenerator`s.

AX.4 promotion of the AB.6.6 plants. The matview <prefix>_multi_xor_violation walks every Transfer firing of any chain that declares ≥2 non-fan_in children (multi-XOR-child chains: the parent fires once; the chain declares N XOR-sibling children; exactly ONE child should fire). It LEFT JOINs _current_transactions against the declared XOR-sibling children (matched on transfer_parent_id = parent.transfer_id AND rail_name OR template_name = child.name) and surfaces rows where COUNT(matched_child) <> 1:

  • missed: count = 0 → the parent fired but no XOR-sibling child did.

  • overlap: count ≥ 2 → the parent fired and ≥2 XOR-sibling children both fired.

Identity tuple: (parent_transfer_id, disagreement_kind).

Two generators (analogous to AX.2 xor_group) because the emit shapes differ: missed emits 1 parent only; overlap emits 1 parent + 2 child firings. Single invariant; two generators register as separate edges in INVARIANT_GENERATOR_EDGES.

Single-edge property: transfers-only emit (no daily_balances rows) → no drift trip. Note that overlap may trip fan_in_disagreement as a cross-class side effect if the chain has fan_in entries (the AB.5 coupling) — extras tolerated per AS.5.

The matview uses concat_agg(“fcd.matched_child_name”, “,”, dialect) for the fired_children column; AX.0 confirmed SQLite’s built-in GROUP_CONCAT routes cleanly.

Classes

MultiXorMissedGenerator(chain_parent_name, ...)

Plant a parent Transfer with NO declared XOR-sibling children firing.

MultiXorOverlapGenerator(chain_parent_name, ...)

Plant a parent Transfer + TWO child firings (both XOR-siblings; both linked to the parent via transfer_parent_id).

MultiXorViolationInvariant([prefix])

Detector for the AB.6.5 matview.

class recon_gen.common.spine.multi_xor_violation.MultiXorMissedGenerator(chain_parent_name, anchor_day, instance=None, prefix='spec_example', account_id_override=None)[source]

Bases: object

Plant a parent Transfer with NO declared XOR-sibling children firing. Matview’s child_count = 0 → ‘missed’ row.

Emits ONE leg row for the parent: rail_name stamps the chain.parent (or the template’s first leg_rail when the parent is a Template); template_name stamps the parent template name when applicable.

AY.4.c.2 — account_id_override allows the plant adapter (AY.4.c.3) to thread OLD plant account_ids through, preventing PK collisions when N plants of the same shape compose.

Parameters:
  • chain_parent_name (str)

  • anchor_day (date)

  • instance (L2Instance | None)

  • prefix (str)

  • account_id_override (str | None)

property account_id: str

account_id_override wins when set (AY.4.c.2).

account_id_override: str | None = None
anchor_day: date
chain_parent_name: str
property claimed_accounts: frozenset[str]
emit(conn, *, scenario_id=None)[source]
Return type:

None

Parameters:
  • conn (SyncConnection)

  • scenario_id (str | None)

instance: L2Instance | None = None
property intended: RuleViolation
property parent_transfer_id: str
prefix: str = 'spec_example'
class recon_gen.common.spine.multi_xor_violation.MultiXorOverlapGenerator(chain_parent_name, variant_a_child_name, variant_b_child_name, anchor_day, instance=None, prefix='spec_example', account_id_override=None)[source]

Bases: object

Plant a parent Transfer + TWO child firings (both XOR-siblings; both linked to the parent via transfer_parent_id). Matview’s child_count = 2 → ‘overlap’ row.

Emits 3 leg rows: 1 parent + 2 children. Each child row’s rail_name/template_name matches the chain’s declared XOR-sibling child name (rail vs template kind resolved at emit time).

AY.4.c.2 — account_id_override allows the plant adapter (AY.4.c.3) to thread OLD plant account_ids through, preventing PK collisions when N plants of the same shape compose.

Parameters:
  • chain_parent_name (str)

  • variant_a_child_name (str)

  • variant_b_child_name (str)

  • anchor_day (date)

  • instance (L2Instance | None)

  • prefix (str)

  • account_id_override (str | None)

property account_id: str

account_id_override wins when set (AY.4.c.2).

account_id_override: str | None = None
anchor_day: date
chain_parent_name: str
property claimed_accounts: frozenset[str]
emit(conn, *, scenario_id=None)[source]
Return type:

None

Parameters:
  • conn (SyncConnection)

  • scenario_id (str | None)

instance: L2Instance | None = None
property intended: RuleViolation
property parent_transfer_id: str
prefix: str = 'spec_example'
variant_a_child_name: str
variant_b_child_name: str
class recon_gen.common.spine.multi_xor_violation.MultiXorViolationInvariant(prefix='spec_example')[source]

Bases: object

Detector for the AB.6.5 matview.

Identity tuple: (parent_transfer_id, disagreement_kind). The matview’s other columns (parent_rail_or_template_name, child_count, fired_children, business_day) are diagnostic.

Parameters:

prefix (str)

detect(conn)[source]
Return type:

set[Violation]

Parameters:

conn (SyncConnection)

name: ClassVar[str] = 'multi_xor_violation'
prefix: str = 'spec_example'
scenario_for_missed(*, anchor_day=datetime.date(2030, 1, 1), instance=None)[source]

Pick a chain with ≥2 non-fan_in children + return a generator that plants ONE parent firing with NO child firings — matview reads count=0, surfaces ‘missed’ row.

Return type:

MultiXorMissedGenerator

Parameters:
scenario_for_overlap(*, anchor_day=datetime.date(2030, 1, 1), instance=None)[source]

Pick a chain with ≥2 non-fan_in children + return a generator that plants ONE parent firing + TWO child firings (both XOR-siblings; both linked to the parent via transfer_parent_id) — matview reads count=2, surfaces ‘overlap’ row.

Return type:

MultiXorOverlapGenerator

Parameters: