Buckets:
| # 06. Config reference | |
| **Reads:** nothing — reference chapter | |
| **Writes:** nothing | |
| **Code:** `src/onf/graph/core/schema.py`, `src/onf/config.py`, `evals/common/modes.sh` | |
| **Stage:** BUILD and RUNTIME | |
| **Read after:** [`05-artifacts.md`](05-artifacts.md) | |
| Every constant and every environment variable, organised by subsystem. Two kinds of knob: | |
| | kind | where it lives | changed by | | |
| |---|---|---| | |
| | **frozen** | `src/onf/graph/core/schema.py`, or a module-level constant in the owning module | editing the source and rebuilding the artifact | | |
| | **env** | a `from_env()` factory in `src/onf/config.py`, or one of the four documented exceptions | exporting a variable before the run | | |
| `schema.py`'s flat names (`COARSEN`, `HIST_H`, …) are **aliases derived from `DEFAULTS`**, never | |
| literals. Change the dataclass default; the flat name follows. | |
| `GraphConfig` / `SentinelConfig` mirror many of `schema.py`'s values as their | |
| *defaults* and expose them as `GR_*` / `SN_*` variables. A knob listed as env therefore has | |
| two ways to move: edit `schema.py` (changes the default everywhere, including training) or export the | |
| variable (changes this run only). The provenance column below describes the shipped value. | |
| Provenance is `CHOSEN` (picked, no derivation on record), `DERIVED` (computed or measured from | |
| something else, with the derivation stated), or `--` (not determinable from the code or the existing | |
| docs — not guessed). | |
| --- | |
| ## 6.1 Graph build | |
| Frozen in `schema.py`. Every one of these invalidates `g_nodes.npz` / `g_edges.npz`, and therefore | |
| `graph_hash`, and therefore every head and kernel fit against them. | |
| | constant | value | env | C/D | what breaks if it changes | | |
| |---|---|---|---|---| | |
| | `COARSEN` | 5 | `GR_COARSEN` | CHOSEN | raw frames per node; every node id renumbers | | |
| | `PSI_FREQS` | 4 | — | -- | time-encoding octaves; `node_in_dim = 15 + 2·psi_freqs`, so the head's input layer width | | |
| | `GRIP_OPEN_THR` | 0.035 | — | CHOSEN | closed-gripper threshold; moves every coarsening cut and every `grip` label | | |
| | `PHASE_CONV` | `"arange(T)/(T-1) full"` | — | CHOSEN | stamped into `g_nodes.npz` and re-checked on load; a mismatch raises | | |
| | `DILATIONS` | (1,2,4,8,16) | — | DERIVED | `3 × 16 × 5 = 240` raw frames of reach ≈ p50 `long` demo length | | |
| | `RELATIONS` / `REL_INDEX` / `N_RELATIONS` | 12 names, order load-bearing | — | DERIVED | from `DILATIONS`; `rel` is an index into this order, so reordering silently re-labels every edge | | |
| | `K_SIBLING` | 8 | `GR_K_SIBLING` | CHOSEN | kNN out-degree of `sibling`; also the lateral-mixing density the tracker's `M_sib` inherits | | |
| | `K_ALIGN` | 4 | `GR_K_ALIGN` | CHOSEN | kNN out-degree of `align` | | |
| | `NBINS_ALIGN` | 20 | — | CHOSEN | one bin = 0.05 phase; shared by `align` bucketing, the phase-CE loss, basin cells and the sentinel's end-of-task gate | | |
| | `CDIST_BS` | 2048 | — | CHOSEN | `torch.cdist` row-block size; memory/throughput only | | |
| | `KERNEL_BW` | 0.15 rad | `GR_KERNEL_BW` | CHOSEN | joint-space kernel bandwidth for edge weights and for seeding | | |
| | `GEO_SCALE` | 0.5303 | `ONF_GEO_SCALE` | DERIVED | calibrated so median `f` over LODO node distances matches the trained field's median `f` on the same graph; read **only** under `ONF_CLEANLINESS=geo` | | |
| `SUITE_HDF5_DIRS` (`src/onf/graph/build/from_demos.py`) maps suite names to HDF5 directories: | |
| `object → libero_object`, `spatial → libero_spatial`, `goal → libero_goal`, | |
| **`long → libero_10`** (not `libero_long`). CHOSEN — it is the upstream LIBERO layout. | |
| --- | |
| ## 6.2 Retrieval head | |
| ### Network and query shape (frozen, `schema.py`) | |
| | constant | value | env | C/D | what breaks if it changes | | |
| |---|---|---|---|---| | |
| | `HIDDEN` | 64 | `GR_HIDDEN` | CHOSEN | every weight tensor; `g_head.npz` no longer loads | | |
| | `LAYERS` | 3 | `GR_LAYERS` | CHOSEN | message-passing depth; weights are shared across layers, so depth is stored as a 0-d scalar in the checkpoint, not implied by shapes | | |
| | `AGG` | `"sum"` | `GR_AGG` | CHOSEN | `"logsumexp"` with `m = −cost` recovers DTW's soft-min | | |
| | `AGG_TEMP` | 1.0 | — | -- | logsumexp temperature; inert under `agg="sum"` | | |
| | `HIST_H` | 8 | `GR_HIST` | CHOSEN | query window `W`; equals one policy action chunk | | |
| | `SEG_K` | 8 | `GR_SEG_K` | CHOSEN | reference-segment length; a point target restores `q` but not `qdot` | | |
| | `SEED_TOPK` | 256 | `GR_SEED_TOPK` | CHOSEN | nodes given a nonzero `h0`; everything else stays exactly 0 | | |
| | `SEED_VEL_W` | 2.0 | `GR_SEED_VEL_W` | CHOSEN | exponent on the velocity-direction factor in seeding; 0 disables it | | |
| | `ADVANCE` | 0 raw frames | — | DERIVED | the head answers "where am I now"; the transition kernel owns how far forward, and its fitted mixture already advances E[a] = 9.6 raw frames per 8-step check | | |
| ### Objective weights (frozen, `schema.py`) | |
| | constant | value | env | C/D | what breaks if it changes | | |
| |---|---|---|---|---| | |
| | `PHASE_CE_W` | 1.0 | `GR_PHASE_CE_W` | CHOSEN | primary term: CE on the 20-bin phase marginal | | |
| | `PHASE_EXPECT_W` | 0.5 | `GR_PHASE_EXPECT_W` | CHOSEN | primary term: phase-expectation regression | | |
| | `NODE_W` | 0.1 | `GR_NODE_W` | CHOSEN | auxiliary node-identity BCE+rank; strand identity is only 8–15% learnable | | |
| | `PHASE_BIN_SMOOTH_W` | 1.0 | — | CHOSEN | ±1-bin smoothing mass on the phase-CE target | | |
| | `PHASE_BIN_SMOOTH_T` | 1.0 | — | CHOSEN | smoothing decay `exp(−|db|/t)` | | |
| | `WHERE_PHASE_BAND` | 0.05 | `GR_WHERE_PHASE_BAND` | CHOSEN | multi-positive candidate band; one `NBINS_ALIGN` bin, same width as the deployed entry band | | |
| | `WHERE_MOVE_TEMP` | 0.1 | `GR_WHERE_MOVE_TEMP` | CHOSEN | softmax temperature on inverse movement cost in the soft target | | |
| | `WHERE_TRUE_BONUS` | 2.0 | — | CHOSEN | multiplicative boost on the true continuation | | |
| ### Curriculum (frozen, `src/onf/graph/train/data.py`) | |
| | constant | value | C/D | what breaks if it changes | | |
| |---|---|---|---| | |
| | `N_NEG` | 16 | CHOSEN | mined hard negatives per query, across buckets (a)/(b)/(c) | | |
| | `SELFX_K` | 16 | CHOSEN | local kNN pool searched for the self-intersection bucket | | |
| | `SELFX_PHASE_GAP` | 0.15 | CHOSEN | `|Δphase|` that promotes a near-in-`q` neighbour into bucket (b) | | |
| | `ENTRY_FRAC` | 1/3 | CHOSEN | share of the **non-static** queries drawn as ENTRY | | |
| | `ENTRY_LO_MULT` / `ENTRY_HI_MULT` | 0.25 / 50.0 | DERIVED | radius range is `(0.25·p50, 50·p99)` of the measured LODO demo-start noise floor | | |
| | `ENTRY_LOGUNIFORM` | `True` | DERIVED | the range spans two decades; a linear draw puts ~90% of mass in the top decade | | |
| | `ENTRY_STATIC_FRAC` | 0.15 | CHOSEN | drawn **first**, before the ENTRY coin flip, so it is a share of all queries; without it the deployed t=0 window shape never appears in training | | |
| | `ENTRY_STATIC_BAND` | 0.05 | CHOSEN | phase band of the static class's soft-target pool; matches `GR_ENTRY_BAND` exactly | | |
| | `ENTRY_STATIC_NODE_W` | 1.0 | CHOSEN | replaces `node_w` on static rows (their phase terms are trivial — the whole pool is in bin 0) | | |
| | `ENTRY_STATIC_SRC_AUX_W` | 0.0 | CHOSEN | the source-node warm-up would fight the uniform-over-pool target | | |
| ### Loss terms (frozen, `src/onf/graph/train/loss.py`) | |
| | constant | value | C/D | what breaks if it changes | | |
| |---|---|---|---| | |
| | `ALPHA_BCE` | 0.3 | CHOSEN | node term is `0.3·BCE + 0.7·RANK`, the whole of which `NODE_W` then demotes | | |
| | `SRC_AUX_W` | 0.05 | CHOSEN | weight of the kNN-solvable "predict the source node" warm-up | | |
| | `ABSTAIN_W` | 0.5 | CHOSEN | weight of the abstain decision term | | |
| | `ABSTAIN_MARGIN` | 1.0 nats | CHOSEN | margin on the exact statistic inference reads, `abstain_logit − logits[reached].max()` | | |
| | `ABSTAIN_NODE_MAX_FALLBACK` | 0.0 nats | CHOSEN | keeps the margin defined when nothing is reachable | | |
| | `REL_INIT_STD` | 0.02 | CHOSEN | relation-embedding init (`net/modules.py`) | | |
| | `LOG_W_EPS` | 1e-12 | CHOSEN | floor inside `softmax(log w)` pooling | | |
| ### Training loop (frozen, `src/onf/graph/train/loop.py`) | |
| | constant | value | env | C/D | what breaks if it changes | | |
| |---|---|---|---|---| | |
| | `N_QUERY` | 4096 | — | CHOSEN | queries generated per stage | | |
| | `N_EVAL` | 128 | — | CHOSEN | held-out queries for the per-epoch report | | |
| | `HELDOUT_STRIDE` | 5 | — | CHOSEN | split is by **demo strand**, never by frame — adjacent frames leak | | |
| | `LR` / `WEIGHT_DECAY` | 1e-3 / 1e-5 | — | CHOSEN | AdamW | | |
| | `GUARD_MRR_TOL` | 0.01 | — | CHOSEN | admissibility gate; an epoch that quietly degrades clean retrieval cannot become "best" | | |
| | `stages` | `(1,)` | — | CHOSEN | stages 2 and 3 were deleted; any other value raises | | |
| | `qbatch` | 8 | `GR_QBATCH` | -- | queries per forward/backward; pure throughput — the loss returns a batch **mean**, so the per-query learning rate is unaffected | | |
| ### Readout, at retrieval time | |
| | knob | default | env | C/D | what breaks if it changes | | |
| |---|---|---|---|---| | |
| | `READOUT_ARMS` | `("euc_raw", "basin")` | — | CHOSEN | the registry; `euc_raw` is the t=0 arm, `basin` the t>0 arm | | |
| | `GraphConfig.readout` | `"euc_raw"` | `GR_READOUT` | CHOSEN | which arm consumes `p(v|Q)` | | |
| | `GraphConfig.temp` | 1.0 | `GR_TEMP` | -- | readout softmax temperature | | |
| | `GraphConfig.topm` | 32 | `GR_TOPM` | -- | candidate nodes kept for readout; ENTRY widens it to the whole surviving pool so the mask is not re-truncated | | |
| | `GraphConfig.seed_decay` | 0.9 | `GR_SEED_DECAY` | CHOSEN | temporal decay `0.9^k` over the query window during seeding | | |
| | `GraphConfig.idf` | 1.0 | `GR_IDF` | -- | exponent on the additive `log_idf` prior (GFM-RAG eq. 15–16) | | |
| | `GraphConfig.move_cost` | `True` | `GR_MOVE_COST` | CHOSEN | passes the movement-cost channel through at deploy so train and deploy see the same input | | |
| | `GraphConfig.entry_band` | 0.0 (off) | `GR_ENTRY_BAND` | CHOSEN | masks candidates to `phase ≤ band` | | |
| | `GraphConfig.task_prior_w` | 0.0 (off) | `GR_TASK_PRIOR_W` | CHOSEN | nats of additive task log-prior the belief filter's own task marginal contributes when the text lane resolved nothing; 1.0 is the plain Bayesian value. Consulted only in the no-lane case, so the six axes whose lane resolves are bit-unchanged | | |
| | `GraphConfig.device` | `""` = auto | `GR_DEVICE` | CHOSEN | CPU and CUDA disagree by up to ~1e-4 rad elementwise | | |
| | `GraphConfig.graph_dir` | `""` | `GR_GRAPH_DIR` | — | overrides `Paths.graph()` | | |
| --- | |
| ## 6.3 Sentinel (t > 0) | |
| ### Frozen in `schema.py` | |
| | constant | value | env | C/D | what breaks if it changes | | |
| |---|---|---|---|---| | |
| | `TRACK_ADVANCE_SET` | (0,1,2,4,6,8,12,16) | — | DERIVED (upper end) | raw-frame advances mixed by the kernel. `0` is mandatory and validated — it is the stall self-loop. 16 ≈ 2× the nominal check spacing, because rollouts run longer and slower than the median demo | | |
| | `TRACK_KERNEL_RELATIONS` | `next1..next16` + `sibling` | — | CHOSEN | excluding `align` and every `prev^d` is the asymmetry that suppresses the measured 8% backwards aliasing | | |
| | `TRACK_BELIEF_TOPK` | 2048 | — | -- | belief entries kept when a readout is handed to host memory | | |
| | `BASIN_RADIUS_QUANTILE` | 0.95 | — | DERIVED | p95 of LODO NN distances → the certified radius `r` | | |
| | `BASIN_BANDWIDTH_QUANTILE` | 0.50 | — | DERIVED | p50 of the same → the KDE bandwidth / stop-short margin `h` | | |
| | `BASIN_MIN_DEMOS` | 2 | — | CHOSEN | cells with fewer distinct demos inherit the per-task median `r`/`h` | | |
| `r_eff = max(r − h, 0)` is DERIVED. `π`, `β` and `leak` are DERIVED — fitted by | |
| `onf.graph.build.tracker_fit` and stored in `g_track.npz`, not in any config. | |
| ### `SentinelConfig`, `SN_*` (env) | |
| | field | default | env | C/D | what breaks if it changes | | |
| |---|---|---|---|---| | |
| | `check_every` | 8 | `SN_CHUNK` | DERIVED | `_POLICY_CHUNK = 8`. A value that does not divide the chunk is **refused**: the client executes a cached chunk open-loop, so a check landing mid-chunk cannot influence the plan already in flight | | |
| | `graph_win` | 8 | `SN_GRAPH_WIN` | DERIVED | must equal `HIST_H` | | |
| | `graph_stride` | 0 → 1 | `SN_GRAPH_STRIDE` | DERIVED | `_TRAIN_WINDOW_STRIDE = 1`. Training windows are 8 **consecutive** raw frames (`finite_diff_vel` is a 1-frame backward difference); stride 8 would hand the net ~8× the velocity magnitude it ever saw. Any other value is refused | | |
| | `graph_topm` | 32 | `SN_GRAPH_TOPM` | -- | candidate nodes kept before readout | | |
| | `graph_temp` | 1.0 | `SN_GRAPH_TEMP` | -- | readout softmax temperature | | |
| | `blend_alpha` | 0.0 | `SN_BLEND_ALPHA` | CHOSEN | weight on the tracking chunk. 0.0 is bit-exactly the frozen policy — `BlendPlan.apply` returns the chunk untouched — so a `SENTINEL=1` run at the default reproduces base numbers exactly. Unread under `blend_learned` | | |
| | `blend_learned` | `False` | `SN_BLEND_LEARNED` | CHOSEN | read the per-row, per-block weight off the trained `AlphaNet` in `g_alpha.npz` instead of using `blend_alpha`. A missing file **raises**: a run that silently measures a different mechanism than the one it was asked for is worse than a run that does not start | | |
| | `blend_scale` | 1.0 | `SN_BLEND_SCALE` | DERIVED | multiplier on the LEARNED weight, unread unless `blend_learned`. The chunk-MSE objective fits the right per-check shape at too confident a level, so the head is rescaled onto the average authority a fixed weight was measured at. **Derived per head, never copied:** the deployed 0.27 is `0.31 × 0.372/0.425`, matching the base-frame head's deployed mean to the previous head's — [chapter 03 §3.6](03-action-chunk-blend.md) | | |
| | `blend_bound` | 0.0 | `SN_BLEND_BOUND` | DERIVED | action-unit saturation of `a_track`'s row 0, `bound·tanh(row0/bound)`; 0 disables it, which is what the measured fixed-alpha cells ran with. 1.0 is the value the simulator's own `[-1, 1]` action clip implies. Under `blend_learned` this is unread and the bound is `ACTION_LIMIT` — [chapter 03 §3.5](03-action-chunk-blend.md) | | |
| | `action_scale_path` | `""` | `SN_ACTION_SCALE` | — | metres/radians per action unit. `""` resolves to `action_scale.json` beside the graph artifacts; a missing file **raises**, naming `scripts/fit_action_scale.py`. There is no default calibration: a wrong scale mis-drives the arm silently | | |
| | `allow_stride_mismatch` | `False` | `SN_ALLOW_STRIDE_MISMATCH` | CHOSEN | opt-out of the stride guard. A **field**, not a bare env read inside the guard, so `asdict(cfg)` records that a run disabled a safety check | | |
| | `allow_misaligned` | `False` | `SN_ALLOW_MISALIGNED` | CHOSEN | opt-out of the chunk-alignment guard, same reasoning | | |
| | `graph_device` | `""` = auto | `SN_GRAPH_DEVICE` | CHOSEN | | | |
| | `graph_dir` | `""` | `SN_GRAPH_DIR` | — | overrides `Paths.graph()` | | |
| ### `scripts/build_sentinel_artifacts.py` (frozen, CLI-overridable) | |
| | constant | value | CLI flag | C/D | what breaks if it changes | | |
| |---|---|---|---|---| | |
| | `HELD_OUT_STRIDE` | 5 | `--held-out-stride` | CHOSEN | `owner % 5 == 0` is held out (100/500 on `long`); the kernel fit set shrinks or grows | | |
| | `FIT_CLEAN_STRIDE` | 3 | `--fit-clean-stride` | CHOSEN | wall-clock bound on the clean half of the fit set | | |
| | `N_DRIFT_SEQ` / `N_CROSS_STRAND_SEQ` | 80 / 80 | `--n-drift` / `--n-cross-strand` | CHOSEN | the two regimes that make `β` identifiable; on clean-only sequences `β = 0` is correct and the fit is uninformative | | |
| | `DRIFT_SEQ_SEED` | 0 | — | CHOSEN | reproducibility of the sampled sequences | | |
| | `N_PROBE_DEMOS` | 40 | — | CHOSEN | sanity-probe sample size (debug only) | | |
| | `BURNIN_CHECKS_MIN` | 3 | — | CHOSEN | probe burn-in | | |
| | `PROBE_PHASE_FRAC` | 0.5 | — | CHOSEN | probe mid-episode | | |
| --- | |
| ## 6.4 Action-chunk blend | |
| The runtime knobs are `SentinelConfig` fields, listed in §6.3 — the blend is issued by the sentinel's | |
| `plan()`. What follows is everything else the mechanism is parameterised by. Full reasoning: | |
| [chapter 03](03-action-chunk-blend.md). | |
| ### Frozen in `src/onf/blend/ee_track.py` and `src/onf/blend/alpha.py` | |
| | constant | value | C/D | what breaks if it changes | | |
| |---|---|---|---| | |
| | `ACTION_DIM` / `POSE_DIM` / `GRIP_COL` | 7 / 6 / 6 | CHOSEN | the OSC action layout. `GRIP_COL` is copied through, never mixed: the command is binary | | |
| | `DEFAULT_MIN_R2` | 0.8 | CHOSEN | `ActionScale.check`'s bar. A rotation block below it usually means the delta was subtracted rather than composed in the world frame | | |
| | `_SMALL_ANGLE` | 1e-3 rad | CHOSEN | the Taylor branch of the Rodrigues trig quotients; under autograd it also keeps the gradient finite | | |
| | `ACTION_LIMIT` | 1.0 | DERIVED | row-0 saturation amplitude, applied to the tracking chunk and to the regression target alike. LIBERO clips the executed action to `[-1, 1]` and real demo actions max at 0.938. A constant, not a parameter: the one run that learned it drove it to 24.5 | | |
| | `HIDDEN` (AlphaNet) | 64 | CHOSEN | width of the one hidden layer. Stored in `g_alpha.npz`, so changing it does not break loading old heads | | |
| | `N_BLOCK` | 2 | CHOSEN | weights per chunk row: one for position, one for rotation. 1 would re-merge the two blocks | | |
| | `N_SCALAR` | 3 | DERIVED | off-manifold distance, top-1 posterior mass, posterior entropy | | |
| | `EXPECT_K` | 32 | DERIVED | `expected_ee_segment`'s support width; matches `ReadoutContext.topm` | | |
| The two fitted scales are not constants — `ActionScale` is read from `action_scale.json`. Measured | |
| values are in [chapter 03 §3.4](03-action-chunk-blend.md). | |
| ### Weight training (frozen, `src/onf/graph/train/corrupt.py`, `align.py`, `loss.py`) | |
| | constant | value | C/D | what breaks if it changes | | |
| |---|---|---|---| | |
| | `p_wrong_task` / `p_offset` / `p_wrong_phase` | 0.10 each | CHOSEN | share of training rows given a deliberately wrong retrieval. At 0 the alpha gradient is one-sided and alpha can only learn arm displacement | | |
| | `phase_tol` | 0.05 | CHOSEN | `WRONG_TASK`'s node must be this close in phase, so the failure is a genuine alias | | |
| | `phase_min` | 0.15 | CHOSEN | `WRONG_PHASE`'s node must be at least this far | | |
| | `offset_m` | (0.05, 0.25) m | CHOSEN | `OFFSET`'s displacement magnitude: an object's own width to a shelf away | | |
| | `ALIGN_H` | 0.05 m | CHOSEN | mean warped DTW distance below which two segments count as the same path (~a gripper width) | | |
| | `CHUNK_PHASE_CE_W` | 0.2 | CHOSEN | the CHUNK objective's anti-collapse regulariser | | |
| | `CHUNK_ALIGN_W` | 0.1 | CHOSEN | weight of the DTW alignment teacher, against an MSE term of 1.0 | | |
| --- | |
| ## 6.5 Paths and process environment | |
| `src/onf/config.py::Paths`. Resolution order is: explicit argument, then the variable, then | |
| repo-local. | |
| | root / method | fallback | env | | |
| |---|---|---| | |
| | `Paths.data` | `<repo>/data` | `ONF_DATA` | | |
| | `Paths.results` | `<repo>/results` | `ONF_RESULTS` | | |
| | `Paths.outputs(*parts)` | `<repo>/outputs` | `ONF_OUTPUTS` | | |
| | `Paths.fwm(suite)` | `data/fwm/` for `object`/`default`, else the `fwm_dir` from `configs/suites.yaml`, else `data/fwm/<suite>` | `QNDF_DIR` (wins outright) | | |
| | `Paths.graph(suite)` | `outputs/<suite>/latest/artifacts` | `GR_GRAPH_DIR` (wins outright) | | |
| | `Paths.hdf5(name)` | first existing of `data/libero_hdf5/<name>`, `data/libero_datasets/<name>` | — | | |
| `_HDF5_ROOTS = ("libero_hdf5", "libero_datasets")` is CHOSEN — a historical two-batch split that | |
| `configs/suites.yaml` does not record. | |
| ### The three env reads that live outside `config.py` | |
| Deliberate: none of them is a run knob these dataclasses carry. | |
| | variable | default | read in | effect | | |
| |---|---|---|---| | |
| | `ONF_CLEANLINESS` | `field` | `graph/core/geometry.py::CleanlinessConfig.from_env` | `geo` swaps the trained field for the weight-free `GeometricField` | | |
| | `ONF_GEO_SCALE` | `GEO_SCALE` = 0.5303 | same | distance scale of that stand-in | | |
| | `SN_GRAPH_TRACE_DIR` | unset | `sentinel/sentinel.py` | per-episode `.npz` debug trace sink; read once at construction, never on the control path | | |
| ### Mandatory for every run | |
| ```bash | |
| export PYTHONPATH=src OMP_NUM_THREADS=4 | |
| ``` | |
| --- | |
| ## 6.6 Modes | |
| `evals/common/modes.sh::onf_set_mode` is the **only** definition of a mode. | |
| `scripts/run_sr.py::parse_mode_recipes` parses this file rather than re-declaring the recipes, so | |
| every arm must stay shaped as `name) export VAR=val ... ;;` — no control flow inside an arm, one | |
| `export` per arm (backslash continuations are fine). | |
| | mode | exports | what it is for | | |
| |---|---|---| | |
| | `base` | nothing | frozen policy, no intervention. A reporting baseline, not an ablation | | |
| | `blend` | `SENTINEL=1`, `SN_BLEND_ALPHA=0.0` | the plumbing check. Bit-identical to `base`; a cell that differs here is a bug, not a result | | |
| | `blend_a05` | `SENTINEL=1`, `SN_BLEND_ALPHA=0.5`, `GR_GRAPH_DIR` at the ADVANCE=0 head | the first fixed-alpha probe ([`../results.md`](../results.md) §5, superseded — but still the best arm on Camera_Viewpoints) | | |
| | `blend_a015` | as above at `0.15` | how much of `blend_a05`'s loss is intervention *magnitude* rather than a wrong blend direction | | |
| | `blend_bounded` | as above at `0.3`, plus `SN_BLEND_BOUND=1.0` | everything the blend gained except the learned weight — the row-0 bound and the task-lane fix — held at a fixed alpha so a gap left here is one alpha has to close | | |
| | `blend_a015_bounded` | as above at `0.15` | the best FIXED weight measured: 262/312 = 84.0% on Objects_Layout, the bar the learned weight has to clear | | |
| | `blend_scaled015` | `SENTINEL=1`, `SN_BLEND_LEARNED=1`, `SN_BLEND_SCALE=0.31`, `GR_GRAPH_DIR` at the v3 Stage-2 artifacts | the learned weight's *shape* at the authority a fixed weight was measured at — 88.1% on Objects_Layout | | |
| | `blend_full` | as above with `SN_BLEND_SCALE=0.27`, `GR_TASK_PRIOR_W=1.0` and the base-frame v4 head | **the current recipe.** 7-axis total +7.9 pp ([`../results.md`](../results.md) §6) | | |
| `evals/common/modes.sh` carries a dozen further probe arms with the measurement that motivated each | |
| in its comment; the table above is the ladder, not the inventory. | |
| The fixed-alpha blend arms pin `GR_GRAPH_DIR` at the ADVANCE=0 head on purpose: under the old | |
| `+4` head the feedforward rows of `a_track` aim ~13.6 frames ahead on an 8-frame chunk, which a | |
| position-restoring servo absorbed and a feedforward blend does not | |
| ([chapter 02 §2.4](02-retrieval-head.md), [chapter 03](03-action-chunk-blend.md)). | |
| --- | |
| ## 6.7 Easy to get wrong | |
| 1. **Assigning a literal to a flat `schema.py` name.** The flat names are aliases derived from | |
| `DEFAULTS`; a literal creates a second source of truth that can drift from the dataclass the | |
| validation lives on. | |
| 2. **Changing a §6.1 constant and reusing an old head.** Anything in that table renumbers nodes or | |
| re-labels edges, so `graph_hash` changes and every stamped artifact must be rebuilt. The loader | |
| will refuse — see [chapter 05 §5.2](05-artifacts.md#52-graph_hash--the-most-important-check-in-the-subsystem). | |
| 3. **Setting `SN_GRAPH_STRIDE` from `SN_CHUNK`.** They are independent. `check_every` is how often | |
| you *check*; `graph_stride` is the spacing *within* the window. Setting stride to 8 gives the | |
| network ~8× the velocity it trained on. The guard refuses it; `SN_ALLOW_STRIDE_MISMATCH=1` | |
| silences the guard, not the problem. | |
| 4. **Exporting a `SN_CHUNK` that does not divide 8.** Refused for the same class of reason: a check | |
| landing mid-chunk cannot influence the chunk already in flight. | |
| 5. **Adding a tuning knob as a bare `os.environ.get`.** A knob that is not a field on one of the | |
| two dataclasses does not appear in the run's `config.json`, so the run record cannot say what it | |
| was set to. The two `SN_ALLOW_*` opt-outs are fields precisely for this reason. | |
| 6. **Running a blend mode without checking which `action_scale.json` it resolved.** The blend | |
| converts metres and radians into action units; the calibration carries no `graph_hash` and no | |
| suite stamp, so a file fitted on another suite loads without complaint and rescales every action | |
| the arm executes. | |
| 7. **Setting `SN_BLEND_ALPHA` or `SN_BLEND_BOUND` under `blend_learned`.** Both are unread there: | |
| the trained head owns the weight and `ACTION_LIMIT` owns the bound. A run that appears to set a | |
| knob it does not set is worse than one that sets nothing. | |
| --- | |
| **Next:** [`../results.md`](../results.md) — what these settings measure, or back to the | |
| [README](../../README.md). | |
Xet Storage Details
- Size:
- 24.2 kB
- Xet hash:
- 33d1809e7ba28d19e1c11e9bff5ceb66ee30d5177d629fe55feddb8d455fe9cf
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.