Date: Jun 18, 2026 (EDT). Question: the shipped derate γ(σ_G) is named a “speed derate” (current_sota.md §6.3 title; symbol table line 95) but is applied to the control gains, K_e, D_e → γK_e, γD_e. Are these the same thing? If not, which one is right, and why does the code’s choice hold the singularity floor while the literal “speed derate” collapses it?
regen:
/Users/antoniahoffman/miniforge3/envs/new-pin-env/bin/python validation/test_derate_mechanism.py
(every algebraic claim below is a passing pin in that file; the
empirical numbers are the committed cascade A/B,
analysis.speed_derate_study logs/logs_Jun18_26 speed_derate_cascade,
HEAD 8bef81a+).
Verdict up front. They are not the same operation, and the difference is decisive:
So §6.3’s title and the symbol table are a misnomer: γ is an impedance derate that produces an emergent slowdown, not a commanded one. The fix is a rename (§4 below), and the cascade A/B is the receipt.
Vocabulary (derate, DLS, σ engagement bands) is in
wiki/terminology.md.
The singularity proximity scalar is σ_G ≡ σ_min(Γ) (current_sota.md
§6, Spearman ≥ 0.997 with σ_min(J⁺)). The ramp γ(σ_G) ∈ [0.25, 1] (eq
6.4) is the same in both cases — scale_by_svd
(utils/sampling.py:70). What differs is what γ
multiplies:
| operation | code site | which equation γ enters | |
|---|---|---|---|
| Impedance derate (shipped) | K_e, D_e → γK_e, γD_e | arm_breve_gains
GNC/breve_controller.py:420; base (new)
base_breve_gains :425 |
the stiffness term −Jᵀ(γK̆)x̃ in the closed loop (eq 4.12), hence the lag floor (eq 4.14) |
| Speed derate (the name’s literal reading) | ν_e → γν_e | derate_twist_by_gamma
GNC/guidance/ee_guidance.py:216 |
the commanded velocity v in the amplification bound (eq 6.1) |
The impedance derate touches the force the arm applies; the speed derate touches the target it chases. That distinction is the whole story.
The quasi-steady cruise-lag error (current_sota.md eq 4.14, computed
by the controller’s own cruise_lag_floor,
GNC/guidance/analytic_feedforward.py) is
\[ \tilde{\boldsymbol{x}}_{ss}=-\big(\boldsymbol{J}_{\tilde{x}}^{\top}\breve{\boldsymbol{K}}\big)^{-1}\,\boldsymbol{b}, \qquad \boldsymbol{b}=\breve{\boldsymbol{C}}\breve{\boldsymbol{v}}_d+\big(\boldsymbol{C}_c+\breve{\boldsymbol{D}}\breve{\boldsymbol{G}}_{v_c}\big)\dot{\tilde{\boldsymbol{x}}}_c . \]
The forcing b carries no K. So scaling the stiffness K̆ → γK̆ gives, exactly,
\[ \tilde{\boldsymbol{x}}_{ss}(\gamma)=-\big(\boldsymbol{J}_{\tilde{x}}^{\top}\gamma\breve{\boldsymbol{K}}\big)^{-1}\boldsymbol{b} =\tfrac{1}{\gamma}\,\tilde{\boldsymbol{x}}_{ss}(1). \tag{lag scales 1/γ} \]
At the derate floor γ = 0.25 the lag grows 4×. But the restoring wrench is γ-invariant:
\[ \boldsymbol{w}(\gamma)=\boldsymbol{J}_{\tilde{x}}^{\top}(\gamma\breve{\boldsymbol{K}})\,\tilde{\boldsymbol{x}}_{ss}(\gamma) =\boldsymbol{J}_{\tilde{x}}^{\top}(\gamma\breve{\boldsymbol{K}})\cdot\tfrac{1}{\gamma}\tilde{\boldsymbol{x}}_{ss}(1) =\boldsymbol{J}_{\tilde{x}}^{\top}\breve{\boldsymbol{K}}\,\tilde{\boldsymbol{x}}_{ss}(1)=\boldsymbol{w}(1). \tag{wrench γ-invariant} \]
Both identities are pinned
(test_gain_derate_scales_lag_by_inverse_gamma,
test_gain_derate_leaves_the_restoring_wrench_invariant).
The reading: reduced authority, same force. The arm
settles at a slacker equilibrium (larger trailing lag) but is pushed
there by the same gentle restoring wrench that just balances
the cruise’s Coriolis forcing C̆v̆_d. It has no extra drive toward
the singular (full-extension) direction — it relaxes rather
than fights. That is the “natural slowdown near singularities” the sheet
describes (eq 6.4 commentary): an emergent slowdown from the
larger lag, never a commanded one. Empirically the gain variant holds
min s_min_J at 0.0268 with γ engaging to a 0.58 median.
The velocity reconstruction from the SVD Γ = Σ sᵢ uᵢ vᵢᵀ amplifies by 1/sᵢ (current_sota.md eq 6.1):
\[ \boldsymbol{x}=\sum_i\frac{\boldsymbol{u}_i^{\top}\boldsymbol{z}}{s_i}\boldsymbol{v}_i \quad\Longrightarrow\quad \lVert\boldsymbol{x}\rVert\le\frac{\lVert\boldsymbol{z}\rVert}{\sigma_{\min}(\boldsymbol{\Gamma})}=\frac{v}{\sigma_{\min}}, \]
with equality when z aligns with u_min, the dying
left-singular direction (both pinned:
test_velocity_reconstruction_obeys_the_sigma_min_bound,
test_bound_is_tight_along_the_dying_direction). The bound
is tight, not conservative — exactly the directions a
near-singular trajectory excites.
Now throttle the command, v → γv. The bound becomes γv/σ_min —
naively safer. But the throttle does not act on σ_min, and here
is the trap: a throttled EE cannot hold the target against the
full-speed orbit, so its pose error grows; the retained full stiffness K
closes that error by extending the arm; extension crashes
σ_min. The denominator moves far more than the numerator.
Quantify it from the committed A/B
(speed_derate_cascade_{gain,speed}): the speed variant’s
net velocity bound relative to the gain variant is
\[ \frac{\gamma\,v/\sigma_{\text{speed}}}{v/\sigma_{\text{gain}}} =\gamma\,\frac{\sigma_{\text{gain}}}{\sigma_{\text{speed}}} =0.25\times\frac{0.0268}{1.04\times10^{-5}}\approx 644 . \]
So the 4× throttle leaves the speed variant’s worst-case joint-rate
bound ≈644× worse, not safer
(test_speed_derate_throttle_is_overwhelmed_by_the_sigma_collapse).
The realized trajectory confirms the mechanism
(analysis.lockin_fingerprint, CLAIMS ~16:00): during the
near-singular episode the arm is not frozen — q̇ runs
2.27× the healthy rate and reach is
1.14× higher. The throttle causes the
over-extension it was meant to prevent. Speed-derate is
falsified: min s_min_J 0.0268 → 1.0e-5, nsf 0.77%.
The math says the operation is correct (impedance derate
holds the floor); only the label is wrong. Proposed edits to
GNC/equations/current_sota.md:
derate_impedance_vs_speed.md.This is the inconsistency the project flagged as indefensible: a name asserting one mechanism (commanded slowdown) over code that runs another (impedance softening). Renaming makes the sheet defensible without touching a single control gain.
γ·τ_b^⊕
via base_breve_gains,
GNC/breve_controller.py:425) moves the arm floor by
+0.1% — i.e. nothing — while degrading base pointing
z_b by +23%. The base gain-derate is
internal-consistency-only (γ now genuinely scales the base K/D block in
the RHS, so the previously logged-but-inert wrench is no longer a
phantom); recommend controller.base.derate.gain stay
default-off.test_singularity_floors.py). They size when the
impedance derate engages; this document explains why engaging
it that way (gains, not command) is the floor-holding choice.validation/test_derate_mechanism.py (5 pins,
all PASS).analysis/speed_derate_study.py (cascade A/B
table + gain-vs-gainbase line);
analysis/lockin_fingerprint.py (amplification fingerprint);
analysis/crossbox_check.py (Δ=0.0000).GNC/equations/current_sota.md §4.3–4.5
(closed loop, eq 4.14), §6.1 (bound), §6.3 (the ramp).generated_reports/GNC/Jun18_26/derating_Jun18.md (one γ,
three application sites).generated_reports/math/threshold_derivation.md.