From e42587cd79d0b079672e746cc33510cdf9cfc43e Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Sat, 8 Aug 2026 16:46:36 +1000 Subject: [PATCH] G-171 amendment: runtime-content masks (declared kit-level battery demotion) Extends the proposed goal with Approach 11 + matching Goal/Scope/Acceptance clauses and a Context assembly finding (2026-08-08): zip-kit bake EXTRACTS the runtime's attached vfs into the per-kit merge tree, so runtime batteries are structurally maskable - but supersedes/replace run in the VFSPAYLOAD phase before extraction and never reach them, so a bi-runtime kit with a lower-versioned payload battery ships both copies and highest-wins picks the runtime's. The amendment: mapvfs.toml kit-entry runtime_excludes applied at merge time after extraction - the payload version wins by absence of competition. Guardrails (boot-critical refusal, smokerequire proof), provenance (mask = declared config, punkkit-stamp runtime_masks key, no-volatile-fields safe; runtime's own record never edited), zip-lane first. Alternatives recorded: require-time pinning via the managed ::package override, runtime-variant proliferation. goals_lint clean. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com --- goals/G-171-bake-writes-land-untracked.md | 55 +++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/goals/G-171-bake-writes-land-untracked.md b/goals/G-171-bake-writes-land-untracked.md index f0c70aad..5f7bd4e0 100644 --- a/goals/G-171-bake-writes-land-untracked.md +++ b/goals/G-171-bake-writes-land-untracked.md @@ -1,9 +1,9 @@ # G-171 Routine builds never write tracked paths - explicit commands own VCS-visible changes Status: proposed -Scope: src/make.tcl (bake/bakehouse/vfslibs - VFSPAYLOAD + PACKAGES phases, kit assembly, new explicit materialize/tidy commands); src/make.tcl sync_layouts phase (the mint-side tracked-path write) with its targets src/project_layouts/ and src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/ plus the workflow_text TERMINOLOGY/DIAGRAM 1b stage-verb assignment; src/vfs/ (payload declarations, _targets staging generalization, README.md + AGENTS.md precedence spec); src/_bake (assembly staging); bin/packages (lib-tier consumption); .gitignore + .fossil-settings/ignore-glob (staging ignore coverage); src/tests/shell/testsuites/punkexe/ (kill-probe + precedence characterization) -Goal: routine build operations (mint, bake/bakehouse/vfslibs and every phase they run) write only to VCS-ignored locations - declared payloads materialize into ignored staging and merge-time layering enacts drop-in-wins precedence identically on every machine - so an interrupted, buggy, or stale-tool bake cannot modify, delete, or shadow tracked files and git/fossil status stays truthful during and after any build; deliberate writes into tracked trees (materializing a fetched/built package into a .vfs folder as drop-in content, retiring superseded committed files, refreshing the thin-layout store) remain available only as explicit separately-invoked commands whose output is an ordinary reviewable VCS change, with help and docs steering to the declaration-based route by default. -Acceptance: from a clean tree, a full bake/bakehouse run - including runs killed at arbitrary mid-run points (kill-probe characterization) - leaves git status and fossil changes reporting nothing outside ignore-covered paths; the VFSPAYLOAD/PACKAGES phases self-check their write destinations and abort before writing any tracked path; a hand-dropped file shadowing a declared payload entry survives assembly with drop-in-wins precedence on a records-free fresh clone (characterized, with the unified regime including _targets documented in src/vfs/README.md); the explicit materialize/tidy command(s) exist and are documented as the sole sanctioned tracked-tree write path, and no bake/bakehouse phase invokes them; a bake -hold run stops after assembly leaving the resolved per-kit images inspectable in staging, and a subsequent plain bake completes to kits identical to a single uninterrupted bake - staged assembly is reused only under digest-confirmed input currency, and stale or hand-modified held state is redone, never shipped; the thin-layout sync writes no tracked path from a mint or bakehouse run - refreshing the layout store and its modpod payload is an explicitly-invoked command producing an ordinary reviewable VCS change, the mint commands detect and report a stale store instead of silently refreshing it (the modules mint packs the tracked modpod tree as it stands), and make.tcl's stage vocabulary names the movement - the layout store documented as the third VCS-tracked consumption tree beside src/bootsupport and src/vfs/_vfscommon.vfs. +Scope: src/make.tcl (bake/bakehouse/vfslibs - VFSPAYLOAD + PACKAGES phases, kit assembly, new explicit materialize/tidy commands); src/make.tcl sync_layouts phase (the mint-side tracked-path write) with its targets src/project_layouts/ and src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/ plus the workflow_text TERMINOLOGY/DIAGRAM 1b stage-verb assignment; src/vfs/ (payload declarations, _targets staging generalization, README.md + AGENTS.md precedence spec); src/_bake (assembly staging); bin/packages (lib-tier consumption); .gitignore + .fossil-settings/ignore-glob (staging ignore coverage); src/tests/shell/testsuites/punkexe/ (kill-probe + precedence characterization); src/runtime/mapvfs.toml (kit-entry runtime-content mask declarations - 2026-08-08 amendment) +Goal: routine build operations (mint, bake/bakehouse/vfslibs and every phase they run) write only to VCS-ignored locations - declared payloads materialize into ignored staging and merge-time layering enacts drop-in-wins precedence identically on every machine - so an interrupted, buggy, or stale-tool bake cannot modify, delete, or shadow tracked files and git/fossil status stays truthful during and after any build; deliberate writes into tracked trees (materializing a fetched/built package into a .vfs folder as drop-in content, retiring superseded committed files, refreshing the thin-layout store) remain available only as explicit separately-invoked commands whose output is an ordinary reviewable VCS change, with help and docs steering to the declaration-based route by default; the same merge-time mask mechanism additionally gives a kit a DECLARED way to exclude runtime-extracted content, so a payload-supplied battery version can ship as the sole indexed candidate instead of losing highest-wins resolution to the runtime's copy (2026-08-08 amendment). +Acceptance: from a clean tree, a full bake/bakehouse run - including runs killed at arbitrary mid-run points (kill-probe characterization) - leaves git status and fossil changes reporting nothing outside ignore-covered paths; the VFSPAYLOAD/PACKAGES phases self-check their write destinations and abort before writing any tracked path; a hand-dropped file shadowing a declared payload entry survives assembly with drop-in-wins precedence on a records-free fresh clone (characterized, with the unified regime including _targets documented in src/vfs/README.md); the explicit materialize/tidy command(s) exist and are documented as the sole sanctioned tracked-tree write path, and no bake/bakehouse phase invokes them; a bake -hold run stops after assembly leaving the resolved per-kit images inspectable in staging, and a subsequent plain bake completes to kits identical to a single uninterrupted bake - staged assembly is reused only under digest-confirmed input currency, and stale or hand-modified held state is redone, never shipped; the thin-layout sync writes no tracked path from a mint or bakehouse run - refreshing the layout store and its modpod payload is an explicitly-invoked command producing an ordinary reviewable VCS change, the mint commands detect and report a stale store instead of silently refreshing it (the modules mint packs the tracked modpod tree as it stands), and make.tcl's stage vocabulary names the movement - the layout store documented as the third VCS-tracked consumption tree beside src/bootsupport and src/vfs/_vfscommon.vfs; a kit declaring a runtime-content mask (mapvfs.toml kit-entry runtime_excludes) bakes to an image where the masked runtime paths are absent and the payload-supplied version is the sole indexed candidate (smokerequire proves resolution at the declared version inside the built artifact), punkkit-stamp.toml records the masked paths, boot-critical paths (tcl_library, boot core) are refused at declaration parse, kits declaring no mask assemble byte-identical to pre-mask bakes, and non-zip kit types declaring masks abort with a stated reason. ## Context @@ -60,6 +60,26 @@ templates-0.2.0.tm carries the same run's make.tcl, so there is no one-run lag) and under this goal it moves with the rest into the explicit command, leaving the mint to pack the tracked modpod tree as it stands. +Assembly finding 2026-08-08 (surfaced by the punk-kit-on-bi-runtime version +question; motivates the runtime-content mask amendment). Zip-kit assembly +EXTRACTS the runtime's attached vfs into the per-kit merge tree - the zip +extraction comment in make.tcl states why: image assembly replaces the entire +attached archive, "so we need the original data to be part of our targetvfs". +A bi runtime's batteries therefore pass through the bake as ordinary +merge-tree files and are structurally maskable - yet no declared vocabulary +reaches them: supersedes/replace run in the VFSPAYLOAD phase against payload +trees BEFORE per-kit extraction, so a kit pairing a bi runtime with a +lower-versioned payload battery ships BOTH copies and Tcl's highest-wins +resolution picks the runtime's (the doctrine recorded in mapvfs.toml's own +comments). User direction 2026-08-08: bi kits may carry conservative battery +versions while punk kits advance - which needs "ship lower and have it win" +as a declared kit property, not a side effect of what happens to be indexed. +The merge-time mask mechanism of Approach 2 is the natural home: one mask +vocabulary over both the payload layering and the runtime-extracted tree +(Approach 11). Cookfs/cookit types edit the payload inside the mounted +runtime - no extract-merge moment - so the mask is zip-lane first and other +types abort with a stated reason. + ## Approach 1. Generalize the G-127 staging pattern: ALL declared payload entries (not just @@ -110,6 +130,26 @@ mint to pack the tracked modpod tree as it stands. generated from) - DIAGRAM 1b marks the store->modpod copy as mint input preparation rather than layout update, and the bakehouse help's "does NOT run the promotion gates" claim becomes true. +11. Runtime-content masks (2026-08-08 amendment; see the Assembly finding in + Context): the Approach 2 mask vocabulary generalizes to the + runtime-extracted portion of the per-kit merge. A kit entry in + src/runtime/mapvfs.toml declares exclusions (e.g. + runtime_excludes = ["lib/tcllib2.0"]) applied at merge time AFTER + extraction, so a payload-supplied lower version becomes the sole indexed + candidate and wins by absence of competition rather than by fighting + Tcl's highest-wins selection. Guardrails: boot-critical paths + (tcl_library, punkboot core) are refused at declaration parse; + interdependent-battery hazards (e.g. tcllibc compiled against a tcllib + version) stay the declarer's responsibility with smokerequire as the + proving surface (the 2026-07-27 Thread-shadowing incident is the + cautionary precedent for silent version substitution). Provenance: a + mask is declared config - a deterministic content input, so recording + it in punkkit-stamp.toml (a runtime_masks key) is no-volatile-fields + safe; the runtime's ridden-in punkbin-artifact.toml then overstates + attached_batteries for the masked kit, and the stamp's record of the + masked paths is the honest correction - the runtime's own record is + never edited. Zip-lane first; cookfs/cookit kits declaring masks abort + with a stated reason until an in-place arm exists. ## Alternatives considered @@ -122,6 +162,15 @@ mint to pack the tracked modpod tree as it stands. - Requiring committed payload removal first - rejected as sequencing: that is G-004's own arc (artifact coverage per package); this goal works with committed payloads still present and decouples their eventual removal from bake behaviour. +- Require-time version pinning instead of runtime-content masks (a declared pin + table enforced via the G-176-era managed ::package override) - workable and + kit-declarable, rejected for this goal's scope: both copies would still ship + (image weight, and the demoted copy stays findable by -exact requires), it + adds a runtime policy layer where assembly-time absence suffices, and it + belongs to the libunknown/commandstack arc if per-consumer version ranges are + ever wanted. Also rejected: runtime-variant proliferation as the only answer + (a suite-built variant per battery-version combination) - correct for + wholesale battery omission, combinatorial for per-kit version selection. ## Notes