File size: 1,649 Bytes
c14ceee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
"""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()