8.5 KiB
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:™️: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:™️: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 tclInitoverride - which is what the tclkit lineage's boot.tcl IS - is dead in 9.1 (tclInterp.c:619-622) andtcl_libPathis gone. A design that works on both generations therefore has to hang offTcl_SetPreInitScriptrather 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, exportsTcl_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/_CVFSdriving$::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_Sizecall sites plus oneTcl_ChannelTypeand fiveTcl_ObjTypeinitialisers. 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.tclcarries the same code aspunk_main.tcltoday, 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.tclkit_type_mismatchcheck is named in Scope because a runtime that legitimately supports more than one container makes its premise false. It currently probesruntime_capsfor 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.