recon_gen.common.spine.xor_group_violation

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

AX.2 promotion of the AB.3.5 / AB.3.5b plants. The matview <prefix>_xor_group_violation walks every Transfer instance of every template that declares leg_rail_xor_groups, for each (Transfer, group) pair LEFT JOINs _current_transactions against the group’s member rails, and surfaces rows where COUNT <> 1:

  • firing_count = 0 → “missed firing”: the Transfer should have fired exactly one member of the XOR group; it fired none.

  • firing_count ≥ 2 → “overlap”: the Transfer fired ≥2 members of the XOR group; SPEC C1 says they’re mutually exclusive.

Identity tuple: (transfer_id, template_name, xor_group_index).

Two generators because the emit shape is genuinely different per failure mode (missed: 1 witness leg outside the group; overlap: 2 member legs both inside the group). 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. Both generators do NOT emit chain-completion rows — extras the SOLO emission might trip on other matviews (e.g., a template that’s also a multi_xor chain parent could trip multi_xor_violation from the same plant) are tolerated per AS.5’s “intended ⊆ detected” contract. Composition with the multi_xor generator clears those extras at the wiring site.

The matview uses concat_agg(“tx.rail_name”, “,”, dialect) for the fired_rails column; AX.0 confirmed SQLite’s built-in GROUP_CONCAT routes cleanly through common/sql/dialect.py’s helper.

Classes

XorGroupMissedFiringGenerator(template_name, ...)

Plant a Transfer tagged with template_name whose target XOR group fires NO members.

XorGroupOverlapGenerator(template_name, ...)

Plant a Transfer tagged with template_name whose target XOR group fires TWO distinct members.

XorGroupViolationInvariant([prefix])

Detector for the AB.3.3 matview.

class recon_gen.common.spine.xor_group_violation.XorGroupMissedFiringGenerator(template_name, xor_group_index, witness_rail_name, anchor_day, prefix='spec_example', account_id_override=None)[source]

Bases: object

Plant a Transfer tagged with template_name whose target XOR group fires NO members.

Emits ONE leg row carrying the template_name + a witness rail_name that is a leg_rail of the template but NOT in the target XOR group. The matview’s template_transfers CTE picks up the Transfer (template_name matches an XOR-grouped template); the LEFT JOIN against (transfer_id, template, member_rail) for the target group finds zero rows; firing_count = 0; the HAVING <> 1 gate surfaces the row with fired_rails = ‘’.

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:
  • template_name (str)

  • xor_group_index (int)

  • witness_rail_name (str)

  • anchor_day (date)

  • 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
property claimed_accounts: frozenset[str]
emit(conn, *, scenario_id=None)[source]
Return type:

None

Parameters:
  • conn (SyncConnection)

  • scenario_id (str | None)

property intended: RuleViolation
prefix: str = 'spec_example'
template_name: str
property transfer_id: str
witness_rail_name: str
xor_group_index: int
class recon_gen.common.spine.xor_group_violation.XorGroupOverlapGenerator(template_name, xor_group_index, variant_a_rail_name, variant_b_rail_name, anchor_day, prefix='spec_example', account_id_override=None)[source]

Bases: object

Plant a Transfer tagged with template_name whose target XOR group fires TWO distinct members.

Emits TWO leg rows sharing one transfer_id + template_name, each carrying a different member rail_name from the target XOR group. The matview’s LEFT JOIN finds two member-rail firings for (transfer_id, template, target_group)COUNT = 2HAVING <> 1 → row surfaces with fired_rails = ‘<a>,<b>’.

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:
  • template_name (str)

  • xor_group_index (int)

  • variant_a_rail_name (str)

  • variant_b_rail_name (str)

  • anchor_day (date)

  • 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
property claimed_accounts: frozenset[str]
emit(conn, *, scenario_id=None)[source]
Return type:

None

Parameters:
  • conn (SyncConnection)

  • scenario_id (str | None)

property intended: RuleViolation
prefix: str = 'spec_example'
template_name: str
property transfer_id: str
variant_a_rail_name: str
variant_b_rail_name: str
xor_group_index: int
class recon_gen.common.spine.xor_group_violation.XorGroupViolationInvariant(prefix='spec_example')[source]

Bases: object

Detector for the AB.3.3 matview.

Identity tuple: (transfer_id, template_name, xor_group_index). The matview’s other columns (firing_count, fired_rails, business_day) are diagnostic — they distinguish missed (0) from overlap (≥2) but the identity-level “did this XOR group misfire” is what the spine carries.

Parameters:

prefix (str)

detect(conn)[source]
Return type:

set[Violation]

Parameters:

conn (SyncConnection)

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

Pick an XOR-grouped template with ≥1 leg_rail outside the target group (the witness rail). Returns a generator that plants ONE Transfer firing the witness — firing_count=0 for the target group, matview surfaces a row.

Raises ValueError if no template has both an XOR group AND a witness leg_rail outside it (the AB.3.5 picker’s input requirement).

Return type:

XorGroupMissedFiringGenerator

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

Pick an XOR group with ≥2 members (validator C1d enforces the ≥2 condition at load time). Returns a generator that plants ONE Transfer firing TWO members of the same XOR group — firing_count=2, matview surfaces a row.

Raises ValueError if no template declares any leg_rail_xor_groups.

Return type:

XorGroupOverlapGenerator

Parameters: