Investigation report — generated 2026-06-06 23:58 EDT. Report-only; no code changed.
s_min_G = σ_min(Γ) and
s_min_J = σ_min(J_νe⊕) — through
seven runtime mechanisms (Tikhonov inverse, CoM/base
speed derate, arm-gain scale, base-torque scale, base-goal blend,
integral-windup gate, EE pose blend) plus a separate startup
config sampler. Each mechanism reads a different
config path.run_PM0848, s_min_G is below
the gamma high threshold (0.05) for 96.1%
of the run and below low (0.01) for 30%;
gamma_scale averages 0.45 and frequently
hits its 0.25 floor
(diagnostics.conditioning.*). The Tikhonov damping is
likewise active almost continuously.scale_by_svd(σ, {low, high, floor}) (utils/sampling.py:59) — a ramp from
floor (σ≤low) to 1.0 (σ≥high). Every derating
site already routes through it. The sprawl is entirely in the
config tree feeding it, not the math.conditioning.{gamma,j_plus} trees), dead
config (com.speed_derating.floor), the value
0.25 triplicated, and a whole mechanism
silently disabled by a floor: 0.0.gamma and
j_plus families track the same physical event and
are candidates to collapse onto one signal/threshold
set.{low, high, floor} on the instrumented
signal s_min_G, with a single Tikhonov damping constant —
~4 knobs replacing ~15. Keep a second ramp only if base-attitude
genuinely needs a different cap (Option B).logs/logs_Jun06_26/full_control_run/enable_true/npz/run_PM0848/enable_true.npz.scale_by_svd.dyn module that computes
s_min_G/s_min_J; robot.sampling
config-search lifecycle.run_PM0848, 50 000 steps)| Signal (npz key) | min | mean | max | time below high=0.05 |
below low=0.01 |
|---|---|---|---|---|---|
diagnostics.conditioning.s_min_G |
1.4e‑4 | 0.0204 | 0.108 | 96.1% | 30.0% |
diagnostics.conditioning.gamma_scale |
0.25 (floor) | 0.4499 | 1.0 | — | — |
s_min_J, j_plus_scale, and the Tikhonov
lam are not logged → mechanisms D/E/F
(below) run blind. Tikhonov
lam = max(0.0001, 0.05² − s_min_G²) is positive whenever
s_min_G < 0.05, i.e. ~96% of the run, so the damped
solve is effectively always engaged.
Every row ultimately calls
scale_by_svd(signal, threshold) (utils/sampling.py:59) except A
(Tikhonov) and G (manual ratio).
| # | Mechanism | Site | Signal | Config path it reads | Enable gate |
|---|---|---|---|---|---|
| A | Tikhonov damped Γ⁻¹ (reduced→full velocity) | BreveController.py:244‑259 | s_min_G |
controller.base.gamma_regularization {damping, floor,
v_max, clip_velocity} |
gamma_regularization.enable |
| B | CoM/base speed derate (scales des v_c,
a_c², ω_b) |
base_guidance.py:147‑154 | s_min_G |
controller.base.conditioning.gamma.sigma |
controller.com.speed_derating.enable |
| C | Arm gain scale (scales arm D,K in breve RHS) | BreveController.py:512‑520 | s_min_G |
controller.base.conditioning.gamma.sigma |
controller.base.conditioning.gamma.enable |
| D | Base torque scale (scales τ_b⊕) |
BreveController.py:126‑141 | s_min_J |
controller.base.conditioning.j_plus.sigma |
controller.base.conditioning.j_plus.enable |
| E | Base-goal blend (rotates base attitude goal inward) | base_guidance.py:156‑170 | s_min_J |
controller.base.conditioning.j_plus.sigma |
controller.base.conditioning.j_plus.enable |
| F | Integral-windup gate (freezes EE integral) | BreveController.py:321‑326 | s_min_J |
arm.integral.scale_gate +
j_plus.sigma |
arm.integral.enable |
| G | EE pose blend near singular Γ (toward fallback pose) | ee_guidance.py:702‑714 | s_min_G |
controller.trajectory.conditioning.gamma.floor |
— (floor=0.0 ⇒ off) |
| H | Startup config sampler (picks non-singular q₀) | utils/sampling.py:59 | both | top-level conditioning.{gamma,j_plus} |
conditioning.*.enable |
| Config path | Value | Consumed by | Note |
|---|---|---|---|
controller.com.speed_derating.enable |
true | B (gate) | gate only |
controller.com.speed_derating.floor |
0.25 | — | DEAD — B reads
base.conditioning.gamma.sigma.floor instead (base_guidance.py:148) |
controller.base.gamma_regularization.{damping,floor,v_max,clip_velocity,enable} |
1e‑4 / 0.05 / 50 / true / true | A | Tikhonov; floor is a σ-floor in
lam=max(damping, floor²−σ²) |
controller.base.conditioning.gamma.sigma.{low,high,floor} |
0.01 / 0.05 / 0.25 | B, C | the gamma ramp |
controller.base.conditioning.j_plus.sigma.{low,high,floor} |
0.02 / 0.05 / 0.1 | D, E | the j_plus ramp |
controller.trajectory.conditioning.gamma.floor |
0.0 | G | makes G a no-op (s_min ≥ 0 always) |
arm.integral.scale_gate |
— | F | gates integral on j_plus scale |
top-level
conditioning.gamma.{floor,step_size,num,enable} |
0.25 / 0.35 / 96 / true | H (sampler) | name-collides with
controller.base.conditioning.gamma |
top-level
conditioning.j_plus.{soft_floor,hard_floor,damping,inv_norm_max,enable,...} |
0.02 / 0.005 / 1e‑4 / 1000 / true | H (sampler) | name-collides with
controller.base.conditioning.j_plus |
The two ramps (gamma, j_plus) differ only in low (0.01
vs 0.02) and floor (0.25 vs 0.1); high is
identical (0.05).
scale_by_svd(s_val, s_opts) — utils/sampling.py:59. The one ramp
primitive: floor for σ≤low, 1.0 for σ≥high,
linear between. Every derating site funnels here.BaseGuidance.build_*_for_step →
derate_desired_by_gamma /
blend_base_goal_by_jplus — base_guidance.py:129‑170.
Mechanisms B and E; B’s enable and threshold live in different
blocks.BreveController.j_plus_condition_scale /
gamma_condition_scale — BreveController.py:126‑132. Thin
wrappers over scale_by_svd; feed C, D, F.BreveController.reconstruct_generalized_velocity — BreveController.py:244‑259.
Mechanism A (Tikhonov); the only place Γ is actually inverted.EEGuidance.blend_near_singular_Gamma — ee_guidance.py:702‑714.
Mechanism G; disabled by config.F1 — Singularity handling is the operating regime, not a
guard. Evidence: s_min_G < 0.05 for
96.1% and < 0.01 for 30% of run_PM0848;
gamma_scale mean 0.45, floor 0.25 frequently active.
Impact: These knobs shape every step, so their sprawl
is a daily tuning/debugging tax, not an emergency-only concern.
Streamlining is high-value. Next step: Treat the conditioning
ramp as a primary controller gain, not a safety afterthought.
F2 — Name collision: two
conditioning.{gamma,j_plus} trees.
Evidence: runtime block at parameters.yaml:81‑93 vs
sampler block at parameters.yaml:138‑155;
disjoint consumers (controller/guidance vs robot.sampling).
Impact: Editing conditioning.gamma.floor changes
the startup sampler, not runtime derating — the single biggest
“impossible to tune” trap. Next step: Rename the top-level
sampler block to config_sampling (or nest it under
robot:).
F3 — Dead and triplicated knobs. Evidence:
com.speed_derating.floor=0.25 is never read (base_guidance.py:148 uses
base.conditioning.gamma.sigma); the value 0.25
also appears at parameters.yaml:87 and :155. Impact:
Edits to the dead floor silently do nothing; duplicated values drift
apart. Next step: Delete speed_derating.floor;
make the floor live in one place.
F4 — One physical singularity, two signal families.
Evidence: Appendix B of the corrected reference — Γ⁻¹’s only
inverse factor is (J_νe⊕)⁻¹, in three of its blocks; so σ_min(Γ)→0 ⇔
σ_min(J_νe⊕)→0. Impact: The gamma (s_min_G) and
j_plus (s_min_J) ramps fire on the same event. Maintaining
two threshold sets is largely redundant. Next step: Drive all
mechanisms off the single instrumented signal s_min_G,
unless a measured reason to split survives.
F5 — j_plus path is uninstrumented.
Evidence: npz logs only s_min_G and
gamma_scale; no s_min_J /
j_plus_scale (controller_diagnostics,
BreveController.py:528‑535 logs only gamma). Impact:
Mechanisms D/E/F (base torque, base-goal blend, integral gate) cannot be
observed or tuned from logs. Next step: Log
s_min_J and j_plus_scale alongside the gamma
pair.
F6 — A mechanism is silently disabled by a floor
value. Evidence:
trajectory.conditioning.gamma.floor = 0.0 (parameters.yaml:247‑249);
blend_near_singular_Gamma returns raw_pose
whenever s_min ≥ floor (ee_guidance.py:706‑707), and
σ ≥ 0 always. Impact: The EE pose-blend mechanism is off, but
nothing says so; a reader assumes it runs. Next step: Decide if
pose-blend is wanted; if not, delete the mechanism + config; if yes, set
a real floor.
F7 — Inconsistent enable ownership for the gamma
family. Evidence: B is gated by
com.speed_derating.enable (base_guidance.py:129); C by
base.conditioning.gamma.enable (BreveController.py:514) — two
flags for the same signal. Impact: Turning “gamma conditioning
off” requires flipping flags in two blocks; easy to half-disable.
Next step: One master enable per conditioning
family.
F8 — Thresholds may be mis-scaled to this robot’s σ
range. Evidence: s_min_G exceeds
high=0.05 only 3.9% of the run, so the ramp almost never
reaches the “healthy = 1.0” end; the UR3-on-cube neutral config is
itself singular (full_paper.tex:398).
Impact: The ramp effectively runs in floor/linear region
permanently — the high knob barely matters, and
floor (0.25) is doing the real work. Tuning
high feels inert. Next step: Re-fit
{low, high} to the observed σ distribution
(e.g. percentiles of s_min_G), or confirm the robot is
meant to live near-singular and treat floor as the primary
gain.
Justified by F4 (Γ ⇔ J_νe⊕ singular together) and F1/F5 (only
s_min_G is instrumented and it already governs the dominant
mechanisms). Replace all six blocks with:
controller:
conditioning: # ONE block; signal = s_min_G
enable: true
sigma: { low: 0.01, high: 0.05 } # the single ramp (F8: re-fit to σ distribution)
floor: 0.25 # single derating cap, shared by B/C/D/E
gamma_damping: 0.0001 # Tikhonov (mechanism A) only extra knob
sigma.high as the σ-floor
(lam = max(gamma_damping, sigma.high² − σ²)); drop
gamma_regularization.{floor, v_max, clip_velocity} unless
clip is shown to be needed.scale_by_svd(s_min_G, conditioning.sigma)
with the shared floor.config_sampling (F2), unrelated
to runtime.Net: ~4 runtime knobs (low, high, floor, gamma_damping)
+ one enable, replacing ~15.
Keep the gamma/j_plus split
only as the conditioning consumer, one ramp each, but:
rename the sampler block (F2), delete speed_derating.floor
(F3), unify enables (F7), and instrument s_min_J (F5). ~8
knobs. Choose this only if a log-backed reason to treat base-attitude
derating differently from velocity/gain derating emerges.
TITLE: Collapse conditioning config to one ramp
BODY: Implement Option A: introduce
controller.conditioning, point mechanisms A–F at it, delete
the redundant blocks. Modify: YAMLs_by_domain/parameters.yaml
(via owning loader), GNC/BreveController.py (126‑132,
244‑259, 512‑520), GNC/base_guidance.py (129‑170).
Inspect-not-modify: utils/sampling.py, the dyn
module computing s_min_G. Create: none.
Validation: A/B a short run vs run_PM0848;
gamma_scale, tau_b, EE error within tolerance;
assert no parameters.yaml key reads removed paths
(grep).
TITLE: Resolve the conditioning name
collision BODY: Rename the top-level sampler
conditioning: block to config_sampling: (or
nest under robot:); update robot.sampling
access. Modify: YAMLs_by_domain/parameters.yaml:138‑155,
the sampler loader/consumer. Validation: startup config
search still selects the same q₀ on a fixed seed.
TITLE: Instrument the j_plus path
BODY: Add s_min_J and
j_plus_scale to controller_diagnostics so
D/E/F are observable. Modify: GNC/BreveController.py:528‑535.
Validation: new keys appear in the npz; finite over a
run.
TITLE: Decide the fate of EE pose-blend (mechanism
G) BODY: It is disabled by
trajectory.conditioning.gamma.floor = 0.0. Either remove
blend_near_singular_Gamma + config, or set a real floor and
validate. Modify / Create: none yet — decision first.
Validation: if removed, coverage/tracking unchanged on
a full run.