Browse Source

G-172 (active): record + surface + audit the distributed-binary CPU floor

Approach 3 (record floor field): build905.zig declares cpu_floor="baseline"
beside the default_target pin and writes cpu_floor + cpu_model into each
family member's embedded record [provenance] (= target.result.cpu.model.name,
so "x86_64" for the default build, "znver5" for -Dcpu=native - the floor is a
default, not a restriction). family_artifacts.tcl derives both from the
embedded record (G-117 single-source-of-truth) into the sidecar [provenance],
failing if absent; family_check.tcl asserts them non-empty.

Approach 4 (audit tool): scriptlib/developer/cpufloor_audit.tcl disassembles a
binary's .text via a located objdump (llvm-objdump preferred, GNU fallback) or
audits a pre-disassembled excerpt, classifies by AVX register width (zmm=v4,
ymm=v3; baseline/v2 forbid both, v3 forbids zmm, v4 allows all), reports
out-of-floor count + first RVA + sample mnemonics, exit 0 PASS / 1 FAIL.
Bundled fixtures in cpufloor_fixtures/ are real disassembly excerpts (avx512,
avx2, clean); selftest 12/12 cases pass. Verified on real binaries: rebuilt
bin/punkzip.exe PASS (zmm=0); a -Dcpu=native probe FAILs at baseline (123 zmm)
and PASSes at v4.

Approach 5 (punk-runtime surfacing): both .ps1 and .bash twins updated and
re-wrapped. Host CPU level detection (PS via IsProcessorFeaturePresent PF
SSE2=10/SSE4.2=38/AVX2=40/AVX512F=41; bash via /proc/cpuinfo flags) feeds a
meets/below/unknown/norecord verdict. fetch prints cpu floor (UNGATED - a
cross-platform fetch for another machine stays free); list annotates rows the
host cannot run (!CPU-FLOOR:v<req>, local rows only); use/run gate on below
with a named diagnosis instead of a silent STATUS_ILLEGAL_INSTRUCTION
(0xC000001D) - the 2026-08-06 AVX-512 regression failure mode; info adds the
fields. bin/punk-runtime.cmd re-wrapped (deterministic;
scriptwrap_runtime_cmd_roundtrip_no_drift test PASSES).

Activation: overlap survey re-run at activation (goals_xref score G-172) - no
goals drafted in the interval; existing Related: notes cover every pair.

