Files
foxhunt/docs
jgrusewski dc3f948ee9 feat(sp14): B.10 — backward wire gradient gating by ALPHA_GRAD_SMOOTHED
Critical safety mechanism that completes the EGF pearl: scales the wire
column of `dL/dx_concat [B, SH2 + 1]` (the gradient flowing FROM the
direction Q-head's first FC SGEMM TO `aux_softmax_diff`) by
`ISV[ALPHA_GRAD_SMOOTHED_INDEX = 393]`, computed by B.4's
`alpha_grad_compute_kernel` and orchestrated per-step in B.11.

`dL/dW[wire_col]` (Q-head's own weight gradient for the appended column)
is NOT scaled — the dW SGEMM `dY^T × x_concat` and the dX SGEMM
`dY × W^T` are independent, so scaling `dx[:, SH2]` AFTER both have
completed leaves dW unaffected. Q-head learns to USE the wire freely;
only the gradient PROPAGATING BACK to aux is gated.

Pre-B.11 (no producer wired) `ISV[393]` holds sentinel `0.0` →
wire force-closed (gradient zeroed) — the conservative safety state.
Post-B.11, B.4 writes the live gate output ∈ [0, 1] each step.

Closes the latent K-mismatch B.8/B.9 left in backward
============================================================

B.8 grew `w_b0fc` to `[adv_h, SH2 + 1]` end-to-end (Adam m/v +
spectral-norm vector + smoke fixtures); B.9 closed the forward dispatch
K-mismatch. The backward dW/dX SGEMMs for `d == 0` still used `K = SH2`
against the new `LDA = SH2 + 1` weight tensor — silently dropping the
last column of dW and zeroing the wire-col gradient. B.10 closes that
gap atomically with the wire-col scale per `feedback_no_partial_refactor`:

  * `backward_branch_dw` for `d == 0` now uses `(dir_qaux_concat_ptr, SH2 + 1)`
    instead of `(save_h_s2, SH2)` — matching the forward consumer
    pattern from B.9.
  * `backward_branch_dx` for `d == 0` now writes to
    `d_dir_qaux_concat [B, SH2 + 1]` with `K = SH2 + 1` instead of
    `scratch_d_h_s2 [B, SH2]` with `K = SH2`. Mirrors the magnitude
    branch's wider-buffer pattern.

New artifacts
=============

  * `sp14_scale_wire_col_kernel.cu`: one thread per batch row, scales
    `dx_concat[b, SH2]` by `isv[393]` IN-PLACE. NaN-safe per the
    `dqn_scale_f32_kernel` precedent (explicit `α==0 ⇒ 0` branch).
    Pure per-thread map, no atomicAdd, no shared memory.
  * `sp14_d_dir_qaux_concat: CudaSlice<f32>` `[B, SH2 + 1]` trainer-
    struct field. Dx SGEMM destination; the wire-col scale acts on
    this buffer; the strided accumulator copies the first SH2 columns
    into `bw_d_h_s2` after the scale.
  * `launch_sp14_scale_wire_col` launcher reads `self.isv_signals_dev_ptr`
    and the new buffer's raw_ptr.
  * `backward_full` signature grows two trailing `u64` args
    (`dir_qaux_concat_ptr`, `d_dir_qaux_concat_ptr`); both
    `backward_full` call sites (CQL aux + main online) wired
    atomically per `feedback_no_partial_refactor`.

Post-call orchestration at trainer level
========================================

  1. `launch_sp14_dir_concat_qaux(save_h_s2)` rebuilds the ONLINE
     concat in `sp14_dir_qaux_concat_scratch` (the forward pass had
     overwritten it with the TARGET concat at line ~25817). Same
     one-step-lag semantic preserved — `aux_nb_softmax_buf` is
     unchanged between forward and backward.
  2. `cuMemsetD32Async` zero of `d_h_s2` — pre-B.10 the direction
     branch (d==0) wrote it with beta=0; post-B.10 the dir-Q dX
     lives in `d_dir_qaux_concat` and is gated + accumulated AFTER
     `backward_full` returns, so the value-FC dx accumulator inside
     `backward_full` (beta=1) needs an explicit zero baseline.
  3. `backward_full` runs: dir branch → `d_dir_qaux_concat`,
     mag/ord/urg branches → their concat dX buffers, value-FC →
     `d_h_s2` (beta=1, on top of zeroed buffer).
  4. `launch_sp14_scale_wire_col` gates col SH2 of `d_dir_qaux_concat`.
  5. `accumulate_d_h_s2_from_concat` (beta=1) copies first SH2 cols
     of `d_dir_qaux_concat` into `d_h_s2`. Wire col stays in
     `d_dir_qaux_concat[:, SH2]`, untouched by this accumulator (its
     destination range is [0, SH2)). Pre-B.11 the wire is already
     zeroed by the sentinel-α gate; the orchestrator that propagates
     the gated wire-col gradient back to the aux head's softmax CE
     backward chain lives in B.11.
  6. mag/ord/urg accumulators continue with beta=1 (comments updated).

Wire status
===========

  * Forward dispatch: unchanged (B.9-complete).
  * Backward dispatch: GATED on both call sites (CQL aux + main online).
  * dW unchanged: the `dW = dY^T × x_concat` SGEMM writes
    `grad_buf[goff_w_b0fc..]` BEFORE the scale-wire-col launches;
    the scale operates ONLY on `d_dir_qaux_concat` (the dx buffer)
    AFTER both dW and dX SGEMMs complete.
  * Target net unaffected: Polyak EMA-only, no backward.
  * CudaSlice wrapper path: passes `0u64` for both new args, falls
    back to the legacy K=SH2 path. Consistent with the forward
    wrapper's diagnostic-only residual.

Verified
========

  * `SQLX_OFFLINE=true cargo check -p ml` clean, 18 warnings (baseline)
  * `cargo test -p ml --test sp14_oracle_tests` 2 passed, 6 ignored (GPU)
  * Audit doc `docs/dqn-wire-up-audit.md` updated per Invariant 7.

After this commit, the EGF pearl is architecturally complete; the
orchestration of when/how the alpha_grad gates fire happens in B.11
(producer chain orchestrator).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 20:49:27 +02:00
..