You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

11 KiB

G-025 Punk executables self-report project version and build provenance

Status: achieved 2026-08-02 Scope: src/vfs/_config/punk_main.tcl (subcommand dispatch); src/make.tcl (stamping build info into the vfs); src/vfs/ (stamp payload location); src/modules/punk/ (in-shell command - the single implementation) Goal: a punk executable reports its identity from embedded data rather than its filename - a documented subcommand prints the punkproject.toml project version it was built from plus the input runtime binary name and vfs folder name used to assemble it - with the same-named command available in the punk module so scripts running in any punk shell (including tclsh-hosted ones like tclsh src/make.tcl shell) get the same report in-process without exec, stamp fields reported as absent rather than fabricated when there is no stamp. Acceptance: the build stamps project version, runtime binary name, and vfs folder name into the kit; the built executable invoked with the version-report subcommand prints those fields machine-parseably on stdout and exits 0 with no other output (G-015-compatible; no repl fallthrough); a same-named command in the punk module returns the same fields in-process (subcommand implemented as a wrapper over it - one implementation) and works from the code interp; the report distinguishes stamped provenance from live facts: a stamped kit reports its stamp, a src-mode or source-tree session additionally reports the live punkproject.toml version as a distinct field when it differs, and unstamped contexts (tclsh src/make.tcl shell, plain tclsh with punk modules) report stamp fields explicitly absent with live runtime facts (actual info nameofexecutable) still provided; the report is correct when the executable file has been renamed or copied; executables built before stamping existed fail gracefully with a clear message rather than fabricating values.

Context

With G-023 producing version-named binaries, an executable's name encodes its version - but names are mutable (copies, renames, the -dev and release-gated plain names) and say nothing about the runtime binary or vfs folder the build consumed. The executable should answer for itself from embedded data: a version-report subcommand at the launch layer, and the same-named command in the punk module for scripts already running inside a punk shell.

The in-shell command is not merely an optimization over exec'ing out. In a tclsh-hosted punk shell (tclsh src/make.tcl shell loads punk::repl directly into the host tclsh - make.tcl ~1913) there is no punk executable to exec: info nameofexecutable is the external tclsh, and invoking it with the subcommand would be meaningless. The in-process command is the only correct path there - hence the module command is the single implementation and the exe subcommand is a thin dispatch wrapper over it (which is also what guarantees the two surfaces report identically).

Report semantics: three distinct notions

Only in a plainly-launched stamped kit do these coincide; the report must keep them distinct and never fabricate:

  1. Build stamp - project version, runtime binary name, vfs folder name, fixed at kit assembly by make.tcl. Absent in unstamped contexts.
  2. Live runtime facts - actual info nameofexecutable, patchlevel. Always available.
  3. Source-tree project version - punkproject.toml, available when running from a source tree regardless of stamping.

Edge cases driving the acceptance clauses:

  • tclsh src/make.tcl shell: no stamp. Stamp fields reported explicitly absent; live facts show the real host tclsh; the source-tree version may be reported but flagged as live-from-punkproject.toml, not as a stamp.
  • Kit launched in src mode (punk902z src): a stamp exists, but the running code is working-tree dev modules whose punkproject.toml may be ahead of the stamped version. Reporting only the stamp misstates what is running; only the live version misstates provenance - report both, distinctly labelled, when they differ.
  • Plain tclsh with installed punk modules and no source tree: no stamp, no punkproject.toml - live facts only.
  • Renamed/copied executables: the report comes from the stamp, so it stays correct whatever the file is called.
  • Pre-stamping kits: the subcommand/command fails gracefully with a clear message.

Progress

  • 2026-08-02 activated (user directive), landed same day (0.47.0) - all acceptance clauses implemented and verified:
    • Stamp: make.tcl bake writes punkkit-stamp.toml at the merged payload root (after the G-125 gate, before image assembly): project_version, vfs, runtime (+ runtime_build_id/runtime_artifact cited from the inherited G-117 record when present - exact immutable -rN linkage per the Notes), kit, target, boot_core_version. DECISION: no time-of-bake field - the target tree is clean-slate reassembled every bake, so a volatile field would make identical inputs stamp differently run-to-run; the G-117 embedded records set the precedent (time facts live in sidecars/ punkcheck records). Double-bake produces sha1-identical stamps.
    • Subcommand: 'buildinfo' is a boot-core builtin (core 0.2.0) - key=value report on stdout, exit 0, nothing else; args rejected exit 2; module unavailable exit 1. Documented in punk::args::moduledoc::punkexe 0.3.0.
    • Single implementation: new punk::buildinfo 0.1.0 (dependency-free); subcommand wraps punk::buildinfo::main; bare 'buildinfo' shell command = aliascore 0.2.0 alias preloaded by repl 0.5.4 (bootsupport include_modules.config gained punk::buildinfo - a snapshot carrying repl 0.5.4 without it broke tclsh-hosted shells; caught and fixed same day).
    • Three notions distinct: stamped kit reports stamp + live + live_vs_stamp=same|differs vs the governing punkproject.toml; tclsh-hosted 'make.tcl shell' reports stamp_present=0 with the real host tclsh as live_executable and the source-tree version as a live fact (verified verbatim); fixtures cover differs both ways.
    • Renamed/copied executables: characterization test copies the kit to another name - stamp reported unchanged, live_executable truthful (buildinfo.test, 4/4 against a stamped bake; stamped tests constrained on a kit_stamped probe so stale pre-G-025 kits skip cleanly).
    • Consumes ::punkboot::boot_state (kit_payload_base + roots) published by boot core 0.2.0 - the G-031/G-089 running-state surface - with self-derivation fallbacks for code-interp/plain-tclsh contexts.
    • Tests: report.test 8/8 module fixtures; punkexe suite 118 total / 0 fail.
  • ACHIEVED flip 2026-08-02, code-interp clause closed by direct probe: piped 'kit punk' (commands execute in the repl code interp) - catch {buildinfo} returns 0 with the report's first line stamp_present=1; the earlier invisibility was the piped result-display path only (exitinfo exit quirk is pre-existing on old kits too - G-038 adjacent, not a G-025 issue). Full-fleet coverage: 11-kit default bake, every kit stamped; final bake carries boot core 0.2.1.
  • Known/deferred: the scope line's punk_main.tcl dispatch element is realized in the G-031 boot core (punkboot_core.tcl - same _config directory). punkorigin.toml punkshell_version gap for bare kits (G-087 note) can now be closed by reading the stamp - candidate follow-up. 'make.tcl check' report line for the stamp/gate surfaces remains a candidate.

Approach notes

  • The command must work from the code interp (where scripts run), not just the repl thread - trivial for static stamp data, but stated so the G-007 location-transparency expectation is met.
  • The subcommand output must be machine-parseable, exit 0, and emit nothing else on stdout/stderr - usable through G-015 piped calls and by exec-style callers.
  • Naming (e.g. buildinfo) is an implementation decision: the in-shell command name must match the subcommand name and not collide with existing repl commands.
  • Stamp location within the vfs payload is an implementation decision to record here (candidates: a dedicated stamp file under the vfs _config, or fields merged into an existing boot config file).

Alternatives considered

  • In-shell command exec'ing its own executable with the subcommand - rejected: wrong in tclsh-hosted shells (no punk executable to call), needless process spawn elsewhere, and two code paths that can drift.
  • Reporting only the stamped version and ignoring live/source-tree context - rejected: actively misleading in src-mode sessions, which are the primary working-tree verification workflow (bin/AGENTS.md).

Notes

  • Related: G-023 (version-named binaries this complements), G-024 (achieved 2026-07-31 - see goals/archive/G-024-mapvfs-toml.md; the mapvfs.toml mapping that will drive stamping inputs, incl. its parse-time punkproject.toml version read), G-015 (piped invocation of the subcommand), G-014 (punkproject.toml reading may share tomlish plumbing).
  • Adjacent need surfaced 2026-07-14 (G-030 follow-up, recorded in src/AGENTS.md "pre-loaded interp" note): when make.tcl runs under a built punk executable, the module copies actually executing are the kit's pre-loaded ones, not the bootsupport snapshots make.tcl's paths would prefer - silent provenance mixing whenever versions diverge. A self-report surface that can also state, for a RUNNING interp, which copy of each key punk module is loaded and where it came from (kit vfs / bootsupport / dev paths) would make that mixing observable instead of silent. (G-030 achieved 2026-07-14 - goals/archive/G-030-maketcl-punkargs.md)
  • Archived-goal references in this file: G-007 achieved 2026-07-05 (goals/archive/G-007-console-location-transparency.md);G-015 achieved 2026-07-07 (goals/archive/G-015-script-subcommand-piped-stdin.md).
  • G-117 relationship (recorded 2026-07-24; G-117 achieved 2026-07-24 - see goals/archive/G-117-self-describing-runtimes.md): G-117 embeds the RUNTIME-layer artifact metadata record (schema v1, build_id) inside family runtimes' attached images at /app/punkbin-artifact.toml, and the record is CONFIRMED to survive make.tcl kit wrapping (punk9_beta reads its runtime's r2 record in-kit). This goal's report should read BOTH layers (kit stamp + inherited runtime record), and the "input runtime binary name" stamp field should cite the embedded record's build_id/artifact name when present - exact immutable -r linkage instead of the mutable working name. Coordinate stamp-file naming with G-117's embedded-record filename (same image, distinct namespaced files).
  • G-087 (archived - goals/archive/G-087-thin-project-layouts.md) added a consumer for the kit version stamp this goal would provide: generated projects' punkorigin.toml records punkshell_version only when the generating shell belongs to a checkout (read via punkboot::utils from punkproject.toml); bare kits currently record an empty version - a stamped kit-level punkshell version would close that gap.

Follow-ons

Follow-on: close the punkorigin.toml punkshell_version gap for bare kits by reading the buildinfo stamp => open Follow-on: 'make.tcl check' report line for the stamp/gate surfaces => open Follow-on: running-interp module-provenance report (which copy of each key punk module is loaded and where from - kit vfs / bootsupport / dev paths), making silent provenance mixing observable => open