# G-172 Distributed binaries declare a CPU floor - no shipped artifact is tuned to its build host Status: proposed Scope: src/buildsuites/suite_tcl90/build905.zig and src/buildsuites/suite_tcl86/build86.zig (flagless target/cpu resolution defaults); src/tools/punkzip/build.zig and src/tools/punkres/build.zig (distributed build-path tools); src/buildsuites/suite_tcl90/tools/family_artifacts.tcl (artifact record emission - the recorded floor field); punkbin artifact repo (external c:/repo/jn/punkbin - win32-x86_64/*.toml sidecars, defaults.txt curation); bin/ (the shipped zig-built exes); src/scriptapps/bin/punk-runtime.* (floor reporting on fetch, floor-vs-host verdict on use/run); scriptlib/developer/ (cpu-floor audit tool) Goal: Every binary this project distributes runs on any CPU meeting a declared instruction-set floor - the floor is a property of the build recipe rather than of whichever machine happened to run it, it travels with the artifact in its metadata record, and neither a build nor a publication can silently ship host-tuned code. Acceptance: A flagless build of each distributed-artifact recipe (suite_tcl90, suite_tcl86, punkzip, punkres) on an AVX-512-capable host emits zero instructions above the declared floor - verified by an audit tool that disassembles the produced binaries and reports out-of-floor instructions, carrying the current AVX-512 regression as its fixture; `-Dcpu=native` still yields a host-tuned local build, proving the floor is a default and not a restriction; each published artifact's metadata record states the floor it was built to and punk-runtime surfaces it; and selecting or launching a runtime whose recorded floor the local CPU does not meet produces a named diagnosis instead of a silent 0xC000001D, while fetching for any platform stays ungated. ## Context Reported 2026-08-06: on a freshly pulled checkout, `bin/punk-runtime.cmd fetch` with no runtime name retrieved the curated default `tclsh9.0.5-punk-r2.exe`, which exited immediately with no prompt, no error and no output. Two other runtimes fetched onto the same machine (`tclsh902z.exe`, `tclsfe-x64.exe`) started normally. The failure was initially read as a Windows-version difference (25H2 works, 23H2 does not). It is not an OS difference. Disassembling `.text` of the artifacts: | artifact | zmm sites | ymm sites | built by | |---|---|---|---| | `tclsh9.0.5-punk-r2.exe` | 2756 | 617 | zig 0.16.0, ReleaseFast | | `tclsh9.0.5-r2.exe` (plain) | 2756 | 617 | zig 0.16.0, ReleaseFast | | `tclsh902z.exe` | 0 | 0 | BAWT / MSYS2 mingw GCC | | `tclsfe-x64.exe` | 0 | 0 | apnadkarni MSVC | The 9.0.5 binaries carry real EVEX-encoded AVX-512 - `vmovdqu64`, `vpscatterqq`, `vpermt2q`, `vpmovm2q`, `vptestnmq`, `vshufi64x2` - with the first site at RVA 0x2360, the very front of `.text`. Tcl has no runtime CPU dispatch, so none of it is guarded. On a CPU without AVX-512 the first one raises #UD and the process is killed with STATUS_ILLEGAL_INSTRUCTION (`0xC000001D`, errorlevel -1073741795) before Tcl writes a byte. Confirmed against the reporting fleet - the split is exactly the AVX-512 line: | host | CPU | uarch | AVX-512 | 9.0.5 runtime | |---|---|---|---|---| | is-vmhost-1 (Win11 23H2) | TR PRO 3955WX | Zen 2 | no | dies, errorlevel -1073741795 | | jcross1 (Win11) | Ryzen 5 7600X | Zen 4 | yes | works | | build/dev box (Win11 25H2) | TR PRO 9955WX | Zen 5 | yes | works | Cause: the recipes called `b.standardTargetOptions(.{})` and no build path passed `-Dtarget`/`-Dcpu`. With no flag, zig resolves cpu_model `determined_by_arch_os` by NATIVE detection; on a Zen 5 host that is `znver5`, and `ReleaseFast` then auto-vectorises freely. Measured with the bundled 0.16.0-dev zig on an auto-vectorisable C loop: flagless -> `znver5`, zmm=805; `-Dcpu=native` -> `znver5`, zmm=805; `-Dtarget=x86_64-windows` -> `x86_64`, zmm=0; `-Dcpu=baseline` -> `x86_64`, zmm=0; `-Dcpu=x86_64_v2` -> `x86_64_v2`, zmm=0. The class is wider than the runtime family. Every zig-built binary the project distributes inherits its build host's instruction set: - all six published `tclsh9.0.5-*` artifacts (punk + plain, r1 + r2, both `-bi-` variants): 2756 zmm each - the whole family, so there is no 9.0.5 fallback to fetch instead; - `bin/punkzip.exe` 1724 zmm, `bin/punkres.exe` 1423 zmm - both build-path tools, so a `bake` on a non-AVX-512 machine dies too; - `bin/punk905.exe`, `punk9-dev.exe`, `punk9_beta.exe`, `punk9bi_beta.exe`, `punkdeclare.exe`, `punkfiledemo.exe`: 2756 zmm; - an older generation (`punk901*.exe`, `punk9.exe`, `xcritcl.exe`, `tclsh90s*.exe`, `mkzipfix.exe`) carries ~4500 ymm sites and no AVX-512 - AVX2-only, from an earlier build host. Same defect, milder floor. Two things make this worse than a portability nit. The artifact record already carries `toolchain`, `optimize` and six source-checkout digests but says nothing about the instruction set, so the one fact that determines whether the binary can execute is the one fact not recorded. And punkbin `defaults.txt` points `win32-x86_64` at `tclsh9.0.5-punk-r2.exe`, so a flagless fetch on a fresh checkout hands every non-AVX-512 machine a dead default runtime - the project's first contact with a new user fails with no message at all. ## Approach 1. Recipe default, not a build-command convention. `standardTargetOptions` takes `.{ .default_target = .{ .cpu_model = .baseline } }`, so a flagless build is portable and `-Dcpu=native` is the opt-in for a host-tuned local build. "Remember to pass `-Dcpu=` when publishing" is precisely what failed silently for six artifacts and four recipes; the default is what publishes. (Applied 2026-08-06 to all four recipes - see Progress.) 2. Floor choice: `baseline` (x86-64 v1) for the x86_64 family (user decision 2026-08-06). For a Tcl interpreter the codegen delta against v2/v3 is negligible against the cost of the default runtime failing to start. The win32-ix86 lane (G-130) makes the same choice on its own axis. 3. Record the floor in the artifact metadata: `[provenance]` gains the resolved cpu model and the floor the recipe declared, emitted by `family_artifacts.tcl` alongside `toolchain`/`optimize`, and carried in both the embedded record and the sidecar toml. 4. Audit tool in `scriptlib/developer/` (the advisory-tool tier): disassemble a binary, classify instructions against a named floor, report anything above it. The current AVX-512 artifacts are its fixture - the tool must flag them and must pass a rebuilt one. This is what makes the acceptance criterion measurable rather than a promise about build habits. 5. punk-runtime surfaces the floor, gating only where execution is implied. `fetch` stays ungated and reports the floor as information - fetching for another platform (`-platform
`) is a normal cross-machine workflow and a
local-CPU verdict would be meaningless there (user point 2026-08-06). The
actionable moment is selection and launch: `use` and `run` are already the
local-only actions (`run` explicitly takes no `-platform` because "foreign
binaries are not runnable here"), so that is where a floor the host does not
meet becomes a named diagnosis. `list` annotates rows the local CPU cannot
run.
6. Republication is IN-SITU replacement (user decision 2026-08-06): rebuilt
binaries replace the unsuitable artifacts under their existing names and
revisions, with sidecar tomls and `sha1sums.txt` regenerated to match.
Artifact immutability remains the long-term intention but is explicitly
violable during alpha - every consuming system is in-house, there are no
third-party users, and leaving known-dead binaries fetchable is the worse
outcome. No `defaults.txt` repoint is needed (it already names
`tclsh9.0.5-punk-r2.exe`). Replacement may proceed as soon as a rebuilt
binary passes the zmm audit; if the floor field (Approach 3) is not yet in
the record schema, a second in-situ record refresh adds it later - cheap
under the same dispensation.
## Alternatives considered
- Pass `-Dcpu=baseline` at publish time only, leaving recipes native by default
- rejected: it is the same unenforced convention that produced the defect,
and it makes a developer's local build and the published artifact differ in a
way nothing checks.
- `x86_64_v2` or `x86_64_v3` floor - deferred, not rejected. v2 (SSE4.2/POPCNT,
2008+) excludes nothing realistically in service; v3 (AVX2/BMI2, 2013+)
excludes Intel N-series/Pentium Silver, which have no AVX at all. Revisit per
artifact class if a measured win justifies it; the recipe already accepts
`-Dcpu=