"""Metric Dictionary — the semantic layer's module adapter (OM-0c, 2026-07-11). The truth lives in harness/semantic.py + model/*.yml (topics + metrics, one governed definition per metric). This thin adapter exists so the app conventions hold: registry row (validate=True, nav=False — the page is a sidebar sentinel like Feedback) → validate.py auto-runs the semantic layer's independent reconciliation contracts alongside every module's checks. modules→harness is sanctioned HERE (the dictionary IS the platform layer's surface); the reverse lazy import inside semantic.py (order-scope builder) is tracked for the OM-2 lift into core/store. """ import harness.semantic as S def topics(): return S.topics() def metrics(): return S.metrics() def describe(key): return S.describe(key) def metric(key, date_from=None, date_to=None, team_id=None): return S.metric(key, date_from, date_to, team_id) def formula(m): """Human-readable formula for a metric definition (the dictionary's Formula column).""" agg = m.get("agg") if agg == "ratio": return f"{m['numerator']} ÷ {m['denominator']}" if agg == "derived": return m.get("expr", "") if agg == "count": return "count(rows)" if agg == "count_distinct": return f"distinct {m['field']}" return f"Σ {m.get('field', '?')}" def run_reconciliation(): """Run every declared independent contract live against Odoo (YTD, all-BU + per-BU).""" return S.validate() def validate(pre=None): """validate.py convention: the dictionary's checks ARE the semantic layer's contracts.""" return S.validate()