Browse Source

G-127 increment 4: docs + records; punkshell 0.39.0

- bin/AGENTS.md: "Cross-target kit outputs (bin/kits/<platform>/)" contract
  section (locations, coexistence, ignore coverage, relocations + orphan note)
- src/AGENTS.md: target-keyed output bullet beside the G-122 host/target
  material (locations, name-spanning selection, %platform% payload axis)
- make.tcl workflow text per its update contract: [K9] output split, [K8]
  untracked additions, .vfs.toml %platform% line; bakelist helptext + report
  header name the kits/<platform>/ tier (both renders verified, width ok)
- punkproject.toml 0.38.0 -> 0.39.0 + CHANGELOG entry (minor bump: new
  declaration capability + relocated cross-target outputs)
- goal detail Progress: G-023 reconciliation stated (versioned outputs compose
  with the platform tier; release gate checks per-kit deploy dir), punkshell902
  + verify-ix86 relocation records finalized, punk9linux migration decision
  recorded (declared where a governed tier exists, hand-curated tcltls/tdom/
  thread drop-ins pending G-116/G-004)

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 1 week ago
parent
commit
d953ce5c07
  1. 24
      CHANGELOG.md
  2. 28
      bin/AGENTS.md
  3. 38
      goals/G-127-crosstarget-vfs-bake.md
  4. 2
      punkproject.toml
  5. 1
      src/AGENTS.md
  6. 23
      src/make.tcl

24
CHANGELOG.md

@ -5,6 +5,30 @@ 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.39.0] - 2026-07-31
- Target-keyed kit output locations (G-127): a kit whose mapvfs entry declares
a target other than the host's default now builds under
`src/_build/kits/<platform>/` and deploys under `bin/kits/<platform>/`
(per-tier punkcheck ledger; sidecar, arch scan, offset probe, smoke probe
and sweep guards follow), while default-target kits keep their flat
locations byte-identically. Same-named kits for different targets coexist -
the pre-G-127 cross-run overwrite and runtime-name disambiguation for
cross-target namesakes are gone; a kit name spanning targets selects all of
them in `bakelist` and selective `bake`. `bakelist` marks such rows with
`out=kits/<platform>/` and prints tiered paths in the detail block.
RELOCATIONS: linux `punkshell902` -> `bin/kits/linux-x86_64/punkshell902`;
the `verify-ix86` kits land at `bin/kits/win32-ix86/` on their next bake
(pre-move flat copies are orphans to remove by hand).
- Per-platform payload declarations (G-127 on the G-115 surface): a
`[payload.*]` source containing `%platform%` materializes once per CONSUMING
kit target (platform set derived from the kit mapping) into VCS-ignored
`_targets/<platform>/` staging inside the `.vfs` folder, and each kit's
merged image receives only its own target's subtree. punk9linux.vfs's
tcllibc entry migrated to the axis and its flat committed
`lib_tcl9/tcllibc` tree was removed from VCS (the packages tier and the
declaration govern it).
## [0.38.0] - 2026-07-31
- Kit mapping converted to toml (G-024, achieved): `src/runtime/mapvfs.toml`

28
bin/AGENTS.md

