From bd65183061a968b2ae93fb3a53949e0b3d66a8df Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Wed, 29 Jul 2026 11:48:54 +1000 Subject: [PATCH] G-128: seam names the kit group icon PUNKSHELL (icon-derived, both arms); punkshell 0.30.2 RT_GROUP_ICON name policy (user decision 2026-07-29): kit_icon_process derives icon_group from the icon FILE's uppercased rootname (RC convention) - punkshell.ico -> PUNKSHELL for the default icon and per-kit overrides alike - and passes it to whichever mechanism embeds. punkres arm uses set-icon -group (punkres 0.2.0); kit_icon_embed_twapi gains the matching optional group_override (name only - language adoption unchanged) so the arms stay in parity. Replaces the retained stub-lineage names (punk91 "SFE", suite kits "TCLSH"); already-deployed kits keep theirs until their next natural rebuild (the policy is not in the punkcheck source set). Sidecar gains icon_group (recorded whenever the icon file exists); bin/AGENTS.md format doc + ARCHITECTURE.md updated, architecture_lint clean. Live-verified on punkluck86 rebakes: punkres arm and twapi arm (TCLLIBPATH route) both emit RT_GROUP_ICON "PUNKSHELL" lang 1033, extracted icons byte-identical between arms; sidecar icon_group=PUNKSHELL; final deployed state punkres-stamped and booting. Full punkexe suite 83 tests 0 failed. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com --- ARCHITECTURE.md | 2 +- CHANGELOG.md | 11 ++++ bin/AGENTS.md | 12 +++-- goals/G-128-portable-pe-resource-stamping.md | 35 ++++++++---- punkproject.toml | 2 +- src/make.tcl | 57 ++++++++++++++------ 6 files changed, 87 insertions(+), 32 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 7f70afc1..95a13bd1 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -87,7 +87,7 @@ Two layers with a deliberate dependency direction (the class never depends on th - **Provenance gates.** Build/promotion commands warn on uncommitted `src/` changes (column-0 `PROVENANCE-WARNING:` token, `-dirty-abort` for strict mode); `vendorupdate` warns for dirty source-project checkouts. - **Boot-precondition gate (G-125).** A bake refuses a kit whose merged `.vfs` supplies no tcl library rather than deploying an artifact that cannot initialise: the kit lands in `FAILED KITS` and nothing is written, so the previously deployed `bin/` survives. Structural and non-executing (so cross-target kits are covered), reading the merged tree rather than the extraction outcome. The predicate is `punkboot::utils::vfs_boot_library_report`, called through the same guarded require as the provenance check so a stale bootsupport snapshot degrades it to a notice; `make.tcl check` reports ACTIVE/UNAVAILABLE. Sources: `src/AGENTS.md`, `src/modules/punkboot/utils-999999.0a1.0.tm`. - **Payload/target consistency checks (G-133), both advisory.** At the same post-merge seam, a bake classifies each binary library in the merged tree by header (`punkboot::utils::binary_arch_classify` - PE/ELF/Mach-O, honest unknowns) against the kit's target platform; wrong-arch libraries outside platform-discriminated subdirs (canonical `-` names, vendor spellings like `win-x64`) earn recapped `BUILD-WARNING`s. After assembly, a kit declaring smoke-require packages (`mapvfs.config` 5th entry element) has each one plain-`package require`d inside the freshly built artifact via its tclsh subcommand - the only check that sees resolution-order defects (wrong-arch version shadowing); cross-target kits skip with a stated reason. Same guarded-require degradation; `make.tcl check` reports both. Neither guarantees statics, pure-tcl packages with binary deps, or version preference beyond the declared smoke set. Sources: `src/AGENTS.md`, `src/runtime/AGENTS.md`, `src/modules/punkboot/utils-999999.0a1.0.tm`. -- **Kit icon step (G-057 + G-128).** Every kit a bake builds gets a `.resources.toml` sidecar (deployed beside `bin/`) recording the build-time icon choice - default `src/runtime/punkshell.ico`, overridable by a root `punkshell.ico` in the kit's own custom `.vfs` folder (pre-merge) - with sha256 identity and provenance lifted from the icon's G-135 assetorigin record. win32-target kits get the icon embedded as PE `RT_ICON`/`RT_GROUP_ICON` behind a single seam (`::punkboot::kit_icon_process`): the vendored punkres portable stamper (`src/tools/punkres`, built to `bin/punkres(.exe)` by the make.tcl tool step) is selected when present and works from any build host; otherwise the twapi arm (tcl-sfe mechanism) serves windows hosts with nothing built. Both arms share one semantic (delete all icon/group entries, write ids 1..N under the first pre-existing group's name+lang) and stamp a per-kit copy of the payload-free raw runtime prefix BEFORE payload attach; punkres can also stamp a FINISHED kit post-hoc, preserving an appended zip payload (archive-relative moved verbatim; file-relative refused by default, shifted with a consent flag). Non-PE targets skip as not applicable; a host where neither mechanism serves skips with a combined notice naming the punkres build remedy; the sidecar is written in every case. Sources: `src/AGENTS.md`, `bin/AGENTS.md`, `src/vfs/AGENTS.md`, `src/tools/AGENTS.md`. +- **Kit icon step (G-057 + G-128).** Every kit a bake builds gets a `.resources.toml` sidecar (deployed beside `bin/`) recording the build-time icon choice - default `src/runtime/punkshell.ico`, overridable by a root `punkshell.ico` in the kit's own custom `.vfs` folder (pre-merge) - with sha256 identity and provenance lifted from the icon's G-135 assetorigin record. win32-target kits get the icon embedded as PE `RT_ICON`/`RT_GROUP_ICON` behind a single seam (`::punkboot::kit_icon_process`): the vendored punkres portable stamper (`src/tools/punkres`, built to `bin/punkres(.exe)` by the make.tcl tool step) is selected when present and works from any build host; otherwise the twapi arm (tcl-sfe mechanism) serves windows hosts with nothing built. Both arms share one semantic (delete all icon/group entries, write ids 1..N; the group is NAMED from the icon file's uppercased rootname - `PUNKSHELL` - with language adopted from the replaced group) and stamp a per-kit copy of the payload-free raw runtime prefix BEFORE payload attach; punkres can also stamp a FINISHED kit post-hoc, preserving an appended zip payload (archive-relative moved verbatim; file-relative refused by default, shifted with a consent flag). Non-PE targets skip as not applicable; a host where neither mechanism serves skips with a combined notice naming the punkres build remedy; the sidecar is written in every case. Sources: `src/AGENTS.md`, `bin/AGENTS.md`, `src/vfs/AGENTS.md`, `src/tools/AGENTS.md`. - **Buildsuites and the kit family.** `src/buildsuites/suite_tcl90/` builds Tcl/Tk/tcllib from source with a pinned zig toolchain and produces the runtime kit family (plain / punk / bi) plus artifact metadata (G-096-G-117 era: see archived goals G-096, G-098, G-102, G-103, G-107); artifacts publish to the punkbin repo that `bin/punk-runtime.cmd` fetches from. `src/buildsuites/suite_tcl86/` is the 8.6 sibling (G-099 + G-100, both achieved): a Tcl 8.6 windows runtime (static + dynamic shells, `tcl86t.dll`, on-disk lib tree - no zipfs, so no self-contained kit) with thread 2.8 + tclvfs + Tk 8.6 + tklib + tcllib(+tcllibc critcl accelerators) companions, gated against the 8.6 core/thread/tclvfs testsuites with tcllib/tklib on a record tier and an opt-in `test-tk`; punkshell's own runtests is censused on that runtime at parity with a same-day native-8.6 baseline. Suite child shells scrub `TCL__TM_PATH` as well as TCLLIBPATH/TCL_LIBRARY/TK_LIBRARY - without it a census measures the machine's module trees. The 8.6 kit container strategy remains in-flux - see "In-flux areas". - **Project generation.** `dev project.new` composes thin layouts from `src/project_layouts/` (overlay chain with `.anti` deletion markers and `name@base` derivation - G-087, achieved) and injects bootsupport modules from the generating shell at generation time. - **Workflow overview.** `tclsh src/make.tcl workflow` prints the embedded ASCII data-flow overview of the build/release pipeline, with its own update contract in `src/AGENTS.md`. This section deliberately summarises rather than copies it. diff --git a/CHANGELOG.md b/CHANGELOG.md index 547a43f1..47ce59e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ 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.2] - 2026-07-29 + +- Baked kits' embedded RT_GROUP_ICON is now NAMED from the icon file's + uppercased rootname - `PUNKSHELL` for `punkshell.ico` (default and per-kit + overrides alike) - instead of retaining the stub lineage's name ("SFE", + "TCLSH"). Applied identically by both icon mechanisms (punkres 0.2.0 + `set-icon -group`; the twapi arm gained the matching override), language + still adopted from the replaced group. The `.resources.toml` sidecar + records the name as `icon_group`. Already-deployed kits keep their old + group name until their next rebuild. + ## [0.30.1] - 2026-07-29 - Portable PE resource stamping (G-128, first increment): new vendored zig tool diff --git a/bin/AGENTS.md b/bin/AGENTS.md index 11e01d4b..8d708c65 100644 --- a/bin/AGENTS.md +++ b/bin/AGENTS.md @@ -168,8 +168,12 @@ never modified). Two mechanisms share one semantic and yield equivalent resource content (G-128 parity evidence): `bin/punkres(.exe)` - the vendored portable stamper, built via `make.tcl tool build punkres`, host-independent - is selected when present; otherwise the twapi arm serves windows hosts with -nothing built. Named "resources", not "icon", so the parked RT_VERSION -stamping extends the same file. +nothing built. The embedded RT_GROUP_ICON is NAMED from the icon file's +uppercased rootname (`punkshell.ico` -> `PUNKSHELL`, RC convention; applies +to per-kit overrides identically since they are also named `punkshell.ico`), +with the resource language adopted from the group being replaced. Named +"resources", not "icon", so the parked RT_VERSION stamping extends the same +file. - Icon choice: a root-level `punkshell.ico` in the kit's own custom `.vfs` folder (consulted pre-merge, so the `_vfscommon.vfs` copy never reads as an @@ -183,7 +187,9 @@ stamping extends the same file. path of the chosen icon); `icon_hash` (`sha256:`-prefixed); `icon_provenance_source` / `icon_provenance_source_hash` (lifted from the chosen icon's `.assetorigin.toml` when one exists - the record then reaches - back to the SVG-derived master); `embedding` = `punkres` | `twapi` | `none`; + back to the SVG-derived master); `icon_group` (the derived RT_GROUP_ICON + resource name, present whenever the icon file exists - recorded even when + embedding did not run); `embedding` = `punkres` | `twapi` | `none`; `embedding_status` = `embedded` | `not-applicable` | `unavailable` | `failed`; `embedding_reason` (empty when embedded). - Skip semantics: a target with no PE resources (linux, freebsd, macosx diff --git a/goals/G-128-portable-pe-resource-stamping.md b/goals/G-128-portable-pe-resource-stamping.md index f880aabc..35e01ac0 100644 --- a/goals/G-128-portable-pe-resource-stamping.md +++ b/goals/G-128-portable-pe-resource-stamping.md @@ -173,17 +173,20 @@ the parked RT_VERSION stamping wants, since the project version is known late. stamping-support review). No acceptance wording change; revisit if other payload shapes (cookit/cookfs, or a G-101-chosen container) become stamping targets - a dedicated goal is warranted only then. -- Group naming (2026-07-29, user-directed): punkres 0.2.0 adds - `set-icon -group ` overriding the adopted RT_GROUP_ICON name - (stored as given, case-insensitive lookups; language + codepage adoption - unchanged; re-stamps without the flag adopt the renamed group, so renaming - is convergent). Motivation: stamped kits carry their stub lineage's group - name (punk91 "SFE", suite-runtime kits "TCLSH") where a punkshell-derived - name reads better. SEAM DEFAULT NOT CHANGED yet - flipping the bake to pass - a derived name (e.g. the icon file's root name, giving "punkshell" for both - the default icon and per-kit overrides) needs the twapi arm to gain the - same override for parity, and changes every baked kit's resource listing - - proposal outstanding with the user. +- Group naming (2026-07-29, user-directed; DEFAULT DECIDED same day): punkres + 0.2.0 adds `set-icon -group ` overriding the adopted RT_GROUP_ICON + name (stored as given, case-insensitive lookups; language + codepage + adoption unchanged; re-stamps without the flag adopt the renamed group, so + renaming is convergent). Motivation: stamped kits carried their stub + lineage's group name (punk91 "SFE", suite-runtime kits "TCLSH"). The SEAM + now derives the name from the icon FILE's uppercased rootname (user + decision: uppercase per the RC convention) - punkshell.ico -> PUNKSHELL for + the default icon and per-kit overrides alike - and passes it to whichever + arm embeds: kit_icon_embed_twapi gained the same optional group_override + for parity. The sidecar records it as icon_group (present whenever the icon + file exists). Kits already deployed keep their old group name until their + next natural rebuild (the naming policy is not in the punkcheck source set, + so it does not itself dirty kits). - Related: G-105 - recorded at activation (2026-07-29 overlap survey): the end-to-end non-windows-host acceptance clause needs a host-native punkres build; cross-target zig builds and target naming live in G-105 rather than here (the same division @@ -288,3 +291,13 @@ the parked RT_VERSION stamping wants, since the project version is known late. (user decision - see Notes); G-101 carries the container-review rider. BSD-2-Clause licence confirmed by user. Seam group-name default: proposal outstanding (Notes). +- 2026-07-29 increment 1b (user-directed): seam group-name default LANDED - + kit_icon_process derives icon_group = uppercased icon-file rootname + (PUNKSHELL) and passes it to both arms; kit_icon_embed_twapi gained the + matching group_override parameter (parity); sidecar gains icon_group + (bin/AGENTS.md + ARCHITECTURE.md updated). Live-verified on punkluck86 + rebakes: punkres arm and twapi arm (TCLLIBPATH route) both produce + RT_GROUP_ICON "PUNKSHELL" lang 1033 with byte-identical extracted icons + (codepage divergence as per the Notes finding); sidecar icon_group + + embedding recorded; final deployed state punkres-stamped and booting. + punkshell 0.30.2. diff --git a/punkproject.toml b/punkproject.toml index 0fd8452b..d1df9c35 100644 --- a/punkproject.toml +++ b/punkproject.toml @@ -1,4 +1,4 @@ [project] name = "punkshell" -version = "0.30.1" +version = "0.30.2" license = "BSD-2-Clause" diff --git a/src/make.tcl b/src/make.tcl index 3e3169ff..383113e1 100644 --- a/src/make.tcl +++ b/src/make.tcl @@ -6312,13 +6312,15 @@ proc ::punkboot::assemble_zipcat_image {raw_runtime wrapvfs outfile zipfile} { #consulted PRE-merge so the _vfscommon copy never reads as an override), and #win32-target kits get that icon embedded as PE RT_ICON/RT_GROUP_ICON resources #when this host can write them. Two mechanisms share one semantic (delete ALL -#icon/group entries, write the .ico images as ids 1..N under the first -#pre-existing group's name+lang - idempotent by construction, parity recorded -#in the G-128 detail file): the vendored punkres portable stamper (G-128, -#src/tools/punkres, built by 'make.tcl tool build punkres') is selected when -#bin/punkres(.exe) exists and works from ANY build host; otherwise the twapi -#arm (tcl-sfe sfe-0.2.tm ReplaceIconInStub lineage; Ashok P. Nadkarni) serves -#windows hosts with nothing built. Ordering is stub-first either way: a per-kit +#icon/group entries, write the .ico images as ids 1..N; the RT_GROUP_ICON is +#NAMED from the icon file - uppercased rootname, so punkshell.ico gives +#PUNKSHELL (user decision 2026-07-29, RC uppercase convention) - with language +#adopted from the first replaced group; idempotent by construction, parity +#recorded in the G-128 detail file): the vendored punkres portable stamper +#(G-128, src/tools/punkres, built by 'make.tcl tool build punkres') is +#selected when bin/punkres(.exe) exists and works from ANY build host; +#otherwise the twapi arm (tcl-sfe sfe-0.2.tm ReplaceIconInStub lineage; Ashok +#P. Nadkarni) serves windows hosts with nothing built. Ordering is stub-first either way: a per-kit #copy of the payload-free raw runtime prefix is stamped BEFORE any payload is #appended (punkres could also stamp post-hoc - the bake keeps stub-first so #both arms stay interchangeable). kit_icon_process is the single internal @@ -6538,12 +6540,14 @@ proc ::punkboot::kiticon::punkres_available {repo_root} { } #G-128 punkres arm: exec the vendored portable stamper on the payload-free stub #copy. punkres itself deletes all icon/group entries, writes the images as ids -#1..N under the first pre-existing group's name+lang, and re-reads its own +#1..N under the first pre-existing group's name+lang (a non-empty +#group_override renames the group via 'set-icon -group' - the seam's naming +#policy; language and codepage adoption unchanged), and re-reads its own #output (resources AND any overlay) before reporting success - equivalent #resource content to the twapi arm from the same input (parity evidence in the #G-128 detail file). Returns the number of images embedded; raises an error #carrying punkres's output on any nonzero exit. -proc ::punkboot::kit_icon_embed_punkres {punkres_exe exepath icopath} { +proc ::punkboot::kit_icon_embed_punkres {punkres_exe exepath icopath {group_override {}}} { set f [open $icopath rb] set icondata [read $f] close $f @@ -6554,7 +6558,12 @@ proc ::punkboot::kit_icon_embed_punkres {punkres_exe exepath icopath} { if {$ico_count == 0} { error "no images in $icopath" } - if {[catch {exec [file nativename $punkres_exe] set-icon [file nativename $exepath] [file nativename $icopath] 2>@1} output]} { + set cmd [list exec [file nativename $punkres_exe] set-icon] + if {$group_override ne ""} { + lappend cmd -group $group_override + } + lappend cmd [file nativename $exepath] [file nativename $icopath] 2>@1 + if {[catch $cmd output]} { error "punkres set-icon failed: $output" } return $ico_count @@ -6563,10 +6572,13 @@ proc ::punkboot::kit_icon_embed_punkres {punkres_exe exepath icopath} { #the images of icopath. Follows sfe-0.2.tm ReplaceIconInStub generalized: all #existing icon/group entries (any name, any lang) are deleted and the new set #written as ids 1..N under the first pre-existing group's name+lang (fallback -#name 1, lang 1033), in one resource-update transaction. Raises an error on -#failure (after -discard); returns the number of images embedded. The file at -#exepath must carry NO appended payload - a resource update rewrites the image. -proc ::punkboot::kit_icon_embed_twapi {exepath icopath} { +#name 1, lang 1033), in one resource-update transaction. A non-empty +#group_override replaces the group NAME only (language adoption unchanged) - +#the same override punkres's 'set-icon -group' applies, so the seam's naming +#policy keeps the two arms in parity (G-128). Raises an error on failure +#(after -discard); returns the number of images embedded. The file at exepath +#must carry NO appended payload - a resource update rewrites the image. +proc ::punkboot::kit_icon_embed_twapi {exepath icopath {group_override {}}} { set f [open $icopath rb] set icondata [read $f] close $f @@ -6601,6 +6613,9 @@ proc ::punkboot::kit_icon_embed_twapi {exepath icopath} { if {[llength $old_groups]} { lassign [lindex $old_groups 0] group_name group_lang } + if {$group_override ne ""} { + set group_name $group_override + } set update_h [twapi::begin_resource_update $exepath] try { foreach entry $old_icons { @@ -6649,6 +6664,15 @@ proc ::punkboot::kit_icon_process {targetkit rt_target rtname kit_type sourcefol set icon_path $sourcefolder/runtime/punkshell.ico } set have_icon [file isfile $icon_path] + #RT_GROUP_ICON name policy (G-128, user decision 2026-07-29): derived from + #the icon FILE's rootname, uppercased per the RC convention - punkshell.ico + #gives PUNKSHELL for the default icon and for per-kit overrides alike + #(overrides are by convention also named punkshell.ico). Applied by + #whichever mechanism embeds; language stays adopted from the replaced group. + set icon_group "" + if {$have_icon} { + set icon_group [string toupper [file rootname [file tail $icon_path]]] + } set embedding none set status "" set reason "" @@ -6687,10 +6711,10 @@ proc ::punkboot::kit_icon_process {targetkit rt_target rtname kit_type sourcefol catch {exec chmod +w $stamped} if {$punkres_ok} { set embedding punkres - set embed_cmd [list ::punkboot::kit_icon_embed_punkres $punkres_info $stamped $icon_path] + set embed_cmd [list ::punkboot::kit_icon_embed_punkres $punkres_info $stamped $icon_path $icon_group] } else { set embedding twapi - set embed_cmd [list ::punkboot::kit_icon_embed_twapi $stamped $icon_path] + set embed_cmd [list ::punkboot::kit_icon_embed_twapi $stamped $icon_path $icon_group] } if {[catch $embed_cmd embed_result]} { ::punkboot::print_build_warnings [list "kit icon embedding FAILED for $targetkit ($icon_origin icon $icon_path via $embedding): $embed_result - kit keeps its runtime's own icon"] @@ -6727,6 +6751,7 @@ proc ::punkboot::kit_icon_process {targetkit rt_target rtname kit_type sourcefol if {[dict exists $ao source_hash]} { lappend lines "icon_provenance_source_hash = \"[$esc [dict get $ao source_hash]]\"" } + lappend lines "icon_group = \"[$esc $icon_group]\"" } lappend lines "embedding = \"$embedding\"" lappend lines "embedding_status = \"$status\""