metric_alignment — metric-catalog verifier + payload alignment smoke
Purpose
Two-pass guard for the metric pipeline. Pass 1 verifies
metrics.yamlis structurally sound
(no null placeholders, parseable reductions/deltas, every leaf has avariable) and that the
catalog actually loads with no duplicate variables. Pass 2 (the alignment smoke) checks that a
live payload’s observed variable leaves match what the catalog requests. Also hosts deprecated
legacy fabricated-payload smokes.
Role in the system
- Verifies
metrics.yaml(the variable catalog) — what is measured — built by the
MetricSpecLoaderin pre_run_loader; judgment semantics live inscoreboard.yaml, not here. - Pulls its catalog/spec/reduction symbols from data_analyzer (
Reductions,Deltas,DataSummary)
and metric_catalog (catalog_by_key,catalog_specs) — all packed into one namespace by
metric_spec_loader_tools. - Run as a script (
python -m analysis.metric_alignment) it prints both verifier reports and exits
non-zero on failure — the cheap, simulation-free catalog gate referenced in.claude/rules/ANALYSIS.md. - The alignment smoke consumes pipeline payloads (a
StepLog/ guidance log); not called by
orchestrator in the live loop — it is a boundary smoke, not a pipeline stage.
Inputs / Outputs
- In (verifiers):
metrics.yaml(or an in-memory metric namespace / selected-key list viametrics=). - In (smoke): one or more live payloads (nested records with named-series leaves).
- Out:
Packagereports withokplus structured findings — YAMLissues(level/check/path/message),
pipelineduplicates, or alignment bucketsmissing/ambiguous/path_mismatches/
length_mismatches. Each report has a matchingprint_*for the console.
Key functions
metric_spec_loader_tools— pack catalog/spec/reduction symbols into one namespace —analysis/metric_alignment.py:36metric_yaml_node_issues— recursive structural verifier over the metric tree —analysis/metric_alignment.py:175metric_yaml_verification_report— Pass 1: parse + structure + loader-build —analysis/metric_alignment.py:202metric_pipeline_verification_report— catalog loads, reduction items build, no duplicate variables —analysis/metric_alignment.py:283duplicate_metric_variables— variables bound to more than one catalog path —analysis/metric_alignment.py:271metric_payload_paths— flatten a payload into{dotted leaf: sample count}—analysis/metric_alignment.py:381metric_alignment_smoke— Pass 2: bucket payload-vs-catalog mismatches —analysis/metric_alignment.py:448
Footguns
The
# noqa: F401guards are load-bearing — never strip them
metric_spec_loader_toolsimports symbols only to hand their string names to
Package.pack(scope=locals()), which resolves them by name. Linters see them as unused; a Ruff pass
once silently deleted them (commitde0b788) and broke the verifier with no immediate error.
(analysis/INSIGHTS.md[footgun])
FALLBACK is advisory; only MISSING / AMBIGUOUS / LENGTH fail the smoke
The smoke buckets are MISSING (variable absent), AMBIGUOUS (name found but catalog path absent among
multiple candidates), FALLBACK (name found, catalog path unmatched — one candidate), LENGTH
(sample count ≠ expected). FALLBACK does not setok=False. (analysis/INSIGHTS.md[config])
The five legacy smokes are deprecated fabricators
guidance_metric_alignment_smoke,empty_controller_diagnostics,empty_guidance_diagnostics,
empty_ee_controller_step_log,ee_controller_metric_alignment_smokepredate the YAML-driven
pipeline; each emits aDeprecationWarningviawarn_legacy_smoke. Verify against real payloads
withmetric_alignment_smoke+metric_yaml_verification_reportinstead. Open question:
empty_ee_controller_step_loghand-builds a zero-filledStepLogand should call empty-path
constructors. (analysis/INSIGHTS.md[history] / [footgun])
Pseudocode
# Pass 1 — metrics.yaml structure + loader
load_spec(metrics.yaml) # parse_ok / parse_error
walk metric tree: # metric_yaml_node_issues, recursive
null non-metadata child -> ERROR missing_fields
reductions not a parseable list -> ERROR / WARN
nested delta missing method/etc -> WARN / ERROR
leaf w/o children & no variable -> ERROR missing_fields (default* exempt)
MetricSpecLoader(...).load_metric_catalog() # loader_ok
ok = parse_ok and loader_ok and no ERROR issues
# Pass 2 — payload vs catalog (the alignment smoke)
observed = flatten payloads -> {path: samples}, indexed by trailing variable name
for spec in catalog.specs:
no provided counts -> MISSING
catalog path absent, >1 cand -> AMBIGUOUS
catalog path absent, 1 cand -> FALLBACK (advisory)
samples != expected -> LENGTH
ok = no MISSING and no AMBIGUOUS and no LENGTH
Related
pre_run_loader · metric_catalog · data_analyzer · orchestrator · ee_guidance · terminology