@ -170,6 +170,34 @@ set; and an unclassifiable binary is silence, not a pass. A kit whose bake recap
showed no `BUILD-WARNING`s still only proves what those checks measure - not that
every payload package loads.
### Cross-target kit outputs (`bin/kits/<platform>/`, G-127)
Kit OUTPUT locations are keyed by each kit's TARGET platform (the mapping's `target`
key - G-122's output half):
- A kit for this host's own default target deploys flat to `bin/<kit>` exactly as
always (build product `src/_build/<kit>`).
- Any other target's kit deploys to `bin/kits/<platform>/<kit>` (build product
`src/_build/kits/<platform>/<kit>`), each tier with its own `.punkcheck` install
ledger and the `<kit>.resources.toml` sidecar beside the kit as usual. `bin/kits/`
rather than `bin/<platform>/` because `bin/runtime/<platform>/` already means build
INPUTS - the two tiers sit side by side as input vs output.
- Same-named kits for DIFFERENT targets therefore coexist (the artifact path is a
pure function of name + target, and `.exe` suffixing follows the target); only a
same-name same-TARGET duplicate gets the historical `<name>_<runtime>` rename.
- `make.tcl bakelist` marks non-default-target rows with `out=kits/<platform>/` and
its per-kit detail block prints the tiered paths; a kit NAME spanning several
targets selects all of them (bakelist and selective bake alike).
- Everything under `bin/kits/` is a build output covered by the existing `/bin/*`
ignore rules in both VCS - never commit from it.
- Relocations at the 2026-07-31 switch: the linux `punkshell902` moved from
`bin/punkshell902` to `bin/kits/linux-x86_64/punkshell902` (intended relocation -
G-127), and the `verify-ix86` kits (`punkluck86`, `punk91ix86`, target
`win32-ix86`) land at `bin/kits/win32-ix86/` on their next bake. Pre-move flat
copies are orphans - remove them by hand.
- Characterization: `src/tests/shell/testsuites/punkexe/maketclkitlocations.test`
(fixture mappings via `PUNK_MAPVFS_CONFIG`).
### Kit resource record sidecar + embedded icon (G-057)
Every kit a bake builds ships with a `bin/<kitname>.resources.toml` text

38
goals/G-127-crosstarget-vfs-bake.md

