From 0e0a64eb23c7ff4a58d93f3886d2e526ee2a858a Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Wed, 29 Jul 2026 13:49:32 +1000 Subject: [PATCH] punk-runtime fetch: materialization hint when the working name is absent; punkshell 0.30.4 Closes the observed UX gap (G-128 detail, program-files checkout findings): fetch reports an active runtime, but bakes reference the suffixless WORKING name that only 'use' materializes - so a first fetch left bakelist reading runtime=missing with nothing pointing at the next step. Both payloads (ps1 + bash, parity wording) now print note: bakes and projects reference - materialize it with: punk-runtime use after fetching an -r artifact whose working name is absent, and stay silent once it exists (the downloads-never-bind rule is unchanged - fetch still materializes nothing). Sources edited under src/scriptapps/bin and bin/punk-runtime.cmd regenerated via scriptwrap multishell (-force 1; checkfile ERROR-free, 4 normal possibly-bogus warnings) - committed together per the wrap workflow; runtimecmd_roundtrip byte-identity passes. New pin runtimecmd_fetch_materialize_hint in runtimecmd_freshness.test (11/11, ~+5s: hint present on both payloads via the fixture server, absent after use via the cmd route). Live-verified against the real punkbin server from the spaced test checkout: hint fires on the no-download path too, silent with the working copy present. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com --- CHANGELOG.md | 10 +++++++ bin/punk-runtime.cmd | 17 +++++++++++ goals/G-128-portable-pe-resource-stamping.md | 10 +++++-- punkproject.toml | 2 +- src/scriptapps/bin/punk-runtime.bash | 7 +++++ src/scriptapps/bin/punk-runtime.ps1 | 10 +++++++ .../binscripts/runtimecmd_freshness.test | 28 +++++++++++++++++++ 7 files changed, 81 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fceb253..0ee23c10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ 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.30.4] - 2026-07-29 + +- `punk-runtime fetch` now prints a one-line materialization hint when the + fetched `-rN` artifact's WORKING name (what mapvfs and bakes reference) is + absent: "note: bakes and projects reference - materialize it + with: punk-runtime use ". Both payloads (ps1 + bash, parity + wording); silent once the working copy exists. Closes the surprise where + fetch reports an active runtime but `make.tcl bakelist` still reads + runtime=missing until `use` runs. + ## [0.30.3] - 2026-07-29 - Fleet renamed: every win32 kit now carries the embedded `PUNKSHELL` group diff --git a/bin/punk-runtime.cmd b/bin/punk-runtime.cmd index ff215c77..542334ee 100755 --- a/bin/punk-runtime.cmd +++ b/bin/punk-runtime.cmd @@ -1861,6 +1861,13 @@ case "$action" in echo "no artifact metadata toml on server for $runtime (ok for pre-family runtimes)" fi fi + #G-128 follow-through: a fetched -r artifact is not what bakes wrap - + #mapvfs and generated projects reference the WORKING name, which only + #'use' materializes. One line while that gap exists. + fetched_working="$(working_name_of "$runtime")" + if [[ -n "$fetched_working" && ! -f "${archdir}/${fetched_working}" ]]; then + echo "note: bakes and projects reference ${fetched_working} - materialize it with: punk-runtime use ${runtime}" + fi #first fetch establishes the active runtime; later fetches never steal it if [[ -z "$(get_active)" ]]; then set_active "$runtime" @@ -3478,6 +3485,16 @@ function psmain { Write-Host "no artifact metadata toml on server for $runtime (ok for pre-family runtimes)" } } + #G-128 follow-through: a fetched -r artifact is not what bakes + #wrap - mapvfs and generated projects reference the WORKING name, + #which only 'use' materializes. One line while that gap exists. + $fm = [regex]::Match($runtime, '^(.*)-r([0-9]+)(\.[Ee][Xx][Ee])?$') + if ($fm.Success) { + $fetchedworking = $fm.Groups[1].Value + $fm.Groups[3].Value + if (-not (Test-Path -Path (Join-Path -Path $archfolder -ChildPath $fetchedworking) -PathType Leaf)) { + Write-Host "note: bakes and projects reference $fetchedworking - materialize it with: punk-runtime use $runtime" + } + } #first fetch establishes the active runtime; later fetches never steal it if ((Get-PunkActiveRuntime $archfolder) -eq "") { Set-PunkActiveRuntime $archfolder $runtime diff --git a/goals/G-128-portable-pe-resource-stamping.md b/goals/G-128-portable-pe-resource-stamping.md index 79176420..eee8d6e9 100644 --- a/goals/G-128-portable-pe-resource-stamping.md +++ b/goals/G-128-portable-pe-resource-stamping.md @@ -361,5 +361,11 @@ the parked RT_VERSION stamping wants, since the project version is known late. even though it lists it as a candidate). Until then bakelist rows read runtime=missing; the `deployed` column is the KIT build/deploy state (absent in a fresh checkout is correct). Candidates flagged to the user: - suffixless `use` materializing from a sole matching -rN artifact, and/or - fetch hinting the `use` step for the platform default. + (a) fetch hinting the `use` step - IMPLEMENTED 2026-07-29 (user-directed, + punkshell 0.30.4): both punk-runtime payloads print "note: bakes and + projects reference - materialize it with: punk-runtime use + " when a fetched -rN artifact's working name is absent, silent + otherwise; pinned by runtimecmd_fetch_materialize_hint (both payloads via + the httpfixture server) and live-verified against the real punkbin server + from the spaced checkout; (b) suffixless `use` materializing from a sole + matching -rN artifact - still open, user-owned. diff --git a/punkproject.toml b/punkproject.toml index 3c47c2fb..1e075dc6 100644 --- a/punkproject.toml +++ b/punkproject.toml @@ -1,4 +1,4 @@ [project] name = "punkshell" -version = "0.30.3" +version = "0.30.4" license = "BSD-2-Clause" diff --git a/src/scriptapps/bin/punk-runtime.bash b/src/scriptapps/bin/punk-runtime.bash index 05f16451..d69d62eb 100644 --- a/src/scriptapps/bin/punk-runtime.bash +++ b/src/scriptapps/bin/punk-runtime.bash @@ -581,6 +581,13 @@ case "$action" in echo "no artifact metadata toml on server for $runtime (ok for pre-family runtimes)" fi fi + #G-128 follow-through: a fetched -r artifact is not what bakes wrap - + #mapvfs and generated projects reference the WORKING name, which only + #'use' materializes. One line while that gap exists. + fetched_working="$(working_name_of "$runtime")" + if [[ -n "$fetched_working" && ! -f "${archdir}/${fetched_working}" ]]; then + echo "note: bakes and projects reference ${fetched_working} - materialize it with: punk-runtime use ${runtime}" + fi #first fetch establishes the active runtime; later fetches never steal it if [[ -z "$(get_active)" ]]; then set_active "$runtime" diff --git a/src/scriptapps/bin/punk-runtime.ps1 b/src/scriptapps/bin/punk-runtime.ps1 index e691c484..5010fc69 100644 --- a/src/scriptapps/bin/punk-runtime.ps1 +++ b/src/scriptapps/bin/punk-runtime.ps1 @@ -848,6 +848,16 @@ function psmain { Write-Host "no artifact metadata toml on server for $runtime (ok for pre-family runtimes)" } } + #G-128 follow-through: a fetched -r artifact is not what bakes + #wrap - mapvfs and generated projects reference the WORKING name, + #which only 'use' materializes. One line while that gap exists. + $fm = [regex]::Match($runtime, '^(.*)-r([0-9]+)(\.[Ee][Xx][Ee])?$') + if ($fm.Success) { + $fetchedworking = $fm.Groups[1].Value + $fm.Groups[3].Value + if (-not (Test-Path -Path (Join-Path -Path $archfolder -ChildPath $fetchedworking) -PathType Leaf)) { + Write-Host "note: bakes and projects reference $fetchedworking - materialize it with: punk-runtime use $runtime" + } + } #first fetch establishes the active runtime; later fetches never steal it if ((Get-PunkActiveRuntime $archfolder) -eq "") { Set-PunkActiveRuntime $archfolder $runtime diff --git a/src/tests/shell/testsuites/binscripts/runtimecmd_freshness.test b/src/tests/shell/testsuites/binscripts/runtimecmd_freshness.test index 1ceea9d0..075ae4e7 100644 --- a/src/tests/shell/testsuites/binscripts/runtimecmd_freshness.test +++ b/src/tests/shell/testsuites/binscripts/runtimecmd_freshness.test @@ -434,6 +434,34 @@ namespace eval ::testspace { }\ -result [list 0 1 1 1 1 0 1] + #added 2026-07-29 (agent, G-128) - fetch of an -r artifact whose WORKING name + #is absent prints the one-line materialization hint (fetch downloads immutable + #artifacts; only 'use' binds the mapvfs-referenced working name); the hint + #disappears once the working copy exists. Presence pinned on both payloads; the + #absence-after-use case via the cmd route only (same guard in both payloads - + #invocation economy). + test runtimecmd_fetch_materialize_hint {fetch without a working copy hints the use step; silent once materialized}\ + -constraints $C -setup { + reset_stage + } -body { + set results {} + set hintpat "*note: bakes and projects reference fakert-alpha.exe - materialize it with: punk-runtime use fakert-alpha-r1.exe*" + set rp [run_cmdroute fetch fakert-alpha-r1.exe -platform testplat-x86_64] + lappend results cmd_exit [dict get $rp exit] + lappend results cmd_hint [string match $hintpat [dict get $rp output]] + set ru [run_cmdroute use fakert-alpha-r1.exe -platform testplat-x86_64] + lappend results use_exit [dict get $ru exit] + set rp2 [run_cmdroute fetch fakert-alpha-r1.exe -platform testplat-x86_64] + lappend results cmd_hint_after [string match $hintpat [dict get $rp2 output]] + reset_stage + set rb [run_bashroute fetch fakert-alpha-r1.exe -platform testplat-x86_64] + lappend results bash_exit [dict get $rb exit] + lappend results bash_hint [string match $hintpat [dict get $rb output]] + set results + } -cleanup { + reset_stage + } -result {cmd_exit 0 cmd_hint 1 use_exit 0 cmd_hint_after 0 bash_exit 0 bash_hint 1} + test runtimecmd_freshness_bash_series_mismatch_and_fetch_behind {bash payload extras: different-series actives get an incomparable verdict, and a diverging no-name fetch prints the BEHIND note with an inline activation hint}\ -constraints $C\ -setup {