hand_roll_census — reinvented metrics and the canonical function that already does it
Concept
The standing lookup table for the measurement contract’s first hard rule: never re-derive a metric. Each row is a signal-math idiom that was, at some point, hand-rolled in a one-off script, paired with the canonical function in
analysis/data_analyzer.pyoranalysis/statistics.pythat already computes it. Before writingnp.mean/np.corrcoef/ a norm-of-a-diff / a percentile against a log, look here first. The closing section is the closed ledger: idioms that stay hand-rolled on purpose, so they are never re-filed as backlog.
What this spans
analysis/data_analyzer.py([[data_analyzer]]) — the reduction path and the data idioms: windows, reductions, episode runs, divergence, per-step jumps, spatial projection.analysis/statistics.py([[statistics]]) — the inference layer: correlation, regression, effect size, dispersion, event studies.- Thesis: a second definition of a number is a wrong number. Every idiom below has exactly one home; the census is the map from the thing you were about to write to the thing that already exists.
Constituent pages
[[data_analyzer]]— the reduction path + data idioms (the home the measurement contract calls “the palace”).[[statistics]]— the two-signal inference layer, split out ofdata_analyzeron 2026-06-18.[[signal_measurement]]— the retired facade doorway (see the frame-shift footgun below).
Mechanism (where it lives in code)
Both homes are plain modules; import the function directly.
from analysis.data_analyzer import measure, measure_many, series, as_log_view # the reduction path
from analysis.statistics import pearson_r, cliffs_delta, episode_contrast # the inference layerThe census — idiom → canonical function
Keyed by idiom, not by the script that reinvented it: the scripts are purged weekly, the idioms recur forever.
| Hand-rolled idiom | Canonical function | Home |
|---|---|---|
np.sqrt(np.mean(x**2)) (RMS of a metric) | measure(source, key, "rms") | data_analyzer |
np.percentile(x, 99) on a metric | measure(source, key, "p99") | data_analyzer |
np.percentile(x, q) at an arbitrary q | percentile(values, q) | data_analyzer |
np.nanmax(x) / np.nanmedian(x) on a metric | measure(source, key, "max" | "median") | data_analyzer |
(sj[op] < FLOOR).mean() (fraction below a floor) | measure(..., "frac_below") / near_singular_fraction(values, threshold) | data_analyzer / statistics |
steady.max() - steady.min() (back-half peak-to-peak) | back_half_pkpk(source, key) or measure(..., "ptp") | data_analyzer |
norm(np.diff(x, axis=0)) (per-step jump) | diff_norm(values, prepend=True) | data_analyzer |
np.linalg.norm(a - b, axis=1) between two runs | divergence_array(view_a, view_b, key) | data_analyzer |
d/dt ln D growth rate (chaos vs ill-conditioning) | local_growth_rate(t, D, smooth=...) | data_analyzer |
| max-abs-diff of two pinned payloads | payload_diff(ref, cur) | data_analyzer |
np.diff(cov) >= -ATOL (monotonicity gate) | monotonicity_drops(series, atol) | data_analyzer |
hand-rolled _runs / _merge over a boolean mask | contiguous_runs / merge_runs / drop_short_runs / longest_run_length | data_analyzer |
| threshold crossing / first crossing | threshold_crossings / first_crossing | data_analyzer |
| floor-diff progress stall detection | quantized_stall_mask(progress) | data_analyzer |
int(np.nanargmin(s)) / (len(s)-1) (when the extreme occurs) | argextreme_fraction(values, which="min") | data_analyzer |
| angle between paired rows of two arrays | rows_angle(a, b) | data_analyzer |
| versine → degrees for a print | as_pointing_deg(versine) — DISPLAY ONLY | data_analyzer |
np.corrcoef(a, b)[0,1] | pearson_r(a, b) | statistics |
scipy.stats.spearmanr | spearman_rho(a, b) | statistics |
| OLS slope/intercept fit | linfit(x, y) | statistics |
| cross-correlation peak / lag | xcorr_peak_lag(a, b, dt) | statistics |
| rank-based effect size on skewed data | cliffs_delta(a, b) | statistics |
| ”signal during episode vs healthy” contrast | episode_contrast(signal, mask) | statistics |
1.96 * std(ddof=1) / sqrt(n) (CI95) | ci95(x) | statistics |
| across-seed spread / dispersion band | ensemble_dispersion(values) · rel_spread(x) | statistics |
(B - A) / A percent change between two runs | rel_delta(new, base) | statistics |
| angle wrapping / circular mean / circular std | wrap · circ_mean · circ_std | statistics |
| seeded event-study control pool | matched_control_pool · event_effect_size | statistics |
Every function above was verified to resolve in its named module on 2026-07-11.
Evidence
- The narrative these rows were distilled from (which script reinvented what, and the byte-identity proofs when each was retired onto the canonical function):
Inspection/validation/INSIGHTS.md§ Hand-roll census. - The governing contract that sends you here:
.claude/skills/sim-runner/references/measurement.md(hard rule 1 — measure throughanalysis/data_analyzer.py, never re-derive). - Parity of the reduction path against the pipeline sweep (1e-12):
Inspection/validation/tests/test_signal_measurement.py.
Footguns
The facade is retired — its function names are dead, and the old census still prints them
validation/signal_measurement.pywas removed 2026-07-01. The census as written invalidation/INSIGHTS.mdnames the facade’s functions, and several of those names exist nowhere in the tree now. Translate before you reach for one:
dead facade name live function home divergence_seriesdivergence_arraydata_analyzerpercentile_ofpercentiledata_analyzertime_to_extremeargextreme_fractiondata_analyzerstep_norm(keyed)diff_norm(raw array)data_analyzercorrelatepearson_r/spearman_rhostatisticsregresslinfitstatisticslead_lagxcorr_peak_lagstatisticseffect_sizecliffs_deltastatistics
measure/series/back_half_pkpk/episode_contrastkept their names — only their import path moved.
A "no facade equivalent" row is not an invitation to hand-roll a metric
Several census rows correctly read no equivalent — but that verdict applies to plant-level and cross-variant math (below), never to a reduction of a logged signal. If the quantity comes out of a log, it goes through
measure/series.
Intentionally NOT promoted — the closed ledger
These stay hand-rolled on purpose: they are not generic signal math, so they live with their own domain code rather than bloating the shared library. Do not re-file them as backlog.
- Plant / robot-level linear algebra — SVD of
J/Γ/J_plus(singular spectrum, manipulability), and the Pinocchio kinetic-energy / momentum-drift conservation checks. These operate on live matrices fromutils/robot.py, not on logged scalars. (s_min_G/kappa_Jare already logged as catalog metrics for the post-hoc view — use those when you want the logged quantity.) - Mesh coverage / set-difference — area-weighted triangle marking couples to mesh geometry + finder state.
- Schedule / fragility oracles + config-threshold sizing — derate-onset, neighbourhood robustness, worst-case joint-rate propagation: these couple to the
controllerconfig, not to a log. - Cross-variant scalar comparisons — Richardson
d1/d2, the cross-dtcommon-grid RMS gap, and A/B ratios between two runs’ scalars (pe_p99,smin_min). These compare two runs’ scalars, not a per-step reduction of one run.ensemble_dispersion/rel_deltacover the dispersion and percent-change shapes; the rest is bespoke by design. - Raw joint-state percentiles —
th3median/p5/p95 andsin(th3)regressors: raw state columns with no catalog spec, so there is no keyed path (by design — the reduction path is keyed on catalog metrics). - Deliberate keepers, not duplication — a NaN-propagating percentile lambda (the canonical
percentilestrips NaN, so the two are not interchangeable); an offline SVD fallback for old logs that lack a livekappa_J; and the test reference values (np.corrcoef,scipy.stats.spearmanr) that exist precisely to validate the promotedpearson_r/spearman_rhoagainst the originals — retiring those would delete the cross-check.
Related
[[data_analyzer]] · [[statistics]] · [[signal_measurement]] · [[metric_catalog]] · [[metrics]] · [[orchestrator]] · terminology