@ -264,8 +264,38 @@ exists locally (empty but for sha1sums.txt) and punkbin upstream carries
the @group branch, so filtered bakelist detail and selective bake cover every
target of a shared name. Full punkexe subtree green: 15 files, 101 tests,
97 pass / 4 constraint-skips / 0 fail (88s, native Tcl903 runner).
- 2026-07-31 increment 4 (docs + records; punkshell 0.39.0):
bin/AGENTS.md gains the "Cross-target kit outputs (bin/kits/<platform>/)"
contract section; src/AGENTS.md gains the target-keyed-output bullet beside
its G-122 host/target material; make.tcl workflow text updated per its update
contract ([K9] output split, [K8] untracked additions, the .vfs.toml
%platform% line, bakelist helptext + report header); punkproject.toml bumped
0.38.0 -> 0.39.0 with the CHANGELOG entry (minor: new declaration capability +
relocated cross-target outputs).
G-023 RECONCILIATION (per Acceptance): version-named outputs COMPOSE with the
platform tier rather than competing - scheme-expanded records carry a target
like any entry and flow through the same per-kit location logic with no
special-casing, so a versioned scheme declaring target <p> yields
bin/kits/<p>/punk<gen>-<version> etc, and the G-023 release gate now checks
the per-kit deploy dir (kit_deploydir) rather than flat bin/. G-023's own
Acceptance naming bin/punk9-0.5.0.exe stays untouched: its outputs are
default-target today, and location only moves if a target is declared.
RELOCATION RECORDS (per Acceptance): punkshell902's move bin/punkshell902 ->
bin/kits/linux-x86_64/punkshell902 is an INTENDED RELOCATION (executed live
2026-07-31, increment 1); the verify-ix86 kits (punkluck86, punk91ix86)
relocate to bin/kits/win32-ix86/ on their next bake as the same rule's
consequence. Pre-move flat copies (bin/punkshell902, src/_build/punkshell902
+ .vfs image; later the flat ix86 kit copies) are orphans for manual removal
- also recorded in bin/AGENTS.md.
PUNK9LINUX MIGRATION DECISION (per Acceptance): punk9linux.vfs is MIGRATED to
the declaration for its tier-available payload - tcllib2.0 (neutral, G-115)
and tcllibc (per-platform %platform%, this goal; flat committed copy removed
from VCS) - while its remaining binary payload (tcltls, tdom, thread3.0.2
.so trees) DELIBERATELY STAYS HAND-CURATED until punkbin lib-tier artifacts
exist for those packages (suite-built tcltls is G-116's scope; the general
vendored-tree migration is G-004's recorded template). Mixed posture is the
honest record: declared where a governed source tier exists, hand-curated
drop-ins where none does yet.
- Remaining for acceptance: byte-comparability spot-check for a zip-type native
kit; bin/AGENTS.md + src/AGENTS.md output-location docs; G-023 reconciliation
statement recorded here; punkshell902 + win32-ix86 relocation records
finalized; punk9linux.vfs remaining drop-ins (tcltls/tdom/thread .so)
recorded as deliberately hand-curated or migrated.
kit (prefix + extracted-content comparison); full-suite/punkexe re-run at
closeout.

2
punkproject.toml

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

1
src/AGENTS.md

@ -77,6 +77,7 @@ Recovery after a wrong path guess:
- Kit bakes consume the punk-runtime WORKING COPIES under `bin/runtime/<platform>/`: `make.tcl bake`/`bakehouse` emit a `BUILD-WARNING:` (recapped at end of run) when a wrapped runtime's beside-toml revision is older than an `-r<N>` artifact present in the same folder - the forgot-to-switch-back guard for deliberate `punk-runtime use <old-rN>` testing excursions. Heed it before trusting freshly baked family kits; `bin/punk-runtime.cmd use <artifact-r<N>>` (`.exe` suffix optional) re-materializes the working copy.
- `tclsh src/make.tcl bakelist ?kitname|@group ...?` (G-121/G-024) reports the kit outputs configured in `src/runtime/mapvfs.toml`: kit name, kit type, runtime (with presence in the runtime store), vfs folder, and the deployed state of `bin/<kit>` vs the `src/_build` build product (`current|stale|absent|nobuild`), with anomalies (`runtime=missing`, `vfs=missing`, `rtrev=r<cur><r<max>` materialization staleness), the cross-target marker `target=<platform>`, groups (`group=<name>`), full-bake exclusion (`default=no`) and scheme roles (`scheme=versioned|dev|release`) in a trailing notes column. A nonexistent store tier is flagged loudly per tier actually referenced (header `(FOLDER MISSING)` for the default tier + stderr derivation; bake's no-runtimes exit self-diagnoses the same way). Name/@group arguments filter the report and add a per-kit detail block (resolved store tier, target and provenance of the target, config entry, group, paths/sizes/mtimes). `make.tcl bake ?kitname|@group ...?` bakes and deploys only the named kits - other kits' `_build`/`bin` artifacts and punkcheck records are untouched and the vfslibs phase narrows to the named kits' vfs folders; an unknown name errors before any build, listing the configured names and groups; flags go before kit names (`make.tcl bake -confirm 0 punk91`). Bare `bake` processes all configured kits except `bake_default=false` entries; a `versioned`-scheme release output (plain `punk<gen>` name) is created when absent and otherwise skipped - a normal bake never overwrites it (the explicit release step is G-023's). Both surfaces consume the shared parsed-mapping helpers (`::punkboot::lib::mapvfs_*`) rather than the file format (G-024: toml reader canonical, deprecated `mapvfs.config` line reader retained as fallback; `PUNK_MAPVFS_CONFIG` env points at an alternate config for characterization). Piped characterization: `src/tests/shell/testsuites/punkexe/maketclbakelist.test`.
- **Host vs target platform (G-122).** Everything a bake EMITS is keyed by the artifact's TARGET platform, never by the driving tclsh's personality: the `bin/runtime/<tier>` store the runtime is read from, `.exe` suffixing of runtime files and kit outputs, the presence checks behind `runtime=missing`, and whether the pre-deploy process sweep uses `tasklist`/`taskkill` or `ps`/`kill`. Host semantics - copy commands, path handling, filesystem case rules, prompts - stay keyed to the host. The default target is the host's own platform canon, EXCEPT a cygwin-family host (an msys2/cygwin-runtime tclsh, which reports `tcl_platform(platform)` `unix` on windows and canonizes as `msys-x86_64`/`cygwin-x86_64`), which targets `win32-x86_64`: such a host now drives the identical kit set, names and store addressing as a native tclsh. `tclsh src/make.tcl check` prints the derivation on one `platform (G-122): host=... target=... store=... exe-suffix=... process-tooling=...` line. A mapvfs entry may declare its own target platform (`target` key - see `src/runtime/AGENTS.md`), which is then read from that platform's tier, named with that platform's executable convention, and skipped by the process sweep (its processes are not visible to this host). Traps this closes, all field-verified 2026-07-26: msys `ps` cannot see a natively-launched kit (only `tasklist` can), and msys2 rewrites arguments that look like absolute posix paths when spawning a native windows program - so `taskkill /PID <n>` arrived as `taskkill C:/<msysroot>/PID <n>`; native-windows command lines therefore go through `::punkboot::exec_nativeargs` (sets `MSYS2_ARG_CONV_EXCL=*`, inert elsewhere). Also note a cygwin-family tclsh is a POSIX Tcl: name the script the way that shell spells paths (`tclsh /c/repo/.../src/make.tcl`, not `C:/repo/...`, which it resolves relative to the cwd) - make.tcl diagnoses the windows-spelling case. Piped characterization: `src/tests/shell/testsuites/punkexe/maketclplatform.test` (the cygwin-host tests self-gate on finding and probing a real msys/cygwin tclsh; `PUNK_MSYS_TCLSH` names one explicitly).
- **Target-keyed kit OUTPUT locations (G-127) - the output half of the G-122 split.** A kit for the host's default target builds to `src/_build/<kit>` and deploys to `bin/<kit>` exactly as always; any other target's kit builds under `src/_build/kits/<platform>/` and deploys under `bin/kits/<platform>/` (per-tier `.punkcheck` ledger; the merged `.vfs` image, resource sidecar, arch scan, offset probe, smoke probe and process-sweep guards all follow the per-kit location). Same-named kits for different targets coexist - the artifact path is a pure function of (name, target) and `.exe` suffixing follows the target - so separate selective bakes can never overwrite each other's cross-target artifacts; only a same-name same-TARGET duplicate keeps the `<name>_<runtime>` disambiguation. A kit NAME matching several targets' entries selects all of them (bakelist and selective bake). Per-.vfs payload declarations gain the same axis: a `[payload.*]` source containing `%platform%` materializes once per CONSUMING kit target into `_targets/<platform>/` staging inside the `.vfs` folder (VCS-ignored), and each kit's merged image receives only its own target's subtree upstream of the arch scan and G-125 gate (`src/vfs/README.md` "Per-platform entries"). Characterization: `src/tests/shell/testsuites/punkexe/maketclkitlocations.test`; output-tier contract for consumers: `bin/AGENTS.md` "Cross-target kit outputs".
- Zip-type kit assembly does not require zipfs in the driving tcl (G-122): with `tcl::zipfs::mkimg` present it is used as before, otherwise the image is assembled by concatenation (raw-runtime split + `punk::zip::mkzip` + append, the same `::punkboot::assemble_zipcat_image` helper the `zipcat` kit type uses). Both mount identically - tcl zipfs reads the archive with archive-start-relative offsets.
- Neither is EXTRACTING the runtime's own attached zip (needed to carry its `tcl_library` into the kit): `punk::zip` >= 0.2.0 reads a zip with stock Tcl only - no zipfs, no vfs::zip, no tcllib (G-124, the former tcllib `zipfile::decode` dependency is gone). The zipfs-less bake path splits off the executable prefix with `punk::zip::extract_preamble` and then reads the MEMBERS from the original runtime with `punk::zip::unzip`, never from the split-off intermediate: a runtime whose zip offsets are file-relative (the historical `zipfs mkimg` convention - `tclsh90b4_piperepl.exe` in the store is one) splits into a .zip whose offsets still count from the removed prefix, which plain zip readers reject. Reading the whole file at the derived base offset makes the two offset conventions indistinguishable to callers; `punk::zip::archive_info <file>` reports which one a given artifact uses. Verified 2026-07-26 by baking a zip kit from msys2's `/usr/bin/tclsh8.6` (no zipfs, no vfs::zip, no tcllib) and booting the result with its `tcl_library` present.
- What the RUNTIME must provide to be zip-kit-wrappable - which zipfs commands, mount conventions and startup hooks are supported - is documented in `bin/AGENTS.md` "Kit-wrappable runtime requirements (G-129)". Short form: `tcl::zipfs::mount` with pairwise no-arg output (`tcl::zipfs::root` NOT required), any attached-archive mount point (the boot derives it from the runtime's own mount table - the androwish/undroidwish 8.6 backport mounts at the executable's own path), a `main.tcl`/`app/main.tcl` startup hook, and a liftable library payload for the G-125 gate. The bake's runtime capability probe keys `has_zipfs` on `tcl::zipfs::mount` accordingly.

23
src/make.tcl

@ -2736,7 +2736,11 @@ DIAGRAM 2 - KIT ASSEMBLY DETAIL (the 'make.tcl bake' stage; incl. vfslibs phase)
entries materialized INTO the .vfs folder by the vfslibs
phase (vendor trees / bin/packages tier), punkcheck-
tracked with drop-in-wins precedence - undeclared or
hand-modified files are preserved, never overwritten
hand-modified files are preserved, never overwritten.
A source containing %platform% materializes once per
CONSUMING KIT TARGET (set derived from mapvfs) into
_targets/<platform>/ staging; each kit's merged image
then gets only its own target's subtree (G-127)
_vfscommon.vfs <kitspecific>.vfs <-- payload declarations (if any) already
| | materialized by the vfslibs phase
@ -2851,7 +2855,9 @@ KEY / NOTES
[K8] What is VCS-tracked where (checkin targets after a build):
tracked: src/** (sources, src/bootsupport, src/project_layouts copies,
src/vfs/_vfscommon.vfs), punkproject.toml, CHANGELOG.md
untracked: modules*/ lib*/ at projectroot, src/_build/, bin/<kit>.exe
untracked: modules*/ lib*/ at projectroot, src/_build/, bin/<kit>.exe,
bin/kits/<platform>/ (cross-target kit outputs - G-127),
src/vfs/*.vfs/_targets/ (per-platform payload staging)
(bin/ scripts/tools are tracked; kit executables are not)
[K9] HOST vs TARGET platform (G-122). What a bake EMITS is keyed by the target
@ -2866,6 +2872,12 @@ KEY / NOTES
process sweep.
'make.tcl check' prints the derivation; 'make.tcl bakelist' shows per-kit
targets, with a target= note on rows that are not on the default target.
OUTPUT locations are target-keyed too (G-127): default-target kits keep the
flat src/_build/<kit> + bin/<kit> locations, any other target's kit builds
and deploys under the kits/<platform>/ tier of both (bin/kits/ = outputs,
beside bin/runtime/ = inputs), so same-named kits for different targets
coexist instead of overwriting each other; bakelist marks such rows with
out=kits/<platform>/ and its detail block prints the tiered paths.
[K10] BOOT-PRECONDITION gate (G-125). A kit whose merged vfs has no tcl library
cannot initialise at all ('Cannot find a usable init.tcl'), so the bake
@ -3108,6 +3120,11 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
default - 'make.tcl check' shows that default), G-024 groups
(group=<name>), entries excluded from full bakes (default=no)
and scheme-expanded outputs (scheme=versioned|dev|release).
Non-default-target kits build and deploy under the
kits/<platform>/ tier of src/_build and bin (G-127) - their rows
carry out=kits/<platform>/ and the deployed state compares the
tiered paths; a kit NAME shared by entries for several targets
selects (and lists) every one of them.
kitname (or @groupname) arguments filter the report to the named
entries (per-kit detail, with resolved store tier, target,
config entry and paths). Reporting only - never builds."
@ -4765,7 +4782,7 @@ if {$::punkboot::command eq "bakelist"} {
append map_display " (deprecated format)"
}
}
puts stdout "# mapvfs: $map_display runtimes: bin/runtime/$rt_os_arch$rt_store_note deployed: bin/<kit> vs src/_build/<kit>"
puts stdout "# mapvfs: $map_display runtimes: bin/runtime/$rt_os_arch$rt_store_note deployed: bin/<kit> vs src/_build/<kit> (out= rows: under kits/<platform>/)"
set headline ""
foreach h $headings w $widths {
append headline [format "%-*s " $w $h]

Loading…
Cancel
Save