recon_gen.common.spine.two_template_chain

Two-template chain (healthy) family — ViolationGenerator only.

AY.2.b promotion of common/l2/seed.py::TwoTemplateChainPlant (AB.2.6 healthy plant). This is a SEED-COLOR generator: it plants a healthy 2-template chain firing (one parent leg + N child template legs all sharing one child Transfer + agreeing on transfer_parent_id) so the L1 dashboard’s PostedRequirements panel + the audit PDF have a clearly-labeled healthy two-template chain row to display, separate from the probabilistic baseline.

Crucially this plant produces NO matview row — chain_parent_disagreement reads COUNT(DISTINCT transfer_parent_id) > 1 grouped by (transfer_id, template_name); this generator emits N child legs all carrying the SAME parent_transfer_id, so the count is 1 and the matview branch never fires.

Per the AY.2.b evidence-currency layering:

  • intended returns a CoverageObservation (NOT RuleViolation, NOT None). The seed claims “I planted a healthy two-template chain firing”; the audit-PDF “PostedRequirements” coverage section reads the row(s) directly. A coverage detector (deferred) could eventually walk <prefix>_transactions WHERE transfer_id=? AND template_name=? GROUP BY transfer_id HAVING COUNT(DISTINCT transfer_parent_id) = 1 and assert ≥1 healthy chain firing per chain-child template; for now intended is presence-only evidence.

No matching Invariant (the AY.0 design’s “audit-fixture without detector” shape). Registers with empty edges in INVARIANT_GENERATOR_EDGES.

Single-edge property (matches the other 4 L2-shape spine generators): transfers-only → no daily_balances rows → no drift trip.

Classes

TwoTemplateChainFactory([prefix])

Smart constructor namespace for TwoTemplateChainGenerator.

TwoTemplateChainGenerator(chain_parent_name, ...)

Emit one parent leg + N child template legs (one per child_leg_rails entry) all sharing one child transfer_id and all carrying the same parent_transfer_id — the healthy 2-template chain shape.

class recon_gen.common.spine.two_template_chain.TwoTemplateChainFactory(prefix='spec_example')[source]

Bases: object

Smart constructor namespace for TwoTemplateChainGenerator.

AY.2.b deliberately omits an Invariant here — there’s no matview to detect this plant’s evidence (the plant is non-violating). The factory mirrors the Invariant.scenario_for(…) pattern from the rest of the spine for surface parity, so seed-color generators feel like the violation-detecting ones at the call site.

Parameters:

prefix (str)

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

Pick any chain whose singleton child is a TransferTemplate (the AB.2.6 picker) and build a generator that plants a healthy 2-template chain firing.

Parent can resolve to either a Rail (rail-parent) or a TransferTemplate (template-parent, AG.3 Gap A); the generator carries enough fields to emit the parent row correctly in both cases.

Raises ValueError when the L2 has no eligible chain (singleton-child + parent ∈ rails ∪ templates + child ∈ templates with ≥1 leg_rail).

Return type:

TwoTemplateChainGenerator

Parameters:
class recon_gen.common.spine.two_template_chain.TwoTemplateChainGenerator(chain_parent_name, parent_rail_name, parent_template_name, child_template_name, child_leg_rails, anchor_day, prefix='spec_example', account_id_override=None)[source]

Bases: object

Emit one parent leg + N child template legs (one per child_leg_rails entry) all sharing one child transfer_id and all carrying the same parent_transfer_id — the healthy 2-template chain shape.

Account fields are synthetic + deterministic (matches the ChainParentDisagreementGenerator pattern; the matview ignores account columns when grouping by transfer_id + template_name).

intended returns a CoverageObservation keyed on (transfer_id, chain_parent_name, child_template_name, child_leg_count) — the presence-claim tuple a coverage detector could round-trip against.

Parameters:
  • chain_parent_name (str)

  • parent_rail_name (str)

  • parent_template_name (str | None)

  • child_template_name (str)

  • child_leg_rails (tuple[str, ...])

  • anchor_day (date)

  • prefix (str)

  • account_id_override (str | None)

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

None

Parameters:
  • conn (SyncConnection)

  • scenario_id (str | None)

property intended: CoverageObservation

a healthy 2-template chain firing landed with N child legs all agreeing on parent_transfer_id. Identity carries the natural-key tuple a coverage detector would round-trip against if/when one lands.

Type:

Presence evidence

parent_rail_name: str
parent_template_name: str | None
property parent_transfer_id: str
prefix: str = 'spec_example'