recon_gen.common.l2.trainer
plants_per_node() — derive per-topology-node planted-exception counts
from an L2 scenario object (X.4.c.6).
The trainer-mode overlay shows the trainer “this role has 2 drift plants
and 1 overdraft” without involving the demo DB — every plant primitive
in common/l2/seed.py carries its host (account_id / rail_name
/ template_name) directly, so a pure walk of the
ScenarioPlant aggregates into a per-node count map.
Symmetric in shape to coverage.py — the chrome chrome consumes both
through the same data-presence / data-trainer-kinds SVG attr
pattern. They differ only in the data-source: coverage hits the DB,
trainer reads the in-memory scenario.
Severability: pure Python, no DB import, no async. The Studio route that wraps this calls it at request time and serializes to JSON.
Functions
|
Count planted plants per topology node. |
Classes
|
Per-topology-node planted-plant counts derived from a ScenarioPlant. |
- class recon_gen.common.l2.trainer.TrainerMap(by_node_id)[source]
Bases:
objectPer-topology-node planted-plant counts derived from a ScenarioPlant.
by_node_idkeys are the same topology IDscoverage.pyuses (role__X/rail__X/tmpl__X); values are{plant_kind: count}mappings with one entry per plant kind that landed on that node. Nodes with zero plants are absent from the map (the chrome’s “no badge” default is the empty case).- Parameters:
by_node_id (Mapping[str, Mapping[Literal['drift', 'overdraft', 'limit_breach', 'stuck_pending', 'stuck_unbundled', 'supersession', 'failed', 'transfer_template', 'inv_fanout', 'inbound_cap_breach', 'two_template_chain', 'chain_parent_disagreement', 'xor_variant_missed_firing', 'xor_variant_overlap', 'fan_in_chain', 'fan_in_chain_missing_parent', 'fan_in_chain_extra_parent', 'multi_xor_missed', 'multi_xor_overlap'], int]])
- by_node_id: Mapping[str, Mapping[Literal['drift', 'overdraft', 'limit_breach', 'stuck_pending', 'stuck_unbundled', 'supersession', 'failed', 'transfer_template', 'inv_fanout', 'inbound_cap_breach', 'two_template_chain', 'chain_parent_disagreement', 'xor_variant_missed_firing', 'xor_variant_overlap', 'fan_in_chain', 'fan_in_chain_missing_parent', 'fan_in_chain_extra_parent', 'multi_xor_missed', 'multi_xor_overlap'], int]]
- recon_gen.common.l2.trainer.plants_per_node(instance, scenario=None)[source]
Count planted plants per topology node.
When
scenariois None, derives the auto-scenario viadefault_scenario_for(instance)— same default the demo apply pipeline uses so the trainer surface previews the same plants the deployed DB will carry.Each plant kind contributes:
drift: role(
account_id) + rail(rail_name)overdraft: role(
account_id)limit_breach: role(
account_id) + rail(rail_name)stuck_pending: rail(
rail_name)stuck_unbundled: rail(
rail_name)supersession: rail(
rail_name)failed: rail(
rail_name)transfer_template: template(
template_name)inv_fanout: rail(
rail_name) (recipient role isn’t a clean “host” — the recipient is one of N senders’ targets, not a plant-singularity owner)
RailFiringPlantis excluded — it’s broad-mode bulk firings, not a SHOULD-violation per the SPEC, so it shouldn’t show up as a “planted exception”.A plant kind that lands on multiple nodes (e.g. drift on both a role and a rail) increments the count on each node — the trainer chrome shows badges per node, not per plant.
- Return type:
- Parameters:
instance (L2Instance)
scenario (ScenarioPlant | None)