recon_gen.common.handbook.l2ft_exceptions
L2FT Hygiene Exceptions parser — AA.C.4.
Reads src/recon_gen/docs/L2FT_Exceptions.md (the single
source of truth for the six L2FT runtime checks) and returns a typed
mapping of exception kind -> L2FTExceptionSection.
Mirrors common.handbook.invariants (which serves the L1
invariants doc + L1 dashboard panels). Two parser deltas from the L1
flavor:
L2FT exception headings are plain
### N. <Title>— no{{ l2_instance_name }}_<kind>Jinja prefix, because the kinds are check_type labels ("Chain Orphans"/"Unmatched Rail Name"/ etc.) shipped in the L2FT dashboard’s unified-exceptionscheck_typecolumn. Kind keys are slug-cased titles ("chain_orphans"/"unmatched_rail_name"/ …).No SHOULD-blockquote convention. L2FT exceptions are runtime checks against the L2 declaration, not L1 SHOULD-constraints — the leading prose paragraph is the “what this surfaces” description, no blockquote indirection.
The doc carries **Columns:** ... + **What to do:** ... lines
in the same shape as L1_Invariants.md; the parser extracts them
identically.
Functions
Read the bundled |
|
|
Compose the L2 Hygiene Exceptions sheet's bottom panel. |
|
Walk the markdown source and yield one section per ``### N. |
Classes
|
One parsed section from |
- class recon_gen.common.handbook.l2ft_exceptions.L2FTExceptionSection(kind, title, body, columns, what_to_do)[source]
Bases:
objectOne parsed section from
L2FT_Exceptions.md.Same shape as
common.handbook.invariants.InvariantSectionminusshort_statement— L2FT exceptions don’t use blockquote SHOULD-statements (they’re runtime checks against L2, not L1 invariants).- Parameters:
kind (str)
title (str)
body (str)
columns (tuple[str, ...])
what_to_do (str)
- body: str
Prose paragraphs after the heading. The
**What to do:** ...line is extracted intowhat_to_doand dropped frombodyso the dashboard panel can render the remediation in its own styled block. The**Columns:** ...line stays inline.
- columns: tuple[str, ...]
Parsed column names from the
**Columns:** ...line. Empty tuple when the section doesn’t declare columns.
- kind: str
Slug-cased section title —
"chain_orphans"/"unmatched_rail_name"/ etc. Joins toL2FT_EXCEPTION_KIND_TO_SHEETand to the L2FT unified dataset’scheck_typeliterals (title-cased there:"Chain Orphans").
- title: str
Human heading —
"Chain Orphans"/"Unmatched Rail Name". Matches the unified L2 Exceptions dataset’scheck_typeliteral exactly so a future renderer can cross-link a row to its panel description.
- what_to_do: str
Remediation paragraph parsed from the
**What to do:** ...line. One-paragraph guidance: what does a row in this check mean for the integrator, and what should they do about it. Empty string when the section omits the line.
- recon_gen.common.handbook.l2ft_exceptions.load_bundled_l2ft_exceptions()[source]
Read the bundled
L2FT_Exceptions.mdfromrecon_gen.docsand return parsed sections.Single call site for the dashboard-side consumer (AA.C.4 panel wiring) — it doesn’t need to know where the doc lives.
- Return type:
dict[str,L2FTExceptionSection]
- recon_gen.common.handbook.l2ft_exceptions.panel_markdown(sections)[source]
Compose the L2 Hygiene Exceptions sheet’s bottom panel.
L2FT’s six checks all roll up onto one sheet (the unified Hygiene Exceptions sheet), so unlike L1 — where each invariant kind has its own sheet + panel — L2FT gets one panel that lists all six kinds with their remediation guidance inline. Shape mirrors L1’s L1 Exceptions intro panel (AA.C.3.e).
Returns a markdown string suitable for
rich_text.markdown(...).- Return type:
str- Parameters:
sections (dict[str, L2FTExceptionSection])
- recon_gen.common.handbook.l2ft_exceptions.parse_l2ft_exceptions(md_text)[source]
Walk the markdown source and yield one section per
### N. <Title>heading. Returns{kind: L2FTExceptionSection}.- Return type:
dict[str,L2FTExceptionSection]- Parameters:
md_text (str)