Project version 0.57.0 -> 0.57.1 (patch - user-visible punk-runtime behaviour
shipped in kits). Remaining for acceptance: rebuild + republish in-situ (per
Approach 6's alpha dispensation) and audit the republished artifacts to confirm
zmm=0 - a publication-time, user-owned step.

Assisted-by: harness=pi; primary-model=huggingface/zai-org/GLM-5.2; api-location=huggingface.co
master
Julian Noble 3 days ago
parent
commit
8f446690c1
  1. 2
      AGENTS.md
  2. 16
      CHANGELOG.md
  3. 2
      GOALS.md
  4. 283
      bin/punk-runtime.cmd
  5. 67
      goals/G-172-distributed-binary-cpu-floor.md
  6. 2
      punkproject.toml
  7. 276
      scriptlib/developer/cpufloor_audit.tcl
  8. 32
      scriptlib/developer/cpufloor_fixtures/avx2.dis.txt
  9. 70
      scriptlib/developer/cpufloor_fixtures/avx512.dis.txt
  10. 70
      scriptlib/developer/cpufloor_fixtures/clean.dis.txt
  11. 17
      src/buildsuites/suite_tcl90/build905.zig
  12. 13
      src/buildsuites/suite_tcl90/tools/family_artifacts.tcl
  13. 8
      src/buildsuites/suite_tcl90/tools/family_check.tcl
  14. 125
      src/scriptapps/bin/punk-runtime.bash
  15. 158
      src/scriptapps/bin/punk-runtime.ps1

2
AGENTS.md

@ -214,7 +214,7 @@ The project version is fully independent of module versions. A module bump (even
- `TEMP_REFERENCE/` - Reference-only material for agents, not a work folder; ignored by both git and fossil, so its contents (including its AGENTS.md) are machine-local and unversioned. Holds the nested fossil checkout of the Tcl core sources at `TEMP_REFERENCE/tcl9`, which must stay on `trunk` per the fossil branch-discipline rule in User Preferences (see TEMP_REFERENCE/AGENTS.md when present)
- Directories agents should not directly modify (no child DOX needed):
- `callbacks/` — Experimental shellspy features, user-only
- `scriptlib/` — Shared utilities + manual tests, user-only. EXCEPTIONS: `scriptlib/_punktest/` is test-owned (fixtures for `src/tests/shell/testsuites/punkexe/scriptexec.test`, resolved via `lib:_punktest/<name>`); agents may manage that subfolder as part of test work. `scriptlib/developer/` holds agent-authored developer showcase/demo apps and developer utility scripts (created at user request 2026-07-11, e.g `tkconsole_demo.tcl` for the G-001 tk console backend, `goals_lint.tcl` for the goals doc contracts per goals/AGENTS.md Verification, `goals_xref.tcl` goals cross-reference/scope-overlap analysis (unlinked overlap pairs, path-intersection queries, dangling refs) per goals/AGENTS.md Verification, `whatis.tcl` runtime command introspection backing the `tcl-whatis` agent skill, `nslist.tcl` runtime namespace/package discovery backing the `tcl-nslist` agent skill, `runtests_parity.tcl` comparing `runtests.tcl -report json` outputs for result parity between runner modes per src/tests/AGENTS.md Verification, `architecture_lint.tcl` validating root `ARCHITECTURE.md` references - path existence, goal-id resolution, size budget, `assetorigin_check.tcl` classifying assets against their `*.assetorigin.toml` provenance sidecars per the format in `src/assets/logo/AGENTS.md` - six advisory states, fixture selftest, plain tclsh); agents may add or update entries there when the user asks for one. The rest of `scriptlib/` stays user-only.
- `scriptlib/` — Shared utilities + manual tests, user-only. EXCEPTIONS: `scriptlib/_punktest/` is test-owned (fixtures for `src/tests/shell/testsuites/punkexe/scriptexec.test`, resolved via `lib:_punktest/<name>`); agents may manage that subfolder as part of test work. `scriptlib/developer/` holds agent-authored developer showcase/demo apps and developer utility scripts (created at user request 2026-07-11, e.g `tkconsole_demo.tcl` for the G-001 tk console backend, `goals_lint.tcl` for the goals doc contracts per goals/AGENTS.md Verification, `goals_xref.tcl` goals cross-reference/scope-overlap analysis (unlinked overlap pairs, path-intersection queries, dangling refs) per goals/AGENTS.md Verification, `whatis.tcl` runtime command introspection backing the `tcl-whatis` agent skill, `nslist.tcl` runtime namespace/package discovery backing the `tcl-nslist` agent skill, `runtests_parity.tcl` comparing `runtests.tcl -report json` outputs for result parity between runner modes per src/tests/AGENTS.md Verification, `architecture_lint.tcl` validating root `ARCHITECTURE.md` references - path existence, goal-id resolution, size budget, `assetorigin_check.tcl` classifying assets against their `*.assetorigin.toml` provenance sidecars per the format in `src/assets/logo/AGENTS.md` - six advisory states, fixture selftest, plain tclsh, `cpufloor_audit.tcl` the G-172 distributed-binary CPU-floor audit instrument (disassembles a binary's .text via a located objdump, or audits a pre-disassembled excerpt, and reports AVX-register-width instructions above a declared floor; bundled real-disassembly fixtures in `scriptlib/developer/cpufloor_fixtures/` + a `-selftest`); agents may add or update entries there when the user asks for one. The rest of `scriptlib/` stays user-only.
- `bin/` — Built binaries and helpers, build output target. This includes the polyglot `.cmd` launcher/utility scripts (e.g `bin/punk-runtime.cmd`): they are GENERATED by the punk::mix scriptwrap machinery from sources under `src/scriptapps/` — a request to "fix bin/<name>.cmd" means editing `src/scriptapps/<name>.*` + `<name>_wrap.toml` and re-wrapping (see bin/AGENTS.md), never editing the output
- `modules/` (root) — Build output target for `tclsh src/make.tcl modules`
- `lib/` (root) — Build output target for `tclsh src/make.tcl libs`

16
CHANGELOG.md

@ -5,6 +5,22 @@ The latest `## [X.Y.Z]` header must match the `version` field in `punkproject.to
Entries are newest-first; one bullet per notable change. See the root `AGENTS.md`
"Project Versioning" section for the bump policy.
## [0.57.1] - 2026-08-07
- punk-runtime surfaces a recorded CPU instruction-set floor and gates launching a
runtime the local CPU cannot run (G-172). A runtime's artifact metadata toml
now carries `cpu_floor` (the recipe's declared default floor) and `cpu_model`
(the build's resolved CPU model); `fetch` reports them (ungated - a
cross-platform fetch for another machine stays free), `list` annotates rows the
host cannot run (`!CPU-FLOOR:v<req>`), `use`/`run` abort with a named diagnosis
instead of a silent STATUS_ILLEGAL_INSTRUCTION (0xC000001D), and `info` shows
the fields. The suite_tcl90 kit-family record writes the floor into each
artifact's `[provenance]`, and a new codegen audit tool
`scriptlib/developer/cpufloor_audit.tcl` disassembles a binary and reports
instructions above the declared floor (the acceptance instrument for the
AVX-512 host-tuning regression). Floor-bearing published artifacts land at
the next republication.
## [0.57.0] - 2026-08-06
- Recognised-but-unavailable documentation landings are now surfaced distinctly

2
GOALS.md

@ -406,7 +406,7 @@ Detail: goals/G-167-punkargs-version-delta-availability.md
Scope: src/make.tcl (bake/bakehouse/vfslibs - VFSPAYLOAD + PACKAGES phases, kit assembly, new explicit materialize/tidy commands); src/make.tcl sync_layouts phase (the mint-side tracked-path write) with its targets src/project_layouts/ and src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/ plus the workflow_text TERMINOLOGY/DIAGRAM 1b stage-verb assignment; src/vfs/ (payload declarations, _targets staging generalization, README.md + AGENTS.md precedence spec); src/_bake (assembly staging); bin/packages (lib-tier consumption); .gitignore + .fossil-settings/ignore-glob (staging ignore coverage); src/tests/shell/testsuites/punkexe/ (kill-probe + precedence characterization)
Detail: goals/G-171-bake-writes-land-untracked.md
### G-172 [proposed] Distributed binaries declare a CPU floor - no shipped artifact is tuned to its build host
### G-172 [active] Distributed binaries declare a CPU floor - no shipped artifact is tuned to its build host
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)
Detail: goals/G-172-distributed-binary-cpu-floor.md

283
bin/punk-runtime.cmd

@ -1527,6 +1527,76 @@ provenance_class() {
}
'
}
#G-172 CPU instruction-set floor surfacing and runnability verdict (ps1
#payload parity). A runtime's toml carries cpu_floor (the recipe's declared
#default floor) and cpu_model (what the build resolved to). host_cpu_level detects
#the local CPU's x86-64 level from /proc/cpuinfo flags (avx512f=v4, avx2=v3,
#sse4_2=v2, sse2=v1); cpu_floor_verdict compares and sets globals so use/run gate
#launching a runtime the local CPU cannot run (a named diagnosis instead of a
#silent STATUS_ILLEGAL_INSTRUCTION 0xC000001D - the 2026-08-06 AVX-512 failure).
#A detection gap (no /proc/cpuinfo) yields level 0 and the verdict never blocks
#on unknown, so a detection failure cannot prevent a launch.
punk_host_cpu_level=""
host_cpu_level() {
[[ -n "$punk_host_cpu_level" ]] && { echo "$punk_host_cpu_level"; return; }
local lvl=0 flags
if [[ -r /proc/cpuinfo ]]; then
flags=$(grep -m1 '^flags' /proc/cpuinfo 2>/dev/null || true)
if printf '%s' "$flags" | grep -qw 'avx512f'; then lvl=4
elif printf '%s' "$flags" | grep -qw 'avx2'; then lvl=3
elif printf '%s' "$flags" | grep -qw 'sse4_2'; then lvl=2
elif printf '%s' "$flags" | grep -qw 'sse2'; then lvl=1
fi
fi
punk_host_cpu_level=$lvl
echo "$lvl"
}
#G-172 map a recorded cpu_model name to an x86-64 level (1..4), or 0 for a
#specific uarch / unknown. A specific uarch (znver5, skylake...) is NOT a level
#- the codegen audit tool (scriptlib/developer/cpufloor_audit.tcl) is the
#authoritative runnability check for those.
cpu_model_level() {
case "$1" in
x86_64) echo 1;;
baseline) echo 1;;
x86_64_v2) echo 2;;
x86_64_v3) echo 3;;
x86_64_v4) echo 4;;
*) echo 0;;
esac
}
#G-172 floor-vs-host verdict. $1 = path to the runtime's toml. Sets globals:
#floor_verdict (meets|below|unknown|norecord), floor_required, floor_host,
#floor_message, floor_cpu_floor, floor_cpu_model. 'below' => recorded codegen
#exceeds the host - the caller MUST NOT launch (would die with 0xC000001D).
#'unknown' => specific uarch or host undetermined: do not block, surface the audit.
cpu_floor_verdict() {
local toml="$1"
floor_cpu_floor=$(sed -n 's/^[[:space:]]*cpu_floor[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$toml" 2>/dev/null | head -n 1)
floor_cpu_model=$(sed -n 's/^[[:space:]]*cpu_model[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$toml" 2>/dev/null | head -n 1)
floor_host=$(host_cpu_level)
floor_required=0; floor_message=""
if [[ -z "$floor_cpu_model" ]]; then
floor_verdict="norecord"; return
fi
floor_required=$(cpu_model_level "$floor_cpu_model")
if [[ "$floor_required" -eq 0 ]]; then
floor_verdict="unknown"
floor_message="cpu_model='$floor_cpu_model' is a specific uarch (not an x86-64 level); runnability is verified by the codegen audit tool: tclsh scriptlib/developer/cpufloor_audit.tcl <runtime> (declared floor: $floor_cpu_floor)"
return
fi
if [[ "$floor_host" -eq 0 ]]; then
floor_verdict="unknown"
floor_message="host CPU level undetermined (/proc/cpuinfo unavailable); recorded cpu_model='$floor_cpu_model' (x86-64 v$floor_required), floor='$floor_cpu_floor' - runnability not verified"
return
fi
if [[ "$floor_host" -lt "$floor_required" ]]; then
floor_verdict="below"
floor_message="runtime built for cpu_model='$floor_cpu_model' (x86-64 v$floor_required) but this CPU is x86-64 v$floor_host - launching it would fail with STATUS_ILLEGAL_INSTRUCTION (0xC000001D). Aborting; use '$0 list' for a runtime this CPU can run."
return
fi
floor_verdict="meets"
}
#G-103 artifact metadata: a runtime may carry a <rootname>.toml beside it (emitted
#by the buildsuite kit-family-artifacts step / fetched from punkbin). Prints a
#short "[variant=... tcl=... rN ...]" summary for list output, "" when absent.
@ -1554,6 +1624,24 @@ metadata_summary() {
#integrity flag: a runtime filed under a platform folder its metadata says it
#was not built for (cross-platform fetch/staging misfiling)
[[ -n "$target" && "$target" != "$archtail" ]] && parts="$parts !TARGET-MISMATCH:$target"
#G-172 CPU floor surface + runnability annotation. floor= is informational; a
#!CPU-FLOOR:v<req> tag marks a row the local CPU cannot run - gated to the
#LOCAL platform only (a foreign-platform row is cross-build staging). Absent
#on pre-G-172 tomls. (runs in a command-substitution subshell - host_cpu_level
#caches only within this call, which is fine.)
local cfloor cmodel cmlevel hlevel
cfloor=$(sed -n 's/^[[:space:]]*cpu_floor[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" 2>/dev/null | head -n 1)
[[ -n "$cfloor" ]] && parts="$parts floor=$cfloor"
if [[ "$archtail" == "$local_platform" ]]; then
cmodel=$(sed -n 's/^[[:space:]]*cpu_model[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" 2>/dev/null | head -n 1)
if [[ -n "$cmodel" ]]; then
cmlevel=$(cpu_model_level "$cmodel")
if [[ "$cmlevel" -gt 0 ]]; then
hlevel=$(host_cpu_level)
[[ "$hlevel" -gt 0 && "$hlevel" -lt "$cmlevel" ]] && parts="$parts !CPU-FLOOR:v$cmlevel"
fi
fi
fi
[[ -n "$parts" ]] && printf '[%s]' "${parts# }"
}
#operator help (the 'help' action; the no-args case shows show_usage only).
@ -1911,6 +1999,12 @@ case "$action" in
#build-origin class (table-aware read - schema v2)
fclass=$(provenance_class < "${archdir}/${tomlname}")
[[ -n "$fclass" ]] && echo "provenance: class=$fclass"
#G-172: surface the recorded CPU floor as information. Fetch is UNGATED
#- a cross-platform fetch (-platform <p>) for another machine is normal
#and a local-CPU verdict would be meaningless there.
ffloor=$(sed -n 's/^[[:space:]]*cpu_floor[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "${archdir}/${tomlname}" 2>/dev/null | head -n 1)
fmodel=$(sed -n 's/^[[:space:]]*cpu_model[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "${archdir}/${tomlname}" 2>/dev/null | head -n 1)
[[ -n "$ffloor" || -n "$fmodel" ]] && echo "cpu floor: floor=$ffloor model=$fmodel"
else
rm -f "${archdir}/${tomlname}"
echo "no artifact metadata toml on server for $runtime (ok for pre-family runtimes)"
@ -2154,6 +2248,21 @@ case "$action" in
done
exit 1
fi
#G-172 floor verdict: selecting a runtime the local CPU cannot run is a
#named diagnosis instead of a silent 0xC000001D on the next 'run'. Only
#the LOCAL platform is gated - a foreign -platform folder is cross-build
#staging deployed elsewhere to run. 'below' blocks the selection.
if [[ "$platform" == "$local_platform" ]]; then
utoml="$archdir/$(rootname_of "$1").toml"
if [[ -f "$utoml" ]]; then
cpu_floor_verdict "$utoml"
if [[ "$floor_verdict" == "below" ]]; then
echo "punk-runtime use: $1 - $floor_message"
exit 1
fi
[[ "$floor_verdict" == "unknown" ]] && echo "punk-runtime use: $1 - $floor_message"
fi
fi
#G-103 artifact-tier names (-r<N>, immutable): 'use' MATERIALIZES the
#artifact into its WORKING name (name minus -r<N> - what mapvfs and
#projects reference), copies its metadata toml alongside, and selects
@ -2222,6 +2331,20 @@ case "$action" in
fi
fi
activeruntime_fullpath="$archdir/$activeruntime"
#G-172 floor verdict: launching a runtime the local CPU cannot run is a
#named diagnosis instead of a silent 0xC000001D (#UD before main - the
#2026-08-06 AVX-512 regression failure mode). 'below' aborts before the
#launch; 'unknown' notes the audit tool but does not block (a -Dcpu=native
#local build runs on its own host by definition).
rtoml="$archdir/$(rootname_of "$activeruntime").toml"
if [[ -f "$rtoml" ]]; then
cpu_floor_verdict "$rtoml"
if [[ "$floor_verdict" == "below" ]]; then
echo "punk-runtime run: $activeruntime - $floor_message"
exit 1
fi
[[ "$floor_verdict" == "unknown" ]] && echo "punk-runtime run: $activeruntime - $floor_message"
fi
#echo "using $activeruntime_fullpath"
#(the action was already shifted off during the option scan - "$@" is
#exactly the runtime's argument list)
@ -2350,7 +2473,7 @@ case "$action" in
if [[ -n "$embedded" || -f "$sidecar" ]]; then
printf ' %-20s %-36s %s\n' "field" "embedded" "sidecar"
disagreements=""
for k in schema name class variant working_name revision target build_id origin packager builder source_url upstream_ref retrieved project project_url license build_host_platform tcl_patchlevel sha1 size built; do
for k in schema name class variant working_name revision target build_id origin packager builder source_url upstream_ref retrieved project project_url license build_host_platform tcl_patchlevel cpu_floor cpu_model sha1 size built; do
ev=""; sv=""
if [[ -n "$embedded" ]]; then
ev=$(printf '%s\n' "$embedded" | sed -n 's/^[[:space:]]*'"$k"'[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' | head -n 1)
@ -3035,6 +3158,22 @@ function Get-PunkRuntimeMetadataSummary {
if ($expectedplatform -ne "" -and $fields.ContainsKey('target') -and $fields['target'] -ne $expectedplatform) {
$parts += "!TARGET-MISMATCH:$($fields['target'])"
}
#G-172 CPU floor surface + runnability annotation. floor= is informational (the
#recipe's declared default); !CPU-FLOOR:v<req> marks a row the local CPU cannot
#run - gated to the LOCAL platform only (a foreign-platform row is cross-build
#staging, not runnable here regardless). Absent on pre-G-172 tomls (no tag).
if ($fields.ContainsKey('cpu_floor') -and $fields['cpu_floor'] -ne "") {
$parts += "floor=$($fields['cpu_floor'])"
}
if ($expectedplatform -eq $script:PunkLocalPlatform -and $fields.ContainsKey('cpu_model') -and $fields['cpu_model'] -ne "") {
$cmLevel = Get-PunkCpuModelLevel $fields['cpu_model']
if ($cmLevel -gt 0) {
$hLevel = Get-PunkHostCpuLevel
if ($hLevel -gt 0 -and $hLevel -lt $cmLevel) {
$parts += "!CPU-FLOOR:v$cmLevel"
}
}
}
if ($parts.Count -eq 0) {
return ""
}
@ -3079,6 +3218,99 @@ function Get-PunkRuntimeProvenanceClass {
}
return ""
}
#G-172 CPU instruction-set floor surfacing and runnability verdict. A runtime's
#metadata toml (and embedded record) carry cpu_floor (the recipe's declared default
#floor) and cpu_model (what the build ACTUALLY resolved to). A published artifact
#built at the recipe default records cpu_model="x86_64" (baseline, v1); -Dcpu=native
#honestly records the host uarch. The verdict compares the recorded codegen level
#to the local CPU so selecting/launching a runtime the local CPU cannot run is a
#NAMED diagnosis instead of a silent STATUS_ILLEGAL_INSTRUCTION (0xC000001D) -
#the failure mode of the 2026-08-06 AVX-512 regression (see G-172 Context). Fetch
#stays ungated (a cross-platform fetch for another machine is normal); only the
#local-only actions (use/run) gate, and list annotates rows the host cannot run.
#Host level detection: IsProcessorFeaturePresent (kernel32) with the documented
#PF constants (winnt.h): SSE2=10 (v1 baseline), SSE4.2=38 (v2), AVX2=40 (v3),
#AVX512F=41 (v4). Detected once and cached; a detection failure degrades to 0
#(unknown) and the verdict never blocks on unknown, so a detection gap cannot
#prevent a launch - only a POSITIVE below-floor verdict blocks.
$script:PunkHostCpuLevel = $null
function Get-PunkHostCpuLevel {
if ($null -ne $script:PunkHostCpuLevel) { return $script:PunkHostCpuLevel }
$code = @'
using System;
using System.Runtime.InteropServices;
public class PunkCpuFeat {
[DllImport("kernel32.dll")]
static extern bool IsProcessorFeaturePresent(uint feature);
public static int Level() {
if (IsProcessorFeaturePresent(41)) return 4; //AVX512F (x86-64 v4)
if (IsProcessorFeaturePresent(40)) return 3; //AVX2 (x86-64 v3)
if (IsProcessorFeaturePresent(38)) return 2; //SSE4.2 (x86-64 v2)
if (IsProcessorFeaturePresent(10)) return 1; //SSE2 (x86-64 v1 baseline)
return 0;
}
}
'@
try {
Add-Type -TypeDefinition $code -ErrorAction Stop
$script:PunkHostCpuLevel = [PunkCpuFeat]::Level()
} catch {
#P/Invoke unavailable (locked-down host / broken PS): degrade to unknown
$script:PunkHostCpuLevel = 0
}
return $script:PunkHostCpuLevel
}
#G-172 map a recorded cpu_model name to an x86-64 level (1..4), or 0 for a
#specific uarch / unknown name. The standard zig level models map directly; a
#specific uarch (znver5, skylake, ...) is NOT a level - the codegen audit tool
#(scriptlib/developer/cpufloor_audit.tcl) is the authoritative runnability check
#for those, since punk-runtime cannot map a uarch name to a feature set.
function Get-PunkCpuModelLevel {
param([string] $cpuModel)
switch ($cpuModel) {
"x86_64" { return 1 }
"baseline" { return 1 }
"x86_64_v2" { return 2 }
"x86_64_v3" { return 3 }
"x86_64_v4" { return 4 }
default { return 0 }
}
}
#G-172 floor-vs-host verdict. $fields is the record-field hashtable from
#Get-PunkRuntimeRecordFields on the runtime's toml. Returns a hashtable:
# Verdict 'meets' | 'below' | 'unknown' | 'norecord'
# Required 0..4 (the recorded codegen level; 0 = unknown/specific-uarch)
# Host 0..4 (the local CPU level; 0 = undetermined)
# Message the diagnosis line (empty on meets/norecord)
# CpuFloor / CpuModel as recorded (empty if absent)
#'below' => the recorded codegen exceeds the host: launching would die with
#0xC000001D, so the caller MUST NOT launch. 'unknown' => cannot verdict by name
#(specific uarch or host undetermined): do not block, surface the audit tool.
function Get-PunkCpuFloorVerdict {
param([hashtable] $fields)
$cm = ""; if ($fields.ContainsKey('cpu_model')) { $cm = $fields['cpu_model'] }
$cf = ""; if ($fields.ContainsKey('cpu_floor')) { $cf = $fields['cpu_floor'] }
#NOTE: deliberately NOT named $host - that is a read-only automatic variable
#in PowerShell (the $Host object); reusing it throws VariableNotWritable.
$hlevel = Get-PunkHostCpuLevel
if ($cm -eq "") {
return @{ Verdict='norecord'; Required=0; Host=$hlevel; Message=""; CpuFloor=$cf; CpuModel=$cm }
}
$req = Get-PunkCpuModelLevel $cm
if ($req -eq 0) {
$msg = "cpu_model='$cm' is a specific uarch (not an x86-64 level); runnability is verified by the codegen audit tool: tclsh scriptlib/developer/cpufloor_audit.tcl <runtime> (declared floor: $cf)"
return @{ Verdict='unknown'; Required=0; Host=$hlevel; Message=$msg; CpuFloor=$cf; CpuModel=$cm }
}
if ($hlevel -eq 0) {
$msg = "host CPU level undetermined (IsProcessorFeaturePresent unavailable); recorded cpu_model='$cm' (x86-64 v$req), floor='$cf' - runnability not verified"
return @{ Verdict='unknown'; Required=$req; Host=0; Message=$msg; CpuFloor=$cf; CpuModel=$cm }
}
if ($hlevel -lt $req) {
$msg = "runtime built for cpu_model='$cm' (x86-64 v$req) but this CPU is x86-64 v$hlevel - launching it would fail with STATUS_ILLEGAL_INSTRUCTION (0xC000001D). Aborting; use 'punk-runtime list' for a runtime this CPU can run."
return @{ Verdict='below'; Required=$req; Host=$hlevel; Message=$msg; CpuFloor=$cf; CpuModel=$cm }
}
return @{ Verdict='meets'; Required=$req; Host=$hlevel; Message=""; CpuFloor=$cf; CpuModel=$cm }
}
#G-117 embedded record: zip CENTRAL-DIRECTORY read of the exe-appended archive via
#.NET System.IO.Compression (offsets resolve from the end-of-central-directory
#record, so the prepended executable data is no obstacle). The target is NEVER
@ -3614,6 +3846,16 @@ function psmain {
#build-origin class (table-aware read - schema v2)
$fclass = Get-PunkRuntimeProvenanceClass ([string[]](Get-Content -Path $tomllocal))
if ($fclass -ne "") { Write-Host "provenance: class=$fclass" }
#G-172: surface the recorded CPU floor as information. Fetch is
#UNGATED - a cross-platform fetch (-platform <p>) for another
#machine is a normal workflow and a local-CPU verdict would be
#meaningless there, so only the recorded floor/model are printed.
$fflds = Get-PunkRuntimeRecordFields ([string[]](Get-Content -Path $tomllocal))
$ffloor = ""; if ($fflds.ContainsKey('cpu_floor')) { $ffloor = $fflds['cpu_floor'] }
$fmodel = ""; if ($fflds.ContainsKey('cpu_model')) { $fmodel = $fflds['cpu_model'] }
if ($ffloor -ne "" -or $fmodel -ne "") {
Write-Host "cpu floor: floor=$ffloor model=$fmodel"
}
} catch {
Write-Host "no artifact metadata toml on server for $runtime (ok for pre-family runtimes)"
}
@ -3687,6 +3929,25 @@ function psmain {
}
exit 1
}
#G-172 floor verdict: selecting a runtime the local CPU cannot run is a
#named diagnosis instead of a silent 0xC000001D on the next 'run'.
#Only the LOCAL platform is gated - a foreign -platform folder is
#cross-build staging deployed elsewhere to run. 'below' blocks the
#selection; 'unknown' notes the audit tool but does not block.
if ($arch -eq $script:PunkLocalPlatform) {
$utoml = Join-Path -Path $archfolder -ChildPath ((Get-PunkRuntimeRootName $rtname) + ".toml")
if (Test-Path -Path $utoml -PathType Leaf) {
$uflds = Get-PunkRuntimeRecordFields ([string[]](Get-Content -Path $utoml))
$uverd = Get-PunkCpuFloorVerdict $uflds
if ($uverd.Verdict -eq 'below') {
Write-Host "punk-runtime use: $rtname - $uverd.Message"
exit 1
}
if ($uverd.Verdict -eq 'unknown') {
Write-Host "punk-runtime use: $rtname - $uverd.Message"
}
}
}
#G-103 artifact-tier names (-r<N>, immutable): 'use' MATERIALIZES the
#artifact into its WORKING name (name minus -r<N> - what mapvfs and
#projects reference), copies its metadata toml alongside, and selects
@ -3762,6 +4023,24 @@ function psmain {
}
$active = Join-Path -Path $archfolder -ChildPath $activename
write-host "using: $active"
#G-172 floor verdict: launching a runtime the local CPU cannot run
#is a named diagnosis instead of a silent 0xC000001D (#UD before
#main - the failure mode of the 2026-08-06 AVX-512 regression).
#'below' aborts before Start-Process; 'unknown' notes the audit
#tool but does not block (a -Dcpu=native local build runs on
#its own host by definition).
$rtoml = Join-Path -Path $archfolder -ChildPath ((Get-PunkRuntimeRootName $activename) + ".toml")
if (Test-Path -Path $rtoml -PathType Leaf) {
$rflds = Get-PunkRuntimeRecordFields ([string[]](Get-Content -Path $rtoml))
$rverd = Get-PunkCpuFloorVerdict $rflds
if ($rverd.Verdict -eq 'below') {
Write-Host "punk-runtime run: $activename - $rverd.Message"
exit 1
}
if ($rverd.Verdict -eq 'unknown') {
Write-Host "punk-runtime run: $activename - $rverd.Message"
}
}
if ($PSBoundParameters.opts.Length -gt 0) {
$optsType = $PSBoundParameters.opts.GetType() #method can only be called if .opts is not null
write-host "type of opts: $($optsType.FullName)"
@ -4114,7 +4393,7 @@ function psmain {
if ($havesidecar) { $sfields = Get-PunkRuntimeRecordFields ([string[]](Get-Content -Path $sidecarfile)) }
write-host (" {0,-20} {1,-36} {2}" -f "field", "embedded", "sidecar")
$disagreements = @()
foreach ($k in @('schema','name','class','variant','working_name','revision','target','build_id','origin','packager','builder','source_url','upstream_ref','retrieved','project','project_url','license','build_host_platform','tcl_patchlevel','sha1','size','built')) {
foreach ($k in @('schema','name','class','variant','working_name','revision','target','build_id','origin','packager','builder','source_url','upstream_ref','retrieved','project','project_url','license','build_host_platform','tcl_patchlevel','cpu_floor','cpu_model','sha1','size','built')) {
$ev = ""; $sv = ""
if ($efields.ContainsKey($k)) { $ev = $efields[$k] }
if ($sfields.ContainsKey($k)) { $sv = $sfields[$k] }

67
goals/G-172-distributed-binary-cpu-floor.md

@ -1,6 +1,6 @@
# G-172 Distributed binaries declare a CPU floor - no shipped artifact is tuned to its build host
Status: proposed
Status: active
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.
@ -220,3 +220,68 @@ project's first contact with a new user fails with no message at all.
fixture), 5 (punk-runtime surfacing and the use/run verdict). Behind those:
r1-generation disposition (replace vs drop) and the bin/ punk9* kit rebake
with the new runtime (punkproject version-gate discipline applies).
- 2026-08-07: goal activated at user direction (overlap survey re-run via
`goals_xref.tcl score G-172` - no goals drafted in the interval; the existing
Related: notes cover every overlapping pair). Approaches 3, 4, 5 CODE landed:
- Approach 3 (record floor field): `src/buildsuites/suite_tcl90/build905.zig`
declares `const cpu_floor = "baseline";` beside the default_target pin and
writes `cpu_floor` + `cpu_model` (=`target.result.cpu.model.name`, resolving
to "x86_64" for the default build, "znver5" for -Dcpu=native) into the
embedded record's [provenance], after toolchain/optimize (ast-check PASS;
17 format placeholders = 17 args). `tools/family_artifacts.tcl` derives both
from the embedded record (G-117 single-source-of-truth, like
origin/packager) and emits them into the sidecar [provenance], failing if
absent. `tools/family_check.tcl` asserts embed_cpu_floor/embed_cpu_model
non-empty. suite_tcl86 has no family machinery (G-158 territory) - only the
build86.zig cpu_model pin (already in place). NOT yet built/published - the
floor field reaches published artifacts at the next republication.
- Approach 4 (audit tool): `scriptlib/developer/cpufloor_audit.tcl` (plain
tclsh, no deps) disassembles a binary's .text via a located objdump
(llvm-objdump preferred, GNU objdump fallback) or audits a pre-disassembled
excerpt (`-from-dis`), classifies by AVX register width (zmm=v4, ymm=v3;
baseline/v2 forbid both, v3 forbids zmm, v4 allows all - SSE4.2 not
width-detectable so baseline and v2 share a ceiling), reports out-of-floor
count + first RVA + sample mnemonics, exit 0 PASS / 1 FAIL. Selftest
(`-selftest`) runs 12 fixture/floor cases - all pass. Fixtures are REAL
disassembly excerpts in `scriptlib/developer/cpufloor_fixtures/` (avx512,
avx2, clean) generated from a temp-built probe on this Zen 5 host (no
binary committed). Verified against real binaries: rebuilt bin/punkzip.exe
PASS (zmm=0 ymm=0); a -Dcpu=native probe FAILs at baseline (123 zmm, 151
out-of-floor, first RVA 140002952) and PASSes at v4. The acceptance's
measurable instrument is in place.
- Approach 5 (punk-runtime surfacing): both payload twins updated and
re-wrapped. `src/scriptapps/bin/punk-runtime.ps1` adds
`Get-PunkHostCpuLevel` (IsProcessorFeaturePresent via Add-Type P/Invoke;
PF SSE2=10/SSE4.2=38/AVX2=40/AVX512F=41 -> level 1..4, cached, 0 on
detection failure), `Get-PunkCpuModelLevel` (x86_64/baseline->1, _v2->2,
_v3->3, _v4->4, else 0), `Get-PunkCpuFloorVerdict` (meets|below|unknown|
norecord; below => block). `punk-runtime.bash` mirrors with
`host_cpu_level` (/proc/cpuinfo flags avx512f/avx2/sse4_2/sse2),
`cpu_model_level`, `cpu_floor_verdict` (sets globals). Wired: fetch prints
`cpu floor: floor=.. model=..` (UNGATED - cross-platform fetch stays free);
list metadata_summary adds `floor=` and `!CPU-FLOOR:v<req>` (local-platform
rows only); use gates on the local platform (below => exit 1, named
diagnosis); run gates before launch (below => exit 1); info adds
cpu_floor/cpu_model to the embedded-vs-sidecar field table. `$host` is a
read-only automatic variable in PowerShell - the PS verdict uses `$hlevel`
(caught during testing). Re-wrapped via
`punk::mix::commandset::scriptwrap::multishell punk-runtime -askme 0 -force 1`
from src/scriptapps/bin; wrap is deterministic (re-wrap diff = identical);
the scriptwrap_runtime_cmd_roundtrip_no_drift test PASSES. Host detection
verified (PS level=4 on this Zen 5 box; bash /proc/cpuinfo level=4 in
git-bash); verdict logic verified with a mocked v2 host (x86_64_v4 ->
below/block, znver5 -> unknown, x86_64 -> meets) in both twins.
Remaining for acceptance (publication-time, not code): rebuild the family +
tools with the floor field in the record, republish in-situ to punkbin (per
Approach 6's alpha dispensation), and run the audit tool against the
republished artifacts to confirm zmm=0 (the acceptance's "flagless build emits
zero instructions above floor"). The [tests]-freshness refresh of the replaced
tomls folds into that republication. A real end-to-end `use`/`run` `below`
block requires a host whose level is below a published artifact's recorded
cpu_model - not demonstrable on this v4 host with baseline-floor artifacts
(every host meets v1); the mechanism is verified by the mocked-host tests.
Behind those: r1-generation disposition and the bin/ punk9* kit rebake.

2
punkproject.toml

@ -1,6 +1,6 @@
[project]
name = "punkshell"
version = "0.57.0"
version = "0.57.1"
license = "BSD-2-Clause"
url = "https://www.gitea1.intx.com.au/jn/punkshell"
#packager: declared identity for published artifacts (declarative, not proof -

276
scriptlib/developer/cpufloor_audit.tcl

@ -0,0 +1,276 @@
#cpufloor_audit.tcl - G-172 audit instrument: disassemble a distributed binary
#(or a pre-disassembled .text excerpt) and report instructions above a declared
#CPU instruction-set floor. The acceptance criterion of G-172 ("a flagless build
#of each distributed-artifact recipe emits zero instructions above the declared
#floor") is measurable by THIS tool rather than by a promise about build habits.
#
#The defect class (see goals/G-172-distributed-binary-cpu-floor.md Context): zig
#auto-vectorises ReleaseFast codegen to whatever the build host's CPU happens
#to expose when a recipe resolves cpu_model .determined_by_arch_os by NATIVE
#detection. On a Zen 5 host that is AVX-512 - real EVEX-encoded zmm-operand
#instructions at the front of .text. Tcl has no runtime CPU dispatch, so on a
#non-AVX-512 CPU the first one raises #UD and the process dies with
#STATUS_ILLEGAL_INSTRUCTION (0xC000001D) before writing a byte. The 2026-08-06
#regression shipped the entire published tclsh9.0.5 family (2756 zmm sites each)
#and the build-path tools (punkzip 1724, punkres 1423) - the bundled fixtures
#are real excerpts of that codegen class.
#
#Detection is by AVX REGISTER WIDTH, the same signal the Context measurements
#used: a `zmm[0-9]+` operand is AVX-512 (x86-64 v4), a `ymm[0-9]+` operand is
#AVX2 (x86-64 v3). Size specifiers (zmmword/ymmword/xmmword) never match - they
#lack the trailing digit. SSE4.2/POPCNT (the v2-only delta over baseline) is
#not detectable by width; baseline and v2 therefore share the same register
#ceiling (no AVX) and audit identically. The regression is AVX-width, so this
#is the honest instrument for it; a future finer-grained floor (per-instruction
#mnemonic classification) is a follow-on, not required by the acceptance.
#
#Plain tclsh, no dependencies. Exit 0 = no instructions above floor (PASS);
#exit 1 = out-of-floor instructions found (FAIL) or a selftest failure.
#
#Usage:
# tclsh cpufloor_audit.tcl ?-floor baseline|v2|v3|v4? <binary>
# Disassemble <binary>'s .text with a located objdump and audit it.
# llvm-objdump is preferred (Intel syntax), GNU objdump (-M intel) is the
# fallback. No disassembler on PATH is a hard error (install llvm-objdump,
# or pipe a pre-disassembled excerpt in with -from-dis).
# tclsh cpufloor_audit.tcl -from-dis ?-floor <f>? <dis-text-file>
# Audit a pre-disassembled .text excerpt (objdump -d output) directly -
# no disassembler needed. The bundled fixtures are this shape.
# tclsh cpufloor_audit.tcl -selftest
# Run the bundled fixtures (scriptlib/developer/cpufloor_fixtures/) through
# every floor and check the verdicts - the regression-as-fixture contract.
#
#Floor defaults to baseline (the project's chosen floor for the x86_64 family -
#see G-172 Approach 2: a Tcl interpreter's codegen delta against v2/v3 is
#negligible against the cost of the default runtime failing to start).
package require Tcl 8.6
proc scriptdir {} {
global argv0
return [file dirname [file normalize $argv0]]
}
proc floor_forbidden {floor} {
switch -- $floor {
baseline { return [dict create zmm 1 ymm 1] }
v2 { return [dict create zmm 1 ymm 1] }
v3 { return [dict create zmm 1 ymm 0] }
v4 { return [dict create zmm 0 ymm 0] }
default { error "unknown floor '$floor' (expected baseline, v2, v3 or v4)" }
}
}
#is <line> an instruction line (addr: hexbytes... mnemonic...)?
proc is_insn_line {line} {
return [regexp {^\s*[0-9a-fA-F]+:\s+([0-9a-fA-F]{2}\s)+} $line]
}
#extract the mnemonic of an instruction line (first token after the hex-byte run)
proc insn_mnemonic {line} {
if {![regexp {^\s*[0-9a-fA-F]+:\s+(.+)$} $line -> rest]} { return "" }
set rest [regsub {^([0-9a-fA-F]{2}\s+)+} $rest ""]
set rest [regsub {^\s+} $rest ""]
set mnem [lindex [split $rest \t] 0]
return [lindex [split $mnem " "] 0]
}
#audit a list of disassembly lines against a floor.
#returns dict: total zmm_sites ymm_sites out_of_floor first_rva sample_mnemonics
proc audit_lines {lines floor} {
set forbidden [floor_forbidden $floor]
set fz [dict get $forbidden zmm]
set fy [dict get $forbidden ymm]
set total 0
set zmm 0
set ymm 0
set out 0
set first_rva ""
set mnemonics {}
foreach line $lines {
if {![is_insn_line $line]} continue
incr total
set line_zmm [expr {[regexp {zmm[0-9]+} $line] ? 1 : 0}]
set line_ymm [expr {[regexp {ymm[0-9]+} $line] ? 1 : 0}]
if {$line_zmm} { incr zmm }
if {$line_ymm} { incr ymm }
set line_out 0
if {$line_zmm && $fz} { set line_out 1 }
if {$line_ymm && $fy} { set line_out 1 }
if {!$line_out} continue
incr out
if {$first_rva eq ""} {
regexp {^\s*([0-9a-fA-F]+):} $line -> first_rva
}
set mnem [insn_mnemonic $line]
if {$mnem ne "" && $mnem ni $mnemonics && [llength $mnemonics] < 12} {
lappend mnemonics $mnem
}
}
return [dict create total $total zmm_sites $zmm ymm_sites $ymm \
out_of_floor $out first_rva $first_rva sample_mnemonics $mnemonics]
}
#locate a disassembler and return a command prefix that disassembles .text in
#Intel syntax. Empty string = none found.
proc find_disassembler {} {
foreach {cmd} {
{llvm-objdump -d --section=.text --x86-asm-syntax=intel}
{objdump -d --section=.text -M intel}
} {
set exe [auto_execok [lindex $cmd 0]]
if {$exe ne ""} {
return [concat [list $exe] [lrange $cmd 1 end]]
}
}
return ""
}
proc read_lines {path} {
set f [open $path r]
fconfigure $f -translation binary
set data [read $f]
close $f
#normalise CRLF -> LF so the parser sees one line model
return [split [string map [list \r\n \n \r \n] $data] \n]
}
proc report {path floor res} {
set out [dict get $res out_of_floor]
set zmm [dict get $res zmm_sites]
set ymm [dict get $res ymm_sites]
set total [dict get $res total]
puts "cpufloor_audit: $path"
puts " floor: $floor"
puts " .text insns: $total"
puts " zmm sites (v4): $zmm"
puts " ymm sites (v3): $ymm"
puts " out-of-floor: $out"
if {$out > 0} {
puts " first out-of-floor RVA: [dict get $res first_rva]"
set ms [dict get $res sample_mnemonics]
if {[llength $ms]} {
puts " sample out-of-floor mnemonics: [join $ms {, }]"
}
puts " VERDICT: FAIL - instructions above the declared floor are present"
} else {
puts " VERDICT: PASS - no instructions above the declared floor"
}
}
proc usage {} {
puts stderr "usage: tclsh cpufloor_audit.tcl ?-floor baseline|v2|v3|v4? <binary>"
puts stderr " tclsh cpufloor_audit.tcl -from-dis ?-floor <f>? <dis-text-file>"
puts stderr " tclsh cpufloor_audit.tcl -selftest"
}
proc selftest {} {
set d [file join [scriptdir] cpufloor_fixtures]
set cases {
{avx512.dis.txt baseline 1}
{avx512.dis.txt v2 1}
{avx512.dis.txt v3 1}
{avx512.dis.txt v4 0}
{avx2.dis.txt baseline 1}
{avx2.dis.txt v2 1}
{avx2.dis.txt v3 0}
{avx2.dis.txt v4 0}
{clean.dis.txt baseline 0}
{clean.dis.txt v2 0}
{clean.dis.txt v3 0}
{clean.dis.txt v4 0}
}
set fail 0
foreach case $cases {
lassign $case fixture floor expect_fail
set p [file join $d $fixture]
if {![file exists $p]} {
puts "SELFTEST FAIL: fixture missing: $p"
incr fail
continue
}
set res [audit_lines [read_lines $p] $floor]
set got [dict get $res out_of_floor]
set got_fail [expr {$got > 0 ? 1 : 0}]
set zmm [dict get $res zmm_sites]
set ymm [dict get $res ymm_sites]
set status OK
if {$got_fail != $expect_fail} {
set status "MISMATCH (expected [expr {$expect_fail ? {FAIL} : {PASS}}])"
incr fail
}
puts [format "SELFTEST %-16s floor=%-9s zmm=%-4d ymm=%-4d out=%-4d %s" \
$fixture $floor $zmm $ymm $got $status]
}
if {$fail} {
puts "SELFTEST: $fail case(s) failed"
return 1
}
puts "SELFTEST: all cases pass"
return 0
}
#--- argv parsing ---
set floor baseline
set from_dis 0
set selftest_mode 0
set positional {}
foreach a $argv {
switch -- $a {
-floor { set expecting_floor 1 }
-from-dis { set from_dis 1 }
-selftest { set selftest_mode 1 }
-help - --help - -h {
usage; exit 0
}
default {
if {[info exists expecting_floor]} {
set floor $a
unset expecting_floor
} else {
lappend positional $a
}
}
}
}
if {[info exists expecting_floor]} {
usage; exit 1
}
if {$selftest_mode} {
exit [selftest]
}
if {[llength $positional] == 0} {
usage; exit 1
}
set target [lindex $positional 0]
if {![file exists $target]} {
puts stderr "cpufloor_audit: no such file: $target"
exit 1
}
if {$from_dis} {
set lines [read_lines $target]
} else {
set dis [find_disassembler]
if {$dis eq ""} {
puts stderr "cpufloor_audit: no disassembler found on PATH (tried llvm-objdump, objdump)."
puts stderr " install llvm-objdump, or pass a pre-disassembled excerpt with -from-dis."
exit 1
}
set cmd [concat $dis [list $target]]
if {[catch {exec {*}$cmd 2>@1} disout]} {
#objdump returns nonzero on some warnings but still emits disassembly;
#only treat as fatal if there is no instruction output at all
if {![regexp -inline {[0-9a-fA-F]+:} $disout]} {
puts stderr "cpufloor_audit: disassembler failed: $disout"
exit 1
}
}
set lines [split [string map [list \r\n \n \r \n] $disout] \n]
}
set res [audit_lines $lines $floor]
report $target $floor $res
exit [expr {[dict get $res out_of_floor] > 0 ? 1 : 0}]

32
scriptlib/developer/cpufloor_fixtures/avx2.dis.txt

@ -0,0 +1,32 @@
sample.exe: file format coff-x86-64
Disassembly of section .text:
140015fc2: c5 fc 10 07 vmovups ymm0, ymmword ptr [rdi]
140016001: c5 fc 11 06 vmovups ymmword ptr [rsi], ymm0
140016ca6: c5 fc 10 00 vmovups ymm0, ymmword ptr [rax]
140016cad: c5 fc 11 06 vmovups ymmword ptr [rsi], ymm0
140017842: c4 e2 7d 13 c9 vcvtph2ps ymm1, xmm1
14001785b: c4 e2 7d 13 db vcvtph2ps ymm3, xmm3
140017884: c4 e2 7d 13 c0 vcvtph2ps ymm0, xmm0
140017889: c5 f4 59 c8 vmulps ymm1, ymm1, ymm0
14001788d: c5 e4 59 c0 vmulps ymm0, ymm3, ymm0
140017891: c4 e3 7d 1d c9 04 vcvtps2ph xmm1, ymm1, 0x4
140017897: c4 e3 7d 1d c0 04 vcvtps2ph xmm0, ymm0, 0x4
1400178c7: c4 e3 7d 1d c9 04 vcvtps2ph xmm1, ymm1, 0x4
1400178cd: c4 e3 7d 1d c0 04 vcvtps2ph xmm0, ymm0, 0x4
14001853e: c5 fc 10 01 vmovups ymm0, ymmword ptr [rcx]
140018542: c5 fc 11 00 vmovups ymmword ptr [rax], ymm0
140018b07: c4 e2 7d 13 ed vcvtph2ps ymm5, xmm5
140018b0c: c4 e2 7d 13 e4 vcvtph2ps ymm4, xmm4
140018b11: c5 dc 59 e5 vmulps ymm4, ymm4, ymm5
140018b15: 62 b3 7d 28 1d e0 04 vcvtps2ph xmm16, ymm4, 0x4
140018b23: 62 a2 7d 28 13 c8 vcvtph2ps ymm17, xmm16
140018b2e: 62 f1 74 20 5c ec vsubps ymm5, ymm17, ymm4
140018b34: 62 b1 5c 28 58 e1 vaddps ymm4, ymm4, ymm17
140018b3a: c4 e3 7d 1d ed 04 vcvtps2ph xmm5, ymm5, 0x4
140018b40: c4 e3 7d 1d e4 04 vcvtps2ph xmm4, ymm4, 0x4
140021500: c4 c1 7c 11 0a vmovups ymmword ptr [r10], ymm1
1400218d0: c4 c1 7c 11 0e vmovups ymmword ptr [r14], ymm1
140021d80: c4 c1 7e 7f 06 vmovdqu ymmword ptr [r14], ymm0
1400221e0: c4 c1 7e 7f 06 vmovdqu ymmword ptr [r14], ymm0

70
scriptlib/developer/cpufloor_fixtures/avx512.dis.txt

@ -0,0 +1,70 @@
sample.exe: file format coff-x86-64
Disassembly of section .text:
140002917: 83 e0 04 and eax, 0x4
14000291a: 49 29 c1 sub r9, rax
14000291d: 44 89 11 mov dword ptr [rcx], r10d
140002920: 44 8b 14 02 mov r10d, dword ptr [rdx + rax]
140002924: 44 89 14 01 mov dword ptr [rcx + rax], r10d
140002928: 46 8b 14 0a mov r10d, dword ptr [rdx + r9]
14000292c: 42 8b 54 02 fc mov edx, dword ptr [rdx + r8 - 0x4]
140002931: 46 89 14 09 mov dword ptr [rcx + r9], r10d
140002935: 42 89 54 01 fc mov dword ptr [rcx + r8 - 0x4], edx
14000293a: 48 89 c8 mov rax, rcx
14000293d: 5e pop rsi
14000293e: 5d pop rbp
14000293f: c3 ret
140002940: 49 81 f8 ff 00 00 00 cmp r8, 0xff
140002947: 77 3c ja 0x140002985 <.text+0x1985>
140002949: 44 89 c0 mov eax, r8d
14000294c: d1 e8 shr eax
14000294e: 4d 8d 48 c0 lea r9, [r8 - 0x40]
140002952: 62 f1 7c 48 10 02 vmovups zmm0, zmmword ptr [rdx]
140002958: 83 e0 40 and eax, 0x40
14000295b: 49 29 c1 sub r9, rax
14000295e: 62 f1 7c 48 10 14 02 vmovups zmm2, zmmword ptr [rdx + rax]
140002965: 62 b1 7c 48 10 0c 0a vmovups zmm1, zmmword ptr [rdx + r9]
14000296c: 62 f1 7c 48 11 01 vmovups zmmword ptr [rcx], zmm0
140002972: 62 f1 7c 48 11 14 01 vmovups zmmword ptr [rcx + rax], zmm2
140002979: 62 b1 7c 48 11 0c 09 vmovups zmmword ptr [rcx + r9], zmm1
140002980: e9 12 01 00 00 jmp 0x140002a97 <.text+0x1a97>
140002985: 62 f1 7c 48 10 02 vmovups zmm0, zmmword ptr [rdx]
14000298b: 41 89 d1 mov r9d, edx
14000298e: 41 83 e1 3f and r9d, 0x3f
140002992: 4f 8d 54 01 c0 lea r10, [r9 + r8 - 0x40]
140002997: 49 c1 ea 06 shr r10, 0x6
14000299b: 44 89 d0 mov eax, r10d
14000299e: 4d 8d 5a ff lea r11, [r10 - 0x1]
1400029a2: 83 e0 07 and eax, 0x7
1400029a5: 62 f1 7c 48 11 01 vmovups zmmword ptr [rcx], zmm0
1400029ab: 49 83 fb 07 cmp r11, 0x7
1400029af: 73 08 jae 0x1400029b9 <.text+0x19b9>
1400029b1: 45 31 db xor r11d, r11d
1400029b4: e9 a9 00 00 00 jmp 0x140002a62 <.text+0x1a62>
1400029b9: be 00 02 00 00 mov esi, 0x200
1400029be: 49 83 e2 f8 and r10, -0x8
1400029c2: 45 31 db xor r11d, r11d
1400029c5: 4c 29 ce sub rsi, r9
1400029c8: 0f 1f 84 00 00 00 00 00 nop dword ptr [rax + rax]
1400029d0: 62 f1 7c 48 28 44 32 f9 vmovaps zmm0, zmmword ptr [rdx + rsi - 0x1c0]
1400029d8: 62 f1 7c 48 28 4c 32 fa vmovaps zmm1, zmmword ptr [rdx + rsi - 0x180]
1400029e0: 62 f1 7c 48 28 54 32 fb vmovaps zmm2, zmmword ptr [rdx + rsi - 0x140]
1400029e8: 49 83 c3 08 add r11, 0x8
1400029ec: 62 f1 7c 48 11 44 31 f9 vmovups zmmword ptr [rcx + rsi - 0x1c0], zmm0
1400029f4: 62 f1 7c 48 11 4c 31 fa vmovups zmmword ptr [rcx + rsi - 0x180], zmm1
1400029fc: 62 f1 7c 48 28 4c 32 fc vmovaps zmm1, zmmword ptr [rdx + rsi - 0x100]
140002a04: 62 f1 7c 48 11 54 31 fb vmovups zmmword ptr [rcx + rsi - 0x140], zmm2
140002a0c: 62 f1 7c 48 28 54 32 fd vmovaps zmm2, zmmword ptr [rdx + rsi - 0xc0]
140002a14: 62 f1 7c 48 11 4c 31 fc vmovups zmmword ptr [rcx + rsi - 0x100], zmm1
140002a1c: 62 f1 7c 48 28 4c 32 fe vmovaps zmm1, zmmword ptr [rdx + rsi - 0x80]
140002a24: 62 f1 7c 48 11 54 31 fd vmovups zmmword ptr [rcx + rsi - 0xc0], zmm2
140002a2c: 62 f1 7c 48 28 54 32 ff vmovaps zmm2, zmmword ptr [rdx + rsi - 0x40]
140002a34: 62 f1 7c 48 11 4c 31 fe vmovups zmmword ptr [rcx + rsi - 0x80], zmm1
140002a3c: 62 f1 7c 48 28 0c 32 vmovaps zmm1, zmmword ptr [rdx + rsi]
140002a43: 62 f1 7c 48 11 54 31 ff vmovups zmmword ptr [rcx + rsi - 0x40], zmm2
140002a4b: 62 f1 7c 48 11 0c 31 vmovups zmmword ptr [rcx + rsi], zmm1
140002a52: 48 81 c6 00 02 00 00 add rsi, 0x200
140002a59: 4d 39 da cmp r10, r11
140002a5c: 0f 85 6e ff ff ff jne 0x1400029d0 <.text+0x19d0>
140002a62: 48 85 c0 test rax, rax

70
scriptlib/developer/cpufloor_fixtures/clean.dis.txt

@ -0,0 +1,70 @@
sample.exe: file format coff-x86-64
Disassembly of section .text:
0000000140001000 <.text>:
140001000: 55 push rbp
140001001: 56 push rsi
140001002: 48 89 e5 mov rbp, rsp
140001005: 45 85 c9 test r9d, r9d
140001008: 7e 6e jle 0x140001078 <.text+0x78>
14000100a: 44 89 c8 mov eax, r9d
14000100d: 41 83 f9 01 cmp r9d, 0x1
140001011: 75 05 jne 0x140001018 <.text+0x18>
140001013: 45 31 c9 xor r9d, r9d
140001016: eb 49 jmp 0x140001061 <.text+0x61>
140001018: 41 89 c2 mov r10d, eax
14000101b: 41 81 e2 fe ff ff 7f and r10d, 0x7ffffffe
140001022: 45 31 c9 xor r9d, r9d
140001025: 66 2e 0f 1f 84 00 00 00 00 00 nop word ptr cs:[rax + rax]
14000102f: 90 nop
140001030: 4f 8b 1c c8 mov r11, qword ptr [r8 + 8*r9]
140001034: 4f 8d 1c 5b lea r11, [r11 + 2*r11]
140001038: 4a 8b 34 ca mov rsi, qword ptr [rdx + 8*r9]
14000103c: 49 01 f3 add r11, rsi
14000103f: 4c 89 1c f1 mov qword ptr [rcx + 8*rsi], r11
140001043: 4f 8b 5c c8 08 mov r11, qword ptr [r8 + 8*r9 + 0x8]
140001048: 4f 8d 1c 5b lea r11, [r11 + 2*r11]
14000104c: 4a 8b 74 ca 08 mov rsi, qword ptr [rdx + 8*r9 + 0x8]
140001051: 49 01 f3 add r11, rsi
140001054: 4c 89 1c f1 mov qword ptr [rcx + 8*rsi], r11
140001058: 49 83 c1 02 add r9, 0x2
14000105c: 4d 39 ca cmp r10, r9
14000105f: 75 cf jne 0x140001030 <.text+0x30>
140001061: a8 01 test al, 0x1
140001063: 74 13 je 0x140001078 <.text+0x78>
140001065: 4b 8b 04 c8 mov rax, qword ptr [r8 + 8*r9]
140001069: 48 8d 04 40 lea rax, [rax + 2*rax]
14000106d: 4a 8b 14 ca mov rdx, qword ptr [rdx + 8*r9]
140001071: 48 01 d0 add rax, rdx
140001074: 48 89 04 d1 mov qword ptr [rcx + 8*rdx], rax
140001078: 5e pop rsi
140001079: 5d pop rbp
14000107a: c3 ret
14000107b: 0f 1f 44 00 00 nop dword ptr [rax + rax]
140001080: 55 push rbp
140001081: 41 57 push r15
140001083: 41 56 push r14
140001085: 41 54 push r12
140001087: 56 push rsi
140001088: 57 push rdi
140001089: 53 push rbx
14000108a: 48 83 ec 20 sub rsp, 0x20
14000108e: 48 8d 6c 24 20 lea rbp, [rsp + 0x20]
140001093: 48 89 d6 mov rsi, rdx
140001096: 48 63 f9 movsxd rdi, ecx
140001099: 48 8d 1c 7f lea rbx, [rdi + 2*rdi]
14000109d: 4c 8d 34 bd 00 00 00 00 lea r14, [4*rdi]
1400010a5: 4c 8d 3c 3f lea r15, [rdi + rdi]
1400010a9: 45 31 e4 xor r12d, r12d
1400010ac: e8 6f 06 00 00 call 0x140001720 <.text+0x720>
1400010b1: 48 8d 05 98 df 02 00 lea rax, [rip + 0x2df98] # 0x14002f050
1400010b8: 0f 1f 84 00 00 00 00 00 nop dword ptr [rax + rax]
1400010c0: 4a 89 34 e0 mov qword ptr [rax + 8*r12], rsi
1400010c4: 48 8d 0c 37 lea rcx, [rdi + rsi]
1400010c8: 4a 89 4c e0 08 mov qword ptr [rax + 8*r12 + 0x8], rcx
1400010cd: 49 8d 0c 37 lea rcx, [r15 + rsi]
1400010d1: 4a 89 4c e0 10 mov qword ptr [rax + 8*r12 + 0x10], rcx
1400010d6: 48 8d 0c 33 lea rcx, [rbx + rsi]
1400010da: 4a 89 4c e0 18 mov qword ptr [rax + 8*r12 + 0x18], rcx

17
src/buildsuites/suite_tcl90/build905.zig

@ -119,6 +119,14 @@ pub fn build(b: *std.Build) !void {
.default_target = .{ .cpu_model = .baseline },
});
//G-172: the recipe's declared instruction-set floor (x86-64 v1 / baseline). A
//property of the recipe, recorded in every artifact's [provenance] so a build
//or publication cannot silently ship host-tuned code. -Dcpu=<model> raises the
//floor; -Dcpu=native opts into a host-tuned local build (recorded honestly as
//cpu_model in the record, which audit + punk-runtime read back). Keep in sync
//with the default_target cpu_model above.
const cpu_floor = "baseline";
const optimize = b.standardOptimizeOption(.{});
//set up and display some of the same prefix-dependent vars as Makefile for maintainability
@ -2596,9 +2604,16 @@ pub fn build(b: *std.Build) !void {
\\suite = "suite_tcl90"
\\toolchain = "zig {s}"
\\optimize = "{s}"
\\#cpu_floor: instruction-set floor the recipe DECLARES as its default
\\#target (G-172) - a property of the recipe, not the build host. A
\\#flagless build resolves to this floor. cpu_model is what the build
\\#ACTUALLY resolved to; -Dcpu=native honestly records the host uarch
\\#there, proving the floor is a default, not a restriction.
\\cpu_floor = "{s}"
\\cpu_model = "{s}"
\\{s}
\\
, .{ artifact_name, fk.variant, fk.working_name, familyrev, build_id, originurl, packager, project, projecturl, tcl_h_patchlevel, piperepl_block, batteries, builtin.zig_version_string, @tagName(optimize), prov_lines });
, .{ artifact_name, fk.variant, fk.working_name, familyrev, build_id, originurl, packager, project, projecturl, tcl_h_patchlevel, piperepl_block, batteries, builtin.zig_version_string, @tagName(optimize), cpu_floor, target.result.cpu.model.name, prov_lines });
}
var family_tree_base: [family_kits.len]std.Build.LazyPath = undefined;

13
src/buildsuites/suite_tcl90/tools/family_artifacts.tcl

@ -144,6 +144,17 @@ foreach {variant kitpath} $opt(-kits) {
if {$v eq ""} {fail "$artifact embedded record missing v1 field '$k'"}
dict set evars $k $v
}
#G-172 CPU instruction-set floor: the recipe declares a floor (cpu_floor) and
#the build resolves a cpu model (cpu_model) - both carried in the embedded
#record's [provenance]. The sidecar derives them from the embedded record
#(single source of truth, like origin/packager above) so a rebuilt+republished
#artifact's sidecar agrees with its embedded record by construction. Absent
#on pre-G-172 kits - fail rather than emit a floor-less sidecar.
foreach k {cpu_floor cpu_model} {
set v [record_field $embedded $k]
if {$v eq ""} {fail "$artifact embedded record missing G-172 floor field '$k' (kit predates the G-172 record extension?)"}
dict set evars $k $v
}
set m {}
lappend m "#punkshell runtime artifact metadata (schema v2, class \"runtime\") - generated by"
@ -198,6 +209,8 @@ foreach {variant kitpath} $opt(-kits) {
lappend m "suite = [toml_str $opt(-suite)]"
lappend m "toolchain = [toml_str "zig $opt(-zig)"]"
lappend m "optimize = [toml_str $opt(-optimize)]"
lappend m "cpu_floor = [toml_str [dict get $evars cpu_floor]]"
lappend m "cpu_model = [toml_str [dict get $evars cpu_model]]"
foreach {n uuid} $opt(-provenance) {
lappend m "${n}_checkout = [toml_str $uuid]"
}

8
src/buildsuites/suite_tcl90/tools/family_check.tcl

@ -226,7 +226,7 @@ set embed_script {
set rec [read $f]
close $f
out embed_exists 1
foreach k {schema variant tcl_patchlevel working_name name revision build_id piperepl origin packager project license build_host_platform} {
foreach k {schema variant tcl_patchlevel working_name name revision build_id piperepl origin packager project license build_host_platform cpu_floor cpu_model} {
out embed_$k [rfield $rec $k]
}
foreach line [split $rec \n] {
@ -250,6 +250,12 @@ if {[dict get $d embed_build_id] eq ""} {fail "embedded record: empty build_id"}
foreach k {embed_origin embed_packager embed_project embed_license embed_build_host_platform} {
if {![dict exists $d $k] || [dict get $d $k] eq ""} {fail "embedded record: missing v1 field [string range $k 6 end]"}
}
#G-172 CPU floor: the embedded [provenance] must carry the declared floor and the
#resolved cpu model (absent on pre-G-172 kits). cpu_floor is the recipe default
#(baseline for the x86_64 family); cpu_model is what the build resolved to.
foreach k {embed_cpu_floor embed_cpu_model} {
if {![dict exists $d $k] || [dict get $d $k] eq ""} {fail "embedded record: missing G-172 floor field [string range $k 6 end]"}
}
if {$opt(-expectrev) ne ""} {
asserteq $d embed_revision $opt(-expectrev) "embedded record"
if {[string match -nocase *.exe $kitname]} {

125
src/scriptapps/bin/punk-runtime.bash

@ -247,6 +247,76 @@ provenance_class() {
}
'
}
#G-172 CPU instruction-set floor surfacing and runnability verdict (ps1
#payload parity). A runtime's toml carries cpu_floor (the recipe's declared
#default floor) and cpu_model (what the build resolved to). host_cpu_level detects
#the local CPU's x86-64 level from /proc/cpuinfo flags (avx512f=v4, avx2=v3,
#sse4_2=v2, sse2=v1); cpu_floor_verdict compares and sets globals so use/run gate
#launching a runtime the local CPU cannot run (a named diagnosis instead of a
#silent STATUS_ILLEGAL_INSTRUCTION 0xC000001D - the 2026-08-06 AVX-512 failure).
#A detection gap (no /proc/cpuinfo) yields level 0 and the verdict never blocks
#on unknown, so a detection failure cannot prevent a launch.
punk_host_cpu_level=""
host_cpu_level() {
[[ -n "$punk_host_cpu_level" ]] && { echo "$punk_host_cpu_level"; return; }
local lvl=0 flags
if [[ -r /proc/cpuinfo ]]; then
flags=$(grep -m1 '^flags' /proc/cpuinfo 2>/dev/null || true)
if printf '%s' "$flags" | grep -qw 'avx512f'; then lvl=4
elif printf '%s' "$flags" | grep -qw 'avx2'; then lvl=3
elif printf '%s' "$flags" | grep -qw 'sse4_2'; then lvl=2
elif printf '%s' "$flags" | grep -qw 'sse2'; then lvl=1
fi
fi
punk_host_cpu_level=$lvl
echo "$lvl"
}
#G-172 map a recorded cpu_model name to an x86-64 level (1..4), or 0 for a
#specific uarch / unknown. A specific uarch (znver5, skylake...) is NOT a level
#- the codegen audit tool (scriptlib/developer/cpufloor_audit.tcl) is the
#authoritative runnability check for those.
cpu_model_level() {
case "$1" in
x86_64) echo 1;;
baseline) echo 1;;
x86_64_v2) echo 2;;
x86_64_v3) echo 3;;
x86_64_v4) echo 4;;
*) echo 0;;
esac
}
#G-172 floor-vs-host verdict. $1 = path to the runtime's toml. Sets globals:
#floor_verdict (meets|below|unknown|norecord), floor_required, floor_host,
#floor_message, floor_cpu_floor, floor_cpu_model. 'below' => recorded codegen
#exceeds the host - the caller MUST NOT launch (would die with 0xC000001D).
#'unknown' => specific uarch or host undetermined: do not block, surface the audit.
cpu_floor_verdict() {
local toml="$1"
floor_cpu_floor=$(sed -n 's/^[[:space:]]*cpu_floor[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$toml" 2>/dev/null | head -n 1)
floor_cpu_model=$(sed -n 's/^[[:space:]]*cpu_model[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$toml" 2>/dev/null | head -n 1)
floor_host=$(host_cpu_level)
floor_required=0; floor_message=""
if [[ -z "$floor_cpu_model" ]]; then
floor_verdict="norecord"; return
fi
floor_required=$(cpu_model_level "$floor_cpu_model")
if [[ "$floor_required" -eq 0 ]]; then
floor_verdict="unknown"
floor_message="cpu_model='$floor_cpu_model' is a specific uarch (not an x86-64 level); runnability is verified by the codegen audit tool: tclsh scriptlib/developer/cpufloor_audit.tcl <runtime> (declared floor: $floor_cpu_floor)"
return
fi
if [[ "$floor_host" -eq 0 ]]; then
floor_verdict="unknown"
floor_message="host CPU level undetermined (/proc/cpuinfo unavailable); recorded cpu_model='$floor_cpu_model' (x86-64 v$floor_required), floor='$floor_cpu_floor' - runnability not verified"
return
fi
if [[ "$floor_host" -lt "$floor_required" ]]; then
floor_verdict="below"
floor_message="runtime built for cpu_model='$floor_cpu_model' (x86-64 v$floor_required) but this CPU is x86-64 v$floor_host - launching it would fail with STATUS_ILLEGAL_INSTRUCTION (0xC000001D). Aborting; use '$0 list' for a runtime this CPU can run."
return
fi
floor_verdict="meets"
}
#G-103 artifact metadata: a runtime may carry a <rootname>.toml beside it (emitted
#by the buildsuite kit-family-artifacts step / fetched from punkbin). Prints a
#short "[variant=... tcl=... rN ...]" summary for list output, "" when absent.
@ -274,6 +344,24 @@ metadata_summary() {
#integrity flag: a runtime filed under a platform folder its metadata says it
#was not built for (cross-platform fetch/staging misfiling)
[[ -n "$target" && "$target" != "$archtail" ]] && parts="$parts !TARGET-MISMATCH:$target"
#G-172 CPU floor surface + runnability annotation. floor= is informational; a
#!CPU-FLOOR:v<req> tag marks a row the local CPU cannot run - gated to the
#LOCAL platform only (a foreign-platform row is cross-build staging). Absent
#on pre-G-172 tomls. (runs in a command-substitution subshell - host_cpu_level
#caches only within this call, which is fine.)
local cfloor cmodel cmlevel hlevel
cfloor=$(sed -n 's/^[[:space:]]*cpu_floor[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" 2>/dev/null | head -n 1)
[[ -n "$cfloor" ]] && parts="$parts floor=$cfloor"
if [[ "$archtail" == "$local_platform" ]]; then
cmodel=$(sed -n 's/^[[:space:]]*cpu_model[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" 2>/dev/null | head -n 1)
if [[ -n "$cmodel" ]]; then
cmlevel=$(cpu_model_level "$cmodel")
if [[ "$cmlevel" -gt 0 ]]; then
hlevel=$(host_cpu_level)
[[ "$hlevel" -gt 0 && "$hlevel" -lt "$cmlevel" ]] && parts="$parts !CPU-FLOOR:v$cmlevel"
fi
fi
fi
[[ -n "$parts" ]] && printf '[%s]' "${parts# }"
}
#operator help (the 'help' action; the no-args case shows show_usage only).
@ -631,6 +719,12 @@ case "$action" in
#build-origin class (table-aware read - schema v2)
fclass=$(provenance_class < "${archdir}/${tomlname}")
[[ -n "$fclass" ]] && echo "provenance: class=$fclass"
#G-172: surface the recorded CPU floor as information. Fetch is UNGATED
#- a cross-platform fetch (-platform <p>) for another machine is normal
#and a local-CPU verdict would be meaningless there.
ffloor=$(sed -n 's/^[[:space:]]*cpu_floor[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "${archdir}/${tomlname}" 2>/dev/null | head -n 1)
fmodel=$(sed -n 's/^[[:space:]]*cpu_model[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "${archdir}/${tomlname}" 2>/dev/null | head -n 1)
[[ -n "$ffloor" || -n "$fmodel" ]] && echo "cpu floor: floor=$ffloor model=$fmodel"
else
rm -f "${archdir}/${tomlname}"
echo "no artifact metadata toml on server for $runtime (ok for pre-family runtimes)"
@ -874,6 +968,21 @@ case "$action" in
done
exit 1
fi
#G-172 floor verdict: selecting a runtime the local CPU cannot run is a
#named diagnosis instead of a silent 0xC000001D on the next 'run'. Only
#the LOCAL platform is gated - a foreign -platform folder is cross-build
#staging deployed elsewhere to run. 'below' blocks the selection.
if [[ "$platform" == "$local_platform" ]]; then
utoml="$archdir/$(rootname_of "$1").toml"
if [[ -f "$utoml" ]]; then
cpu_floor_verdict "$utoml"
if [[ "$floor_verdict" == "below" ]]; then
echo "punk-runtime use: $1 - $floor_message"
exit 1
fi
[[ "$floor_verdict" == "unknown" ]] && echo "punk-runtime use: $1 - $floor_message"
fi
fi
#G-103 artifact-tier names (-r<N>, immutable): 'use' MATERIALIZES the
#artifact into its WORKING name (name minus -r<N> - what mapvfs and
#projects reference), copies its metadata toml alongside, and selects
@ -942,6 +1051,20 @@ case "$action" in
fi
fi
activeruntime_fullpath="$archdir/$activeruntime"
#G-172 floor verdict: launching a runtime the local CPU cannot run is a
#named diagnosis instead of a silent 0xC000001D (#UD before main - the
#2026-08-06 AVX-512 regression failure mode). 'below' aborts before the
#launch; 'unknown' notes the audit tool but does not block (a -Dcpu=native
#local build runs on its own host by definition).
rtoml="$archdir/$(rootname_of "$activeruntime").toml"
if [[ -f "$rtoml" ]]; then
cpu_floor_verdict "$rtoml"
if [[ "$floor_verdict" == "below" ]]; then
echo "punk-runtime run: $activeruntime - $floor_message"
exit 1
fi
[[ "$floor_verdict" == "unknown" ]] && echo "punk-runtime run: $activeruntime - $floor_message"
fi
#echo "using $activeruntime_fullpath"
#(the action was already shifted off during the option scan - "$@" is
#exactly the runtime's argument list)
@ -1070,7 +1193,7 @@ case "$action" in
if [[ -n "$embedded" || -f "$sidecar" ]]; then
printf ' %-20s %-36s %s\n' "field" "embedded" "sidecar"
disagreements=""
for k in schema name class variant working_name revision target build_id origin packager builder source_url upstream_ref retrieved project project_url license build_host_platform tcl_patchlevel sha1 size built; do
for k in schema name class variant working_name revision target build_id origin packager builder source_url upstream_ref retrieved project project_url license build_host_platform tcl_patchlevel cpu_floor cpu_model sha1 size built; do
ev=""; sv=""
if [[ -n "$embedded" ]]; then
ev=$(printf '%s\n' "$embedded" | sed -n 's/^[[:space:]]*'"$k"'[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' | head -n 1)

158
src/scriptapps/bin/punk-runtime.ps1

@ -320,6 +320,22 @@ function Get-PunkRuntimeMetadataSummary {
if ($expectedplatform -ne "" -and $fields.ContainsKey('target') -and $fields['target'] -ne $expectedplatform) {
$parts += "!TARGET-MISMATCH:$($fields['target'])"
}
#G-172 CPU floor surface + runnability annotation. floor= is informational (the
#recipe's declared default); !CPU-FLOOR:v<req> marks a row the local CPU cannot
#run - gated to the LOCAL platform only (a foreign-platform row is cross-build
#staging, not runnable here regardless). Absent on pre-G-172 tomls (no tag).
if ($fields.ContainsKey('cpu_floor') -and $fields['cpu_floor'] -ne "") {
$parts += "floor=$($fields['cpu_floor'])"
}
if ($expectedplatform -eq $script:PunkLocalPlatform -and $fields.ContainsKey('cpu_model') -and $fields['cpu_model'] -ne "") {
$cmLevel = Get-PunkCpuModelLevel $fields['cpu_model']
if ($cmLevel -gt 0) {
$hLevel = Get-PunkHostCpuLevel
if ($hLevel -gt 0 -and $hLevel -lt $cmLevel) {
$parts += "!CPU-FLOOR:v$cmLevel"
}
}
}
if ($parts.Count -eq 0) {
return ""
}
@ -364,6 +380,99 @@ function Get-PunkRuntimeProvenanceClass {
}
return ""
}
#G-172 CPU instruction-set floor surfacing and runnability verdict. A runtime's
#metadata toml (and embedded record) carry cpu_floor (the recipe's declared default
#floor) and cpu_model (what the build ACTUALLY resolved to). A published artifact
#built at the recipe default records cpu_model="x86_64" (baseline, v1); -Dcpu=native
#honestly records the host uarch. The verdict compares the recorded codegen level
#to the local CPU so selecting/launching a runtime the local CPU cannot run is a
#NAMED diagnosis instead of a silent STATUS_ILLEGAL_INSTRUCTION (0xC000001D) -
#the failure mode of the 2026-08-06 AVX-512 regression (see G-172 Context). Fetch
#stays ungated (a cross-platform fetch for another machine is normal); only the
#local-only actions (use/run) gate, and list annotates rows the host cannot run.
#Host level detection: IsProcessorFeaturePresent (kernel32) with the documented
#PF constants (winnt.h): SSE2=10 (v1 baseline), SSE4.2=38 (v2), AVX2=40 (v3),
#AVX512F=41 (v4). Detected once and cached; a detection failure degrades to 0
#(unknown) and the verdict never blocks on unknown, so a detection gap cannot
#prevent a launch - only a POSITIVE below-floor verdict blocks.
$script:PunkHostCpuLevel = $null
function Get-PunkHostCpuLevel {
if ($null -ne $script:PunkHostCpuLevel) { return $script:PunkHostCpuLevel }
$code = @'
using System;
using System.Runtime.InteropServices;
public class PunkCpuFeat {
[DllImport("kernel32.dll")]
static extern bool IsProcessorFeaturePresent(uint feature);
public static int Level() {
if (IsProcessorFeaturePresent(41)) return 4; //AVX512F (x86-64 v4)
if (IsProcessorFeaturePresent(40)) return 3; //AVX2 (x86-64 v3)
if (IsProcessorFeaturePresent(38)) return 2; //SSE4.2 (x86-64 v2)
if (IsProcessorFeaturePresent(10)) return 1; //SSE2 (x86-64 v1 baseline)
return 0;
}
}
'@
try {
Add-Type -TypeDefinition $code -ErrorAction Stop
$script:PunkHostCpuLevel = [PunkCpuFeat]::Level()
} catch {
#P/Invoke unavailable (locked-down host / broken PS): degrade to unknown
$script:PunkHostCpuLevel = 0
}
return $script:PunkHostCpuLevel
}
#G-172 map a recorded cpu_model name to an x86-64 level (1..4), or 0 for a
#specific uarch / unknown name. The standard zig level models map directly; a
#specific uarch (znver5, skylake, ...) is NOT a level - the codegen audit tool
#(scriptlib/developer/cpufloor_audit.tcl) is the authoritative runnability check
#for those, since punk-runtime cannot map a uarch name to a feature set.
function Get-PunkCpuModelLevel {
param([string] $cpuModel)
switch ($cpuModel) {
"x86_64" { return 1 }
"baseline" { return 1 }
"x86_64_v2" { return 2 }
"x86_64_v3" { return 3 }
"x86_64_v4" { return 4 }
default { return 0 }
}
}
#G-172 floor-vs-host verdict. $fields is the record-field hashtable from
#Get-PunkRuntimeRecordFields on the runtime's toml. Returns a hashtable:
# Verdict 'meets' | 'below' | 'unknown' | 'norecord'
# Required 0..4 (the recorded codegen level; 0 = unknown/specific-uarch)
# Host 0..4 (the local CPU level; 0 = undetermined)
# Message the diagnosis line (empty on meets/norecord)
# CpuFloor / CpuModel as recorded (empty if absent)
#'below' => the recorded codegen exceeds the host: launching would die with
#0xC000001D, so the caller MUST NOT launch. 'unknown' => cannot verdict by name
#(specific uarch or host undetermined): do not block, surface the audit tool.
function Get-PunkCpuFloorVerdict {
param([hashtable] $fields)
$cm = ""; if ($fields.ContainsKey('cpu_model')) { $cm = $fields['cpu_model'] }
$cf = ""; if ($fields.ContainsKey('cpu_floor')) { $cf = $fields['cpu_floor'] }
#NOTE: deliberately NOT named $host - that is a read-only automatic variable
#in PowerShell (the $Host object); reusing it throws VariableNotWritable.
$hlevel = Get-PunkHostCpuLevel
if ($cm -eq "") {
return @{ Verdict='norecord'; Required=0; Host=$hlevel; Message=""; CpuFloor=$cf; CpuModel=$cm }
}
$req = Get-PunkCpuModelLevel $cm
if ($req -eq 0) {
$msg = "cpu_model='$cm' is a specific uarch (not an x86-64 level); runnability is verified by the codegen audit tool: tclsh scriptlib/developer/cpufloor_audit.tcl <runtime> (declared floor: $cf)"
return @{ Verdict='unknown'; Required=0; Host=$hlevel; Message=$msg; CpuFloor=$cf; CpuModel=$cm }
}
if ($hlevel -eq 0) {
$msg = "host CPU level undetermined (IsProcessorFeaturePresent unavailable); recorded cpu_model='$cm' (x86-64 v$req), floor='$cf' - runnability not verified"
return @{ Verdict='unknown'; Required=$req; Host=0; Message=$msg; CpuFloor=$cf; CpuModel=$cm }
}
if ($hlevel -lt $req) {
$msg = "runtime built for cpu_model='$cm' (x86-64 v$req) but this CPU is x86-64 v$hlevel - launching it would fail with STATUS_ILLEGAL_INSTRUCTION (0xC000001D). Aborting; use 'punk-runtime list' for a runtime this CPU can run."
return @{ Verdict='below'; Required=$req; Host=$hlevel; Message=$msg; CpuFloor=$cf; CpuModel=$cm }
}
return @{ Verdict='meets'; Required=$req; Host=$hlevel; Message=""; CpuFloor=$cf; CpuModel=$cm }
}
#G-117 embedded record: zip CENTRAL-DIRECTORY read of the exe-appended archive via
#.NET System.IO.Compression (offsets resolve from the end-of-central-directory
#record, so the prepended executable data is no obstacle). The target is NEVER
@ -899,6 +1008,16 @@ function psmain {
#build-origin class (table-aware read - schema v2)
$fclass = Get-PunkRuntimeProvenanceClass ([string[]](Get-Content -Path $tomllocal))
if ($fclass -ne "") { Write-Host "provenance: class=$fclass" }
#G-172: surface the recorded CPU floor as information. Fetch is
#UNGATED - a cross-platform fetch (-platform <p>) for another
#machine is a normal workflow and a local-CPU verdict would be
#meaningless there, so only the recorded floor/model are printed.
$fflds = Get-PunkRuntimeRecordFields ([string[]](Get-Content -Path $tomllocal))
$ffloor = ""; if ($fflds.ContainsKey('cpu_floor')) { $ffloor = $fflds['cpu_floor'] }
$fmodel = ""; if ($fflds.ContainsKey('cpu_model')) { $fmodel = $fflds['cpu_model'] }
if ($ffloor -ne "" -or $fmodel -ne "") {
Write-Host "cpu floor: floor=$ffloor model=$fmodel"
}
} catch {
Write-Host "no artifact metadata toml on server for $runtime (ok for pre-family runtimes)"
}
@ -972,6 +1091,25 @@ function psmain {
}
exit 1
}
#G-172 floor verdict: selecting a runtime the local CPU cannot run is a
#named diagnosis instead of a silent 0xC000001D on the next 'run'.
#Only the LOCAL platform is gated - a foreign -platform folder is
#cross-build staging deployed elsewhere to run. 'below' blocks the
#selection; 'unknown' notes the audit tool but does not block.
if ($arch -eq $script:PunkLocalPlatform) {
$utoml = Join-Path -Path $archfolder -ChildPath ((Get-PunkRuntimeRootName $rtname) + ".toml")
if (Test-Path -Path $utoml -PathType Leaf) {
$uflds = Get-PunkRuntimeRecordFields ([string[]](Get-Content -Path $utoml))
$uverd = Get-PunkCpuFloorVerdict $uflds
if ($uverd.Verdict -eq 'below') {
Write-Host "punk-runtime use: $rtname - $uverd.Message"
exit 1
}
if ($uverd.Verdict -eq 'unknown') {
Write-Host "punk-runtime use: $rtname - $uverd.Message"
}
}
}
#G-103 artifact-tier names (-r<N>, immutable): 'use' MATERIALIZES the
#artifact into its WORKING name (name minus -r<N> - what mapvfs and
#projects reference), copies its metadata toml alongside, and selects
@ -1047,6 +1185,24 @@ function psmain {
}
$active = Join-Path -Path $archfolder -ChildPath $activename
write-host "using: $active"
#G-172 floor verdict: launching a runtime the local CPU cannot run
#is a named diagnosis instead of a silent 0xC000001D (#UD before
#main - the failure mode of the 2026-08-06 AVX-512 regression).
#'below' aborts before Start-Process; 'unknown' notes the audit
#tool but does not block (a -Dcpu=native local build runs on
#its own host by definition).
$rtoml = Join-Path -Path $archfolder -ChildPath ((Get-PunkRuntimeRootName $activename) + ".toml")
if (Test-Path -Path $rtoml -PathType Leaf) {
$rflds = Get-PunkRuntimeRecordFields ([string[]](Get-Content -Path $rtoml))
$rverd = Get-PunkCpuFloorVerdict $rflds
if ($rverd.Verdict -eq 'below') {
Write-Host "punk-runtime run: $activename - $rverd.Message"
exit 1
}
if ($rverd.Verdict -eq 'unknown') {
Write-Host "punk-runtime run: $activename - $rverd.Message"
}
}
if ($PSBoundParameters.opts.Length -gt 0) {
$optsType = $PSBoundParameters.opts.GetType() #method can only be called if .opts is not null
write-host "type of opts: $($optsType.FullName)"
@ -1399,7 +1555,7 @@ function psmain {
if ($havesidecar) { $sfields = Get-PunkRuntimeRecordFields ([string[]](Get-Content -Path $sidecarfile)) }
write-host (" {0,-20} {1,-36} {2}" -f "field", "embedded", "sidecar")
$disagreements = @()
foreach ($k in @('schema','name','class','variant','working_name','revision','target','build_id','origin','packager','builder','source_url','upstream_ref','retrieved','project','project_url','license','build_host_platform','tcl_patchlevel','sha1','size','built')) {
foreach ($k in @('schema','name','class','variant','working_name','revision','target','build_id','origin','packager','builder','source_url','upstream_ref','retrieved','project','project_url','license','build_host_platform','tcl_patchlevel','cpu_floor','cpu_model','sha1','size','built')) {
$ev = ""; $sv = ""
if ($efields.ContainsKey($k)) { $ev = $efields[$k] }
if ($sfields.ContainsKey($k)) { $sv = $sfields[$k] }

Loading…
Cancel
Save