Browse Source
Two goals from the third-party 32-bit kit investigation, plus the finding that kept G-129 independent. G-129 Notes: the developer asked whether G-129 is needed to support baking with third-party kits. It is - it is the LAST blocker. The chain is: read the runtime's attached payload (G-124, achieved), do not let the boot-precondition gate falsely refuse it (G-125, achieved, plus the punkboot::utils 0.4.0 third-convention fix), then have the baked kit FIND that payload at boot (G-129). Measured by running punk_main.tcl's detection logic verbatim under bin/runtime/win32-ix86/tclsh8.6.10-luck-zip.exe: has_zipfs is 0, the //zipfs:/app branch is never computed, the kitpath branch is skipped, and NO internal module or lib paths are added - while tcl::zipfs::mount really does report the archive mounted at the exe path. So the failure is not "mounted somewhere unexpected and mis-resolved", it is "concluded there is no zipfs at all". This corrects an earlier recommendation to fold G-129 into G-131: folding would have parked third-party kit baking behind a much larger goal that needs a runtime carrying two container capabilities, which in turn needs G-101's port work. G-130 - 32-bit windows runtimes from the buildsuites, both Tcl generations. The motivation is supply, not architectural completeness: old, firewalled or sandboxed systems (industrial ones especially) are where 32-bit persists, they cannot fetch what they need, and a machine carrying binary Tcl modules built for only one major forces the runtime to match the modules. No single supplier keeps current 32-bit windows Tcl available for both majors. Acceptance keeps the binary-extension gate the developer asked for - each runtime must LOAD a real 32-bit extension, not merely start - because accepting drop-in modules is the whole point; twapi 4.7.2 inside the LUCK runtime is a 32-bit dll already in the tree for the 8.6 side. Both generations are required before the goal is met, since the motivating case is precisely that the machine's modules dictate the generation. KIT/CONTAINER TYPE IS DELIBERATELY OUT OF SCOPE - this goal produces runtimes, not kits; that question is G-101's. Sequencing per the developer: before or around the FreeBSD work, because a bitness change is likelier to surface recipe assumptions than another OS at the same bitness. Recorded as verified: punk::platform::local already reports win32-ix86 from a 32-bit interpreter and make.tcl derives the matching host/target/store, so no platform-canon work is needed. G-131 - one runtime, either payload: boot-time container autodetection (metakit or zipfs). Today a runtime's container is fixed when the runtime is ACQUIRED, so deliverables multiply by container: per platform, per generation, per container. If the boot detected what is attached, the container would become a bake-time choice and the count would collapse to platform x generation. Drafted to EXTEND G-129 rather than supersede it, and to depend on G-101 for the metakit arm to exist at all on a suite-built runtime. Its zipfs obligation is only that G-129's derivation still holds when reached through container detection. Carries two constraints found during the survey: the design must be preinit-shaped from the start, because G-101's Tcl 9 survey found the proc tclInit override the tclkit lineage relies on is dead in 9.1 and tcl_libPath is gone; and it explicitly rejects KitCreator's compile-time KIT_STORAGE_MK4/_ZIP/_CVFS switch - the closest prior art - because a compile-time answer still produces one binary per container. Scope names src/make.tcl's kit_type_mismatch check, whose premise (a runtime implies one container) this goal makes false. cookfs and other exotics are out of scope by the developer's decision. Assisted-by: harness=claude; primary-model=claude-opus-5[1m]; api-location=anthropic.commaster
4 changed files with 203 additions and 0 deletions
@ -0,0 +1,79 @@
|
||||
# G-130 32-bit windows runtimes from the buildsuites, both Tcl generations |
||||
|
||||
Status: proposed |
||||
Scope: src/buildsuites/suite_tcl90/ and src/buildsuites/suite_tcl86/ (the win32-ix86 target invocation and any recipe or flag divergence 32-bit forces); src/buildsuites/ (target dimension as settled by G-105 - no per-target tree copies); bin/runtime/win32-ix86/ (output tier - already holds the third-party comparison runtimes); punkbin per-target artifact layout with G-103 metadata carrying the target |
||||
Goal: punkshell's own buildsuites produce current 32-bit windows (win32-ix86) runtimes for BOTH Tcl generations from source with the pinned zig toolchain, so a machine that is old, firewalled or sandboxed - and that carries tcl8-only or tcl9-only binary modules which must be dropped in - can be served whichever generation its modules need from one supplier we control, instead of depending on third-party builds that no single source keeps current for both majors. |
||||
Acceptance: suite_tcl86 and suite_tcl90 each produce a win32-ix86 runtime through the documented target invocation, without disturbing the native build and without a per-target copy of the suite tree; each artifact runs on windows executing a script and resolving its bundled companions (thread and tclvfs for the 8.6 runtime, thread for the 9 runtime), with tcl_platform(pointerSize) 4 recorded; each loads a 32-bit BINARY EXTENSION - the motivating capability - verified against a real one rather than a stub (twapi 4.7.2 as shipped in bin/runtime/win32-ix86/tclsh8.6.10-luck-zip.exe is a 32-bit dll already in the tree for the 8.6 side; the 9-side extension is named at activation); each suite's core-testsuite run is recorded here against its own 32-bit baseline with every divergence from the corresponding 64-bit baseline dispositioned; any pointer-size or ABI assumption the 32-bit target exposes in the suite recipes is recorded; and the artifacts land in bin/runtime/win32-ix86/ and publish with G-103 metadata whose target names the 32-bit platform, so 'punk-runtime.cmd list -platform win32-ix86' shows them beside the third-party runtimes they are intended to replace. |
||||
|
||||
## Context |
||||
|
||||
The motivation is not architectural completeness, it is supply. Old, firewalled or |
||||
sandboxed systems - industrial ones especially - are where 32-bit still turns up, and |
||||
those are exactly the machines that cannot go and fetch what they need. Such a system may |
||||
carry binary Tcl modules built for only one major version, so the runtime has to match the |
||||
modules rather than the other way round. There is no single supplier keeping current 32-bit |
||||
windows Tcl available for BOTH majors, which means today the answer is assembled from |
||||
third-party builds of differing vintage and provenance. |
||||
|
||||
punkshell already builds Tcl from source with a pinned zig toolchain for both generations |
||||
(suite_tcl90, suite_tcl86 - G-096/G-098/G-099/G-100), and G-105 establishes the target as |
||||
an invocation dimension rather than a tree copy. 32-bit windows is the first target where |
||||
the change is one of BITNESS rather than OS, which is what makes it worth its own goal: it |
||||
exercises pointer-size and ABI assumptions that a linux-x86_64 cross does not. |
||||
|
||||
Two third-party 32-bit runtimes now sit in `bin/runtime/win32-ix86/` and serve as the |
||||
comparison baseline for what a suite-built pair would replace: |
||||
`tclsh8.6.10-luck-zip.exe` (Lean Undroidwish Construction Kit, Tcl 8.6.10, zipfs backport, |
||||
38 bundled packages) and `tclsh9.1b0-tclsfe.exe` (apnadkarni/tcl-sfe, Tcl 9.1b0). Between |
||||
them they demonstrate the shape is achievable; neither is ours, and neither is current for |
||||
the other's generation. |
||||
|
||||
## Approach |
||||
|
||||
- Treat 32-bit windows as one more value of G-105's target dimension, not a suite fork. |
||||
If it cannot be expressed that way, that is a finding about the dimension's design and |
||||
belongs back in G-105 before this goal proceeds. |
||||
- Build BOTH generations before declaring the goal met. A single-generation result does |
||||
not serve the motivating case, which is precisely that the machine's modules dictate the |
||||
generation. |
||||
- Gate on loading a real 32-bit binary extension. Producing a runtime that starts is not |
||||
the outcome; producing one that can accept the drop-in modules those systems carry is. |
||||
- Compare against the third-party specimens rather than only against a self-consistent |
||||
baseline - they are the status quo this replaces. |
||||
|
||||
## Alternatives considered |
||||
|
||||
- Keep sourcing 32-bit windows Tcl from third parties - rejected as the status quo the |
||||
goal exists to end: no single supplier is current for both majors, and provenance for a |
||||
locked-down deployment target is exactly where third-party binaries are weakest |
||||
(G-026/G-063 direction). |
||||
- Build 32-bit for one generation only (whichever is easier) - rejected: the motivating |
||||
systems are those whose existing binary modules force the choice of generation, so a |
||||
one-generation answer leaves half of them unserved. |
||||
- Defer until FreeBSD and other targets land - rejected on the developer's sequencing |
||||
(recorded 2026-07-27): this should slot in before or around the FreeBSD work, because |
||||
the bitness axis is likelier to surface recipe assumptions than another OS on the same |
||||
bitness, and finding those early is cheaper. |
||||
|
||||
## Notes |
||||
|
||||
- Depends on: G-105 - the target-as-invocation-dimension mechanism and the |
||||
punkshell-platform-dir vs zig-triple naming mapping. This goal is a consumer of that |
||||
decision and a second exercise of it after linux. |
||||
- Related: G-101 - which container a suite-built 8.6 runtime can be wrapped into is |
||||
decided there, not here. THIS GOAL PRODUCES RUNTIMES, NOT KITS: kit/container type is |
||||
deliberately out of Scope, so a 32-bit runtime that is not yet wrappable still satisfies |
||||
it. The two meet when G-101's decision lands. |
||||
- Related: G-123 - the artifacts publish through the runtime-tier mechanism, and |
||||
`punk-runtime.cmd list -platform win32-ix86` is where a user would see suite-built |
||||
runtimes appear beside the third-party ones. |
||||
- Related: G-129 - the third-party 8.6 specimen in this tier is what exposed punkshell's |
||||
kit-boot mount-point assumption. That is a boot-path concern and separate from producing |
||||
the runtime, but both goals use the same two specimens. |
||||
- Related: G-018 (superseded) - plain zig-built tclsh kits carrying no punk infrastructure; |
||||
the same "punkshell as a Tcl supplier, not only a shell" direction this goal serves. |
||||
- `punk::platform::local` already reports `win32-ix86` correctly from a 32-bit interpreter |
||||
(verified 2026-07-27 on both third-party runtimes), and `make.tcl check` derives |
||||
`host=win32-ix86 target=win32-ix86 store=bin/runtime/win32-ix86` when driven by one. No |
||||
platform-canon work is required; the tier name the store already uses is the canonical |
||||
one. |
||||
@ -0,0 +1,97 @@
|
||||
# G-131 One runtime, either payload: boot-time container autodetection |
||||
|
||||
Status: proposed |
||||
Scope: src/vfs/_config/punk_main.tcl and src/vfs/_config/project_main.tcl (container detection - extends the G-129 zipfs derivation to metakit; both files carry the same code); src/buildsuites/suite_tcl86/ and src/buildsuites/suite_tcl90/ (runtimes carrying both container capabilities, which the detection presupposes); src/make.tcl (the source/target kit-type mismatch check, which today assumes a runtime implies one container); src/runtime/mapvfs.config (kit type as a bake-time choice); bin/runtime/win32-ix86/ (zipfs specimens for the no-regression check); src/tests/shell/testsuites/punkexe/ (characterization); src/AGENTS.md + bin/AGENTS.md (what a runtime must provide) |
||||
Goal: one punk runtime per platform and Tcl generation boots from whichever payload container is attached to it - metakit or zipfs - so the container becomes a bake-time choice rather than a property fixed when the runtime is acquired, and the number of runtime deliverables is set by platform and generation alone. |
||||
Acceptance: ONE runtime binary, byte-identical between the two runs, boots and resolves its own payload from a metakit-wrapped kit AND from a zipfs-attached kit built from the same .vfs - internal modules/ and lib/ trees on tcl::tm::list and auto_path, and a package existing only inside the kit resolving, in both cases; container selection reads what is actually attached, with no compile-time or bake-time constant naming it, verified by wrapping that one runtime both ways from the same source tree; the zipfs arm is inherited from G-129 rather than re-specified - this goal's zipfs obligation is only that G-129's derivation still holds when reached through container detection, checked against the existing bin/runtime/win32-ix86 specimens; a runtime carrying a payload the boot cannot identify says so on stderr rather than continuing silently with no internal paths; punkshell's existing kits are unaffected, verified by comparing internal tcl::tm::list and auto_path before and after across at least one zipfs kit and one starkit-family kit; make.tcl's source/target kit-type mismatch check is reconciled with runtimes that legitimately support more than one container, rather than warning or skipping on them; cookfs and other exotics are explicitly out of scope with their existing branches untouched; and the deliverable reduction is recorded concretely - which runtimes collapse into which, and what the per-platform-per-generation count becomes. |
||||
|
||||
## Context |
||||
|
||||
Today a runtime's container is decided when the runtime is acquired, not when a kit is |
||||
baked: a tclkit-lineage runtime carries metakit and boots starkits, a zipfs runtime boots |
||||
zipfs images, and `src/runtime/mapvfs.config` pairs each kit with a runtime that can boot |
||||
the kit type it names. `make.tcl` encodes that coupling directly - it probes the source |
||||
runtime's capabilities and reports a `kit_type_mismatch` when they disagree with the |
||||
target kit type, warning and (under `-confirm 0`) skipping the kit. |
||||
|
||||
The consequence is a deliverable count multiplied by container. For each platform and each |
||||
Tcl generation punkshell must obtain, verify, publish and keep current a runtime PER |
||||
container it wants to be able to produce. That is also why a container decision like G-101's |
||||
feels weighty: picking the 8.6 container is picking what the 8.6 deliverable IS. |
||||
|
||||
If instead the boot detected what is attached, the container would become a bake-time |
||||
choice - the same runtime wrapped as a starkit or as a zipfs image depending on what the |
||||
bake wants that day. The deliverable count collapses to platform x generation, and G-101's |
||||
container decision stops being a fork in the road and becomes a default. |
||||
|
||||
The detection half is already partly built and about to be extended: `punk_main.tcl` |
||||
branches on zipfs, `::tcl::kitpath` (starkit) and a cookfs volume today, and G-129 replaces |
||||
the zipfs branch's compiled-in `//zipfs:/app` assumption with a derivation from the |
||||
runtime's own mount list. What is missing is (a) runtimes that carry both capabilities at |
||||
once and (b) a detection step that treats container type as a question rather than three |
||||
independently-written branches. |
||||
|
||||
## Approach |
||||
|
||||
- Extend, do not rewrite. G-129 lands the zipfs derivation and unblocks third-party kit |
||||
baking on its own; this goal generalises the same step to metakit and turns the branch |
||||
set into one detection decision. |
||||
- PREINIT-SHAPED FROM THE START. G-101's Tcl 9 survey found that the `proc tclInit` |
||||
override - which is what the tclkit lineage's boot.tcl IS - is dead in 9.1 |
||||
(tclInterp.c:619-622) and `tcl_libPath` is gone. A design that works on both generations |
||||
therefore has to hang off `Tcl_SetPreInitScript` rather than a tclInit override, and that |
||||
shapes the whole thing; discovering it late would mean rewriting the boot twice. |
||||
(UNVERIFIED there and still to check: whether 9.0.5, what suite_tcl90 actually builds, |
||||
exports `Tcl_SetPreInitScript`.) |
||||
- Detection reads evidence, not configuration: what is mounted, what the runtime can mount, |
||||
and what is actually attached to this executable. A bake-time or compile-time constant |
||||
naming the container defeats the purpose. |
||||
- Keep the blast radius honest: cookfs and other exotics stay out of scope and their |
||||
existing branches are left alone. Two containers is the whole win - it is what collapses |
||||
the deliverable count - and each further one costs capability weight in every runtime. |
||||
|
||||
## Alternatives considered |
||||
|
||||
- Compile-time container selection, as KitCreator does it (`KIT_STORAGE_MK4` / `_ZIP` / |
||||
`_CVFS` driving `$::tclKitStorage`, with boot.tcl branching on the result - see G-101's |
||||
Reference material) - rejected, and it is the closest prior art so the rejection matters: |
||||
a compile-time switch still produces one binary per container, which is exactly the |
||||
deliverable multiplication this goal exists to remove. It remains the right reference for |
||||
WHICH steps are container-specific. |
||||
- Keep one container per runtime and simply choose well once (the G-101 decision) - |
||||
rejected as the status quo: it leaves punkshell unable to bake a starkit and a zipfs kit |
||||
from one acquired runtime, and it keeps every future container question expensive. |
||||
- Detect at bake time and stamp the answer into the kit's main.tcl - rejected for the same |
||||
reason G-129 rejected stamping the mount point: it bakes a build-host assumption into the |
||||
artifact, and the running kit is in a strictly better position to look. |
||||
|
||||
## Notes |
||||
|
||||
- Depends on: G-129 - the zipfs mount-point derivation this generalises. That goal is |
||||
deliberately NOT superseded: it is small, it is the last blocker for baking a working kit |
||||
on a third-party runtime (see its Notes for the measured chain), and it delivers that on |
||||
its own well before a both-capabilities runtime exists. |
||||
- Depends on: G-101 - for the metakit arm to exist at all on a suite-built runtime. An 8.6 |
||||
binary carrying both needs metakit AND the androwish zipfs backport compiled in (both |
||||
surveyed there and both additive); a 9 binary carrying metakit needs the mk4tcl port that |
||||
goal costed at ~23 `Tcl_Size` call sites plus one `Tcl_ChannelType` and five |
||||
`Tcl_ObjType` initialisers. This goal runs ALONGSIDE G-101's decision - it does not wait |
||||
on it to be designed - but it cannot complete before that port work. |
||||
- Related: G-031 - the thin-main/shared-boot-core restructure. Container detection belongs |
||||
in the boot core, not in a per-project main; whichever lands second adopts the other's |
||||
shape. `project_main.tcl` carries the same code as `punk_main.tcl` today, which is why |
||||
both are in Scope until G-031 collapses them. |
||||
- Related: G-130 - its 32-bit runtimes are candidates to carry both capabilities, and the |
||||
deliverable-count argument is sharpest there: a new platform x two generations x two |
||||
containers is four artifacts to keep current, or two if this goal lands. |
||||
- Related: G-123 - fewer runtime deliverables is fewer artifacts to publish, checksum and |
||||
keep current in the punkbin tiers; the reduction this goal records is directly a |
||||
reduction in that goal's ongoing work. |
||||
- Related: G-024 - if the container becomes a bake-time choice, a mapvfs entry naming a kit |
||||
type stops implying a particular runtime, which is a simplification that lands on the toml |
||||
format work. |
||||
- The `make.tcl` `kit_type_mismatch` check is named in Scope because a runtime that |
||||
legitimately supports more than one container makes its premise false. It currently |
||||
probes `runtime_caps` for has_zipfs/has_starkit/has_cookfs and treats disagreement with |
||||
the target kit type as an error condition; with both-capability runtimes that disagreement |
||||
becomes the normal case. |
||||
Loading…
Reference in new issue