Static governance scan (no run required)

Conformare normally captures governance at runtime – a describe() / risk() region has to execute to be recorded. That is ideal for the live report (it sees the real lineage and data), but it means a context in a branch that didn’t run, or a module nobody imported, is invisible. The static scan reads the source instead: it parses your .py files and extracts every declared context and risk without executing anything.

scan = cf.scan_governance("src/")            # a file, a directory, or a list
# {'files_scanned': 12, 'contexts': [...], 'risks': [...], 'errors': [...]}

cf.scan_governance_report("src/", "governance.html")   # a self-contained HTML report

Each context and risk carries its file and line, so you can build a governance report for a whole repository that has never been run.

What it matches

It recognises only the governance forms, so ordinary calls are never mistaken for it:

  • with cf.describe(...) / with cf.risk(...) blocks (including a combined with cf.describe(...), cf.risk(...):),
  • @cf.describe(...) / @cf.risk(...) decorators on functions,
  • a risks= argument on a describe(...).

Because it only looks at with-items, decorators and risks=, a method call like df.describe() is never picked up as governance. Only literal arguments are read – a static scan can’t evaluate a computed value – so keep ids, severities and owners as literals if you want them discoverable this way.

Runtime vs static – two views, one model

  Runtime capture (to_html) Static scan (scan_governance)
Needs the code to run yes no
Sees actual lineage / profiles / data yes no (declarations only)
Sees branches/modules that didn’t run no yes
Sees computed (non-literal) governance yes no (literals only)

They are complementary: the runtime report is the record of what a run did; the static scan is the inventory of what the code declares, across everything – which is what you want for repo -wide discovery and for gating in CI.

Gating in CI

Because the scan needs nothing to run, it fits a pull-request check. For example, fail the build if any declared risk is missing a severity, or any context is unowned:

import sys, conformare as cf

scan = cf.scan_governance("src/")
problems = [r for r in scan["risks"] if not r["severity"]]
problems += [c for c in scan["contexts"] if not c["owner"]]
if problems:
    print("governance gaps:", problems)
    sys.exit(1)

Drop that in a GitHub Action step and the convention becomes enforced, the missing enforcement gap versus declarative tools, without ever running the pipeline.


This site uses Just the Docs, a documentation theme for Jekyll.