pre_run_loader — the config gateway
Purpose
The single gateway through which every sim run and analysis job gets its configuration.
Merges a run-spec YAML over the defaults, applies ordered config overrides into thecfg
namespace, and resolves themetrics.yaml(catalog) andscoreboard.yaml(judgment) specs.
Role in the system
RunSpecLoader(stem).prepare()is called by runner / orchestrator at the head of the
pipeline (pre_run_loader → runner → logger → NPZ → data_analyzer → plotter/star_reporter).MetricSpecLoaderis consumed by metric_catalog (and verified bymetric_alignment) — the
what is measured catalog feeding data_analyzer.ScoreboardSpecLoaderis the parser for the how it is judged layer; the completeness contract in
logger (scoreboard_metric_coverage) and the consolerun_scoreboard.pyread these specs.- Reads YAML via
utils.infra.load_spec/RecursiveNamespace; builds gains/dt/camera derived params
viautils.parameter_loader.
Inputs / Outputs
- In: a run-spec stem (
analysis_YAMLs/<stem>.yaml), the default run + figure specs, the global
parameters.yaml, andYAMLs_by_domain/{metrics,scoreboard}.yaml; an optionalRunContext(sweep
parameter/value, run dir). - Out: a
Packageof{spec, cfg, ctx, run_name, run_dir}for the runner; aMetricSpectuple +
source config; aScoreboardSpectuple + by-name index.
Key methods / functions
RunSpecLoader.prepare— resolve spec, name, context, and overridden cfg for one run —analysis/pre_run_loader.py:298RunSpecLoader.ordered_overrides— run-spec overrides, then context pairs (context wins) —analysis/pre_run_loader.py:330RunSpecLoader.apply_overrides— set each override; re-derive gains/dt/camera only when gated —analysis/pre_run_loader.py:340RunSpecLoader.set_config_value— validated dotted-path set (the only sanctionedhasattrtraversal) —analysis/pre_run_loader.py:357MetricSpecLoader.walk_metric_specs— recurse the catalog tree, inheriting context per leaf —analysis/pre_run_loader.py:118ScoreboardSpecLoader.load_scoreboard— resolve gates/weights/direction into specs —analysis/pre_run_loader.py:223merge_mapping_defaults— recursive deep-merge of raw spec over defaults —analysis/pre_run_loader.py:274
Footguns
Snapshot traps: post-load overrides on baked params are silently inert
Three families of leaves are compiled/baked at load time and an override against the snapshot
does nothing unless a re-derive fires.apply_overridesdetects each prefix and re-derives only then
(byte-identical otherwise):
- Gains (
controller.{com,base,arm}.gains.*) → compiled to matrices; override the built
cfg.controller.gains.base.K, not the raw leaf. Re-derived bybuild_controller_gains.- dt (
simulation.time.dt) → feeds EE-goal alphas, startup step count, CoM blend baked in
finalize; a dt/2 sweep would integrate at the new step but steer by default-dt references.
Re-derived byrederive_dt_dependent.- Camera (
...sampling.radius_scale,targeting.reach.*,targeting.camera.*) →camera_radius
and the cos/FOV constants baked at load; aradius_scalesweep once ran SILENTLY as the default
rs0.40 (Jun 19). Re-derived byrederive_camera_radius.(
analysis/INSIGHTS.md[footgun] ×3; MEMORYcontroller-gains-built-matrix-path.)
set_config_valueuseshasattrdeliberatelyThis is the only permitted exception to the YAML.md dot-access rule: it must validate an
arbitrary user-supplied dotted path before setting it, raising loudly on a typo. Elsewhere, use
dot access, neverhasattr/fallbackgetattr. (analysis/INSIGHTS.md[config])
Catalog vs judgment are separate files with separate parsers
metrics.yamlis the variable catalog (what is measured);scoreboard.yamlis the judgment layer
(reduction, direction, gate, weight, meaning,after:window).MetricSpecLoaderand
ScoreboardSpecLoaderown them respectively — don’t cross the wires. A catalog leaf missing
variable:raises viareject_missing_variable. (analysis/INSIGHTS.md[config])
Pseudocode (prepare one run)
spec = load_spec(stem.yaml, merge_dict=default_run + default_figure) # deep-merged defaults
ctx = ctx or RunContext(name=run_name) # name | sweep param/value | run_dir
cfg = load_parameters() # global parameters.yaml
overrides = list(spec.run.config_overrides) + ctx.(param,value) pairs # context pairs win (appended last)
for o in overrides: set_config_value(cfg, o.path, o.value) # hasattr-validated dotted set
if any gain leaf touched: cfg.controller.gains = build_controller_gains(...) # else byte-identical
if dt touched: rederive_dt_dependent(cfg)
if any camera leaf touched: rederive_camera_radius(cfg)
return Package(spec, cfg, ctx, run_name, run_dir)
Related
runner · orchestrator · logger · metric_catalog · data_analyzer · terminology