7.5 KiB
G-101 kit container strategy for zig-built Tcl 8.6 runtimes (no zipfs)
Status: proposed Scope: investigation + decision record under src/buildsuites/suite_tcl86/ (or successor mechanism); TEMP_REFERENCE/metakit + TEMP_REFERENCE/KitCreator (read-only guidance); src/runtime/mapvfs.config ('kit' type consumers); src/make.tcl kit-wrap path (as consumer) Goal: a decided, demonstrated strategy for wrapping zig-built 8.6 runtimes into self-contained punk86-class kit executables in the absence of zipfs - candidate containers: the metakit/mk4vfs tclkit lineage, cookfs, and zipvfs-over-tclvfs boot - so the prebuilt third-party kit runtimes (tclkit86bi.exe, tclkit-win64-dyn.exe) can eventually be replaced by suite-built, provenance-carrying ones. Acceptance: the candidate containers are assessed and recorded here against punkshell's kit expectations (compatibility with make.tcl's 'kit' wrap path or a documented replacement path; boot-time vfs mount without an installed Tcl; loading binary dlls from or via the container; buildable from source under the zig-only policy); one strategy is demonstrated end-to-end - a kit wrapped from the suite-built 8.6 runtime boots on a path without any Tcl installation and runs a script from inside its vfs; the decision, rationale, and the follow-on work needed to reach punk86-kit parity are recorded in this file.
Context
The genuinely new problem in the 8.6 arc: suite_tcl90's kits came almost for free because Tcl 9's zipfs makes exe+zip self-mounting (tclsh90szip.exe, punk905_beta zip-wrap). 8.6 has no zipfs, so a kit needs a vfs container and a boot mechanism:
- metakit/mk4vfs: the classic tclkit lineage (the current prebuilt runtimes are this). TEMP_REFERENCE/metakit and TEMP_REFERENCE/KitCreator were flagged by the user (2026-07-20, during the G-098 (achieved 2026-07-20) vlerq cleanup) as the guidance for when tclkit builds are investigated - the old vlerq/vqtcl references removed from the 9.0 recipe belonged to an earlier attempt at this same territory.
- cookfs: used by some modern kit builders (tcl-sfe lineage); C extension plus scripted boot.
- zipvfs over tclvfs: pure-tcl-plus-tclvfs zip mounting (vfs::zip is already built by the suites) with a boot preamble; no zipfs required but bootstrapping the vfs package itself from inside the container is the chicken-and-egg to solve.
make.tcl's existing 'kit' wrap type drives sdx/mk4-style wrapping; whichever container is chosen must either fit that path or come with a documented successor.
The G-103 runtime kit family (achieved 2026-07-22 - see goals/archive/G-103-runtime-kit-family.md; plain/punk/bi kits with thread + tclvfs + tcllib batteries in the attached container) extends to 8.6 THROUGH this investigation: the user notes (2026-07-20) that in the 8.6 case tclvfs may have to be STATIC and there may be metakit-specific patching - both are part of this goal's assessment, and the 8.6 family variant is blocked on its outcome.
Separated from G-099/G-100 deliberately: runtime + libs + test gating are well-understood ports of the 9.0 work, while this is open investigation - keeping it out of their acceptance keeps the 8.6 suite arc incrementally landable.
SEQUENCING: proposed; naturally last in the 8.6 arc (needs the G-099 runtime to wrap), and only worth activating once G-099/G-100 land.
Notes
- 2026-07-21: the prebuilt runtimes this goal replaces (tclkit86bi.exe, tclkit-win64-dyn.exe) are Metakit tclkits - self-contained (Tcl + VFS embedded) yet DYNAMICALLY linked to libc. That dynamic libc is what lets them 'load' binary extensions (OS dlopen/LoadLibrary + Tcl's stubs table, with the extension copied out of the mk4vfs to a temp dir first; the host does NOT need to export Tcl symbols - stubs hand the table to the extension via the interp). Consequence for the container choice: "loadable binary batteries" implies a DYNAMIC-libc runtime - a fully-static-libc 8.6 kit would hit the same 'load' limitation G-105 records for linux (the compiled-in static-packages alternative is G-058, achieved 2026-07-10 - see goals/archive/G-058-static-runtime-packages.md). The container question (metakit/cookfs/zipvfs) is orthogonal to the libc-linking question; keep them separate at activation.
- 2026-07-21: temp-copy cleanup applies here too - Metakit/starkit 'load' copies the extension out of the VFS to a temp dir (same as zipfs), and cleanup of those copies is a known wart (Tcl core TIP 741, windows-framed). This goal's "loading binary dlls from or via the container" acceptance should characterize that cleanup per platform - TIP 741 detail + requirement in G-103 Notes.
- 2026-07-22: the G-103 family attached-image contract this goal was promised as its concrete payload target now EXISTS (G-103 Progress 2026-07-22; archived): a family runtime's image is tcl_library/ at the container root position the boot searches, tm tree at tcl9/ (8.6: tcl8/), batteries at lib/ with installed-shape pkgIndexes + dlls at bin/, and a one-line stock auto_path hook at lib/pkgIndex.tcl. The 8.6 container investigation targets delivering THAT payload shape (adjusted for 8.6 boot: no zipfs /app anchor - the metakit/cookfs/zipvfs mount point plays the /app role and the hook mechanism must be re-verified against 8.6's tclPkgUnknown).
- 2026-07-25: launch-mechanism ladder for Tk apps launched from Explorer/shortcuts
(spike-validated on punk91/punk86): (1) punkapp::hide_console stays dev-only -
SW_HIDE on the console HWND hides the whole terminal window under ConPTY/tabbed
terminals; (2) in-place FreeConsole + close/open-NUL std reassignment works on
8.6 and on stock 9.x + 9.0.x-era punk kits (Tcl installs the next created channel
into the vacated std slot - tclIO.c Tcl_CreateChannel; recipe
chan close stderr; open NUL wyields a channel auto-named stderr), and since the 9.1-kit std-slot pin was fixed (G-120, achieved 2026-07-25 - a leaked punk::libunknown static-probe child interp held the std channels; libunknown 0.2.2 - see goals/archive/G-120-scriptmode-std-channel-pin.md) it works on the current 9.1 kit too, so in-place stdio repair is available across current kits; (3) relaunch-self via twapi::create_process -noconsole is the primary cross-generation mechanism (hidden console, stdio + package require Tk verified working, no channel surgery; the brief console flash is OS-unavoidable for console-subsystem exes; sign release binaries against self-spawn AV heuristics); (4) a GUI-subsystem punkw-class wrapper is the only zero-flash option (prior art: punkwish91.exe is a full GUI-subsystem punk kit); DETACHED_PROCESS semantics are a trap (no std handles; Tk load fails on Tcl 9). bgerror must be guarded or stdio repaired before detach: punk::repl::bgerror writes stderr (silent output loss on 9.x post-detach; not fatal on 9.1 per spike). - 2026-07-25: trial-kit naming convention (user direction): the G-103 scheme holds for 8.6 family runtimes - artifacts tclsh[-punk[-bi]]-r.exe; during container trials the container tag rides the artifact modifier chain (e.g. tclsh8.6.17-punk-cookfs-r1.exe / -mk4 / -zipvfs) and drops once the container decision lands; kit names stay punk86-class. tclkit/tclkitsh naming is not revived for punk-built artifacts (the -sh suffix implies a GUI sibling that will not exist; current kit downloads already use bare tclkit for console builds). Any future zero-flash launcher takes the w-suffix convention (punkw) rather than -gui/-cli (which in kit lineage encode Tk linkage, not subsystem).