Legacy texture argument state repair

Implementation completed 2026-10-24 on review revision d84f4da79fce87e80e998d48e6fdb2a11c9961fe, following source candidate 547460d4dfb6966b72cc28c04efac22a809d784f and original baseline 5406777ecbcef9cf9b03b40d592d722bb0086de0. Implementation commit: 79e81ba5c425d6aa1f8506787d7a7c19909dccac. This is the implementation worker's evidence, not independent acceptance or main integration. The earlier capability removal remains subject to coordinator review.

Cause and repair

SetTextureStageState and the loader correctly retained zero-valued DIFFUSE. The GPU descriptor omitted all four argument states, and JS substituted TEXTURE/DIFFUSE for both RGB and alpha. The software triangle caller likewise forwarded only operation numbers to a combiner assuming that fixed pair.

The descriptor now carries COLORARG1/2 and ALPHAARG1/2 at DWORDs 41–44. Its 180 bytes at scratch +64 fit the existing 256-byte allocation (end +244). JS independently lowers all four operands. The software caller packs operand choices into the existing internal raster operation words: low byte D3DTOP, bit 8 ARG1=diffuse, bit 9 ARG2=texture. Both real triangle/span routes preserve these words; the actual combiner resolves RGB and alpha separately before selection/multiplication. Existing raw-operation callers keep their prior TEXTURE/DIFFUSE convention and require no signature change.

The actual device initializer calls a new texture-stage initializer. Stage zero defaults to COLOROP=MODULATE, ALPHAOP=SELECTARG1, ARG1=TEXTURE and ARG2=CURRENT for both channels; later color stages default to DISABLE. CURRENT at stage zero is the incoming diffuse value. Explicit DIFFUSE=0 stays a real selector; zero is never used to mean an unset argument. The one necessary change outside the core/GPU files wires this initializer into d3ddev_init_state in the DirectX handler file.

Verification

test/test-legacy-texture-operation-caps.js --negative-controls passes:

The independent argument-reproducer.js is retained byte-for-byte, checked against its sealed review Git blob. It passes this repair: stored and lowered COLORARG1/ALPHAARG1 are both zero. It rejects the retained exact original baseline with the original SELECTARG1 assertion. Baseline execution temporarily uses the original baseline GPU source and baseline WAT, then verifies restoration of the repaired JS; the producer fixture itself retains its baseline-rejection oracle. The reproducer's textual loweredSelectionRGBA field is a hardcoded historical diagnostic, not a recomputed pixel; its actual assertions concern lowered selectors. The expanded test supplies independent pixel evidence.

GPU batching and points regressions also pass. Exact commands, preflight, compiler absolute paths/Git blobs/full SHA-256, excerpt byte ranges/line ranges, ordering and assembled identities are retained in the adjacent evidence. The preflight runs before compilation and reuses verified unchanged compiler blobs. Each Wasm fixture uses one 64 KiB memory; Node heap is exactly 256 MiB, wall/CPU 60 seconds and admission requires MemAvailable >=805306368. Allocation/device lookup imports are fixture doubles, unrelated paths trap if unexpectedly used.

Remaining semantics and qualification

This implements stage-zero DIFFUSE/TEXTURE operand selection for the three specified operations, with CURRENT's stage-zero diffuse equivalence for defaults and explicit CURRENT. It does not establish later-stage CURRENT or multitexture semantics. TFACTOR, SPECULAR, TEMP, CONSTANT, other selectors, COMPLEMENT (0x10) and ALPHAREPLICATE (0x20) remain unsupported. The GPU declines them; software retains its old operand fallback for these unsupported values. Neither path claims correct modifier behavior. Unsupported operations still take the legacy MODULATE fallback, including the independently identified COLOROP=DISABLE defect. No capability mask was weakened or changed by this repair. Passing these tests does not certify the remaining mask as universally truthful.

Source/small authentic excerpt qualification only: no full COM, 512 MiB native guest, default/full build, browser/WebGL pixels, native suite or gameplay was run or claimed. No packages/downloads/workers/boxes were used. Box ID/state/ expiry N/A; coordinator owns lifecycle and all prior boxes remain stopped. Shadow Man's 128 MiB/runtime403 and the separate fixture's historical-accounting holds are unchanged. The root tracked tree/index/refs and held D3D fixture directory were not used for changes or integration.

Accounting and recovery

This continues the original 64 MiB independent-review allocation and original SQLite baseline. Both existing private directories, all named task output and prompt/launch files, predecessor/current session identities, positive cumulative SQLite/WAL/SHM growth and old highwaters remain counted. The initial 553886-byte charge was retained, including the earlier bootstrap and disclosed inspection exceptions; this report does not claim pristine prior compliance. Historical guard.py, targeted-guard.py and blocker receipts remain unchanged. The new implementation-guard.py preserves CAP=786432 and extends accounting roots and sessions, with before/after hash receipts. See the final resource receipt for measured/projected bytes and cumulative capture, including measured outer output.

Routine fixture corrections (authentic helper dependencies, global types, color write mask and ARGB texture format) were completed in this task. Required instruction reads used the authorized measured cap. Several focused code/board inspections exceeded an internal command slice; their charged bounded output and cleanup receipts remain, and subsequent reads were narrowed. These were internal slicing corrections, not cumulative allocation/memory/capture denials. No cumulative guard was reset or weakened. An isolated 32-byte capture rejection left its sentinel absent and verified owned-process-group cleanup. All retained execution receipts include TERM/5-second/KILL cleanup verification.

Recovery uses /tmp/legacy-texture-operation-caps-oct23/repo and /tmp/legacy-texture-caps-independent-accept-oct23. The latter retains the original baseline WAT/reproducer, continuation guards/contracts, compiler/excerpt preflights, baseline driver, guard control, manifests and execution.jsonl. Run python3 .../g.py cheap node --max-old-space-size=256 test/test-legacy-texture-operation-caps.js --negative-controls from the private checkout, setting LEGACY_CAPS_RECEIPT as needed; first refresh the manifest-only receipt and run implementation-preflight.py. Independent reproduction uses REPRO_RECEIPT and the unchanged argument-reproducer.js. The baseline driver implementation-baseline.py serializes the temporary original JS substitution and restores the candidate in finally. Do not run accounting writers concurrently. Raw ignored artifacts are retained locally; Git evidence and these recipes are the remote recovery record. Only the task branch is published; no main merge.