2026-09-02 - (/loop) Packed typed-buffer FLOAT16 load: driver-widened halves, GPU-verified

Increment 4 of the narrow-format work (D466), and the first that is a float in memory rather than an integer normalised into one: a 16-bit IEEE half widened to a 32-bit float. Also the first that needed new module-level infrastructure, so the approach got its own decision - D467.

The three-way choice (D467). Half->float can go through a hand-rolled bit-unpack, a GLSL ext-inst (UnpackHalf2x16), or a real 16-bit float type widened by OpFConvert. Chose OpFConvert: the driver's own IEEE conversion, correct for subnormals/inf/NaN, three instructions, and no shared-header surgery. The manual unpack was rejected because its subnormal path silently reads zero without DenormPreserve (not declared here); the ext-inst route was rejected as more shared infrastructure for no better an answer (it will come back for SRGB's pow, and FLOAT16 can move onto it then if there is ever a reason).

clippy (lib and --tests) and fmt clean; spirv (15) and translate (108 execute + 13 + 2) suites green; all five earlier packed tests and the refusal gate unchanged.

Five kinds now translate (UINT, SINT, UNORM, SNORM, FLOAT16). Next: SRGB (increment 5) - the sRGB transfer curve, x < 0.04045 ? x/12.92 : pow((x+0.055)/1.055, 2.4) applied to the UNORM value. pow has no core SPIR-V op, so this is where the GLSL ext-inst plumbing D467 deferred finally has to land: OpExtInstImport "GLSL.std.450" (a header slot between OpExtension and OpMemoryModel - the one shared change avoided so far) + an OpExtInst emit path and its SHAPES row, then GLSL Pow (26). The linear segment and the select are already-available ops. Then packed stores, then multi-word widths.