recon_gen.common.spine.training

Training/docs scenarios that self-validate.

The audit’s “training scenarios become declarative (and can’t lie)” payoff (docs/audits/date_range_model_audit.md): today, docs prose describes what a demo scenario shows, but the prose ⟷ data link is developer-memory. If the seed changes shape and the planted drift moves off the documented day, the docs silently lie. AS.7 closes that gap.

TrainingScenario is the typed object docs can import + the test suite can validate:

  • name / description — author-facing prose; renderers (mkdocs, walkthroughs) read these.

  • emitters — the ViolationGenerator / LedgerSimulation rows the scenario plants.

  • invariants — the detectors the scenario claims will fire.

  • intended — the specific `Violation`s docs say the analyst will see. The claim that has to hold.

self_validate(conn) emits the scenario, refreshes matviews, runs detect across each invariant, and asserts intended ⊆ detected. If the docs claim violations the data doesn’t produce, the test fires loud — the documented scenario can’t silently fail to demonstrate.

What this REPLACES (eventually): hand-written prose in docs/handbook/ that lives parallel to the seed; the docs walk ASSUMED to match the data. With TrainingScenario, the docs mkdocs-macros can render scenario.description next to a mkdocs-side scenario.intended summary, and a CI test runs scenario.self_validate(conn) against the live seed every build.

AT.6 reuses this mechanism for L2’s anomaly + money_trail scenarios (parallel structure, different surface).

Functions

validate_all(scenarios, conn_factory)

Validate a batch of scenarios, each against its OWN fresh DB.

Classes

TrainingScenario(name, description, ...[, ...])

A docs-renderable, self-validating scenario.

class recon_gen.common.spine.training.TrainingScenario(name, description, emitters, invariants, intended=<factory>, prefix='spec_example', instance_path=None)[source]

Bases: object

A docs-renderable, self-validating scenario.

Authors construct one of these per documented case; docs read name + description (free prose); the test suite calls self_validate(conn) to make sure the data the scenario emits actually produces the violations the prose claims.

intended is the load-bearing field — it’s the claim. A Violation in this set says: “the analyst will see this row in the matview after the scenario applies.” Implementation churn (different leg shapes, account IDs) is fine as long as the intended Violations still fire; that’s the same flexibility AS.5’s semantic_lock gives.

Parameters:
  • name (str)

  • description (str)

  • emitters (tuple[_Emitter, ...])

  • invariants (tuple[Invariant, ...])

  • intended (frozenset[Violation])

  • prefix (str)

  • instance_path (Path | None)

description: str
emitters: tuple[_Emitter, ...]
instance_path: Path | None = None
intended: frozenset[Violation]
invariants: tuple[Invariant, ...]
name: str
prefix: str = 'spec_example'
self_validate(conn)[source]

Apply the scenario; assert every intended Violation fires.

Raises AssertionError with the missing-Violation diff if the docs claim violations the data doesn’t produce. intended detected is the contract — extra detected Violations (e.g., the secondary ledger_drift edge from a drift plant) are fine; missing claimed Violations are the failure mode.

Return type:

None

Parameters:

conn (SyncConnection)

recon_gen.common.spine.training.validate_all(scenarios, conn_factory)[source]

Validate a batch of scenarios, each against its OWN fresh DB.

conn_factory is a no-arg callable returning a fresh sqlite3. Connection with the schema already applied (the in-process harness pattern). Each scenario gets its own connection so prior emissions don’t bleed into the next test’s detect set.

Useful in a docs-build hook: collect every registered TrainingScenario and validate them all in one shot before rendering the prose. A failure halts the build with the missing- violation diff.

Return type:

None

Parameters:
  • scenarios (Iterable[TrainingScenario])

  • conn_factory (Callable[[], SyncConnection])