6.0 KiB
G-162 bakelist input-freshness: content-digest kit stamps and would-a-rebake-differ verdicts
Status: proposed Scope: src/make.tcl (bake stamp writer, bakelist report, digest/cache helpers); src/modules/punk/buildinfo-999999.0a1.0.tm (surface new stamp fields); src/vfs/ (payload trees as digest inputs); src/runtime/ (runtime artifacts and mapvfs.toml as consumed inputs); src/tests/shell/testsuites/punkexe/ (freshness pin) Goal: 'make.tcl bakelist' answers "would a rebake change this kit?" without baking: the bake records content digests of each kit's assembly inputs (payload vfs trees, runtime artifact, resolved mapvfs declaration, bake/assembler schema) in the deterministic punkkit-stamp.toml, and bakelist compares those against the current tree to report a per-kit input-freshness verdict (payload and runtime) alongside the existing deploy-state column - so a pulled or locally-promoted change to any input surfaces as 'stale' before anyone bakes. Acceptance: on a checkout where payload content consumed by a kit changed since that kit's last bake (e.g. one file modified under src/vfs/_vfscommon.vfs), 'make.tcl bakelist' reports that kit's payload verdict as stale without performing a bake, and reports current after a rebake; a runtime-store artifact differing from the stamped runtime digest is reported stale on the same terms; verdicts degrade per kit to 'n/a ()' - no deployed copy, pre-digest stamp schema, unreadable container, container driver unavailable - and a single unreadable kit never aborts or blanks the rest of the listing; zip kits are read pure-Tcl (punk::zip, no mount) on all supported build tclsh runtimes, mk4 kits are read when a metakit driver is loadable in the build interp and report n/a otherwise; stamps stay deterministic (identical inputs yield byte-identical stamp content across rebakes); a punkexe pin covers stale-detect, rebake-to-current and n/a degradation for at least one zip kit.
Context
The existing bakelist 'deployed' column (G-121, archived) byte-compares src/_bake/ against bin/ - a deploy-hop integrity check whose real target is the locked-exe trap (bake exits 0 but the bin copy is skipped while a running shell holds the exe). It says nothing about whether the bake product itself is stale relative to the tree: after a git pull or a local vfscommonupdate, nothing reports that a rebake would produce a different kit (user question 2026-08-03).
The inputs are already well-defined and mostly fingerprinted: mapvfs.toml declares each kit's vfs set and runtime (G-024/G-115, archived); the zip assembler computes a CRC32 for every payload entry during assembly, so a payload digest (hash over the sorted {relpath size crc} manifest) is nearly free at bake time; runtime artifacts carry sha1/size in their G-117 sidecars (archived); punkkit-stamp.toml (G-025, archived) is the deterministic in-kit stamp seam and punk::buildinfo already reads it (its live_vs_stamp verdict is project_version-granular only). Bake-side determinism work (G-031, archived) deliberately keeps time facts out of payloads.
Comparison must be manifest/digest-based, not whole-file byte comparison: zip entries carry source mtimes, so a rebake after a pull can differ byte-wise even with identical content. Current-side digest cost is a walk+CRC of the consumed vfs trees (sub-second cold; a {path size mtime}->digest cache brings the warm path to milliseconds, computed once per vfs and shared across kits).
Approach
- punkkit-stamp.toml schema 2: add per-input digests (one per consumed vfs tree, runtime artifact digest from/alongside the G-117 sidecar, resolved mapvfs declaration digest, bake/assembler schema version). No volatile fields (determinism preserved).
- bakelist: compute current-side digests with a warm cache; read the deployed kit's stamp per container type - zip via punk::zip central-directory member extraction (pure Tcl, no zipfs mount, works on all build tclshs), mk4 via mk4vfs/Mk4tcl only when loadable; anything else (or failure at any step) degrades that kit's verdict to 'n/a ()' without affecting other rows.
- New column semantics: payload current|stale|n/a, runtime current|stale|n/a; the existing deployed column is unchanged.
- Out of scope (possible follow-ons): upstream pipeline-hop verdicts (mint-pending, promotion-pending - derivable from punkcheck records); a -deep dry-run-assembly oracle for assembler-behaviour changes (the stamped bake schema version covers the common case); punk::buildinfo content-granular live-vs-source verdict (this goal only surfaces the new stamp fields in its report).
Notes
- Related: G-131 (one runtime, either payload - container autodetection) - shares the zip/mk4 container axis; the stamp reader's per-container dispatch should align with its detection conventions.
- Related: G-158 (punk86-kit parity on the suite-built mk4 head) - mk4 kits are the live exercise of the driver-unavailable n/a path.
- Related: G-023 (version-named punk binaries) - sibling surface: both shape bakelist rows and bin/ naming; no dependency either direction.
- Related: G-147 (libfetch revision check) - sibling read-only freshness-report pattern (server revisions for lib artifacts vs local input digests for kits).
- Related: G-137 (kit version resources via punkres) - sibling bake-time kit-stamping surface at the same make.tcl seam; its PE-resource stamping mutates the exe prefix after assembly, which is compatible with this goal's determinism claim (stamp content only, not whole-kit bytes).
- Overlap survey 2026-08-03: goals_xref paths src/make.tcl + buildinfo + src/runtime + src/vfs, plus score G-162 unlinked review; live intersections named above. Judged non-overlapping for this goal's mechanism: G-005/G-006/G-141 (runtime provisioning) and G-065 (declarative vendoring - a producer of payload changes this goal would report, no mechanism overlap).
- Related: G-171 - its staging move changes this goal's digest input set (authored .vfs + staging rather than the in-folder tree), and the per-kit digest machinery is shared with its hold/resume seam.