Worked: Start from what absmean actually is. Take any trained layer W. The scale is a single number, the mean absolute weight: scale = np.mean(np.abs(W)). For W ~ N(0, sigma) (sigma = std) this equals sigma * sqrt(2/pi) ~= 0.798 * sigma. Now W/scale has mean absolute value 1 by construction — so round(W/scale) sends the smallest-magnitude weights (those with |W| < scale/2) to 0, and everything else to +/-1 (with clip catching the rare tail beyond 1). That scale/2 threshold is why the zero fraction lands near 0.31 for Gaussian weights regardless of sigma: the absmean rule is scale-invariant.
Your turn: The starter divides by a hard-coded scale = 1.0. Trained weights are small (here std 0.4), so round(W/1.0) pushes ~79% of them to zero — the matrix nearly vanishes and the grader's sparsity check fails. Replace the 1.0 with the absmean statistic so the scale tracks the actual weight magnitude.
Independent: Confirm the two things that make this a valid ternarization: (1) set(np.unique(Wq)) is a subset of {-1,0,1} — the clip(...,-1,1) guarantees no +/-2 leaks through from the round; (2) the reported zero_fraction lands in the 0.2-0.45 band. Then read recon_error and ask yourself why a lossy reconstruction can still be "enough" — that tension is the setup for QAT.