diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a5c4bb0..05fa192f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ The latest `## [X.Y.Z]` header must match the `version` field in `punkproject.to Entries are newest-first; one bullet per notable change. See the root `AGENTS.md` "Project Versioning" section for the bump policy. +## [0.12.42] - 2026-07-17 + +- make.tcl: new informational subcommand `workflow` - prints an embedded plain-ASCII overview of the build/release data flow (release-ready command sequence, source->built-packages->bootsupport/kit-vfs/kit folder diagrams, keyed notes on version stamping, punkcheck provenance, the staleness gate, -confirm and locked-exe deploys). punk::args-documented like the other subcommands (tabled help + PUNKBOOT_PLAIN fallback covered); exempt from the bootsupport staleness gate alongside check/projectversion. The text lives in ::punkboot::workflow_text so it travels with make.tcl into generated-project layouts; update contract for keeping it current documented in src/AGENTS.md Work Guidance and in the output's MAINTENANCE key. + ## [0.12.41] - 2026-07-17 - punk::args 0.12.4: resolve's undefined-id miss path is now collision-aware - an inline definition (`parse ... withdef`, direct resolve) whose @id is already registered with different content quietly purges the id's existing cache entries before registering (matching define's re-creation behaviour), instead of repointing the id while stale cache entries lingered (previously a subsequent define with the original text was a silent no-op, leaving withid lookups stuck on the inline definition). The disabled blanket 'called with undefined id' stderr warning removed (it flagged supported usage). Known residual: the miss path still records no -defspace for @dynamic definitions first seen via resolve. New define.test pin (define_resolve_id_shadow, characterized pre-fix). diff --git a/punkproject.toml b/punkproject.toml index bdca30f3..5e203b00 100644 --- a/punkproject.toml +++ b/punkproject.toml @@ -1,4 +1,4 @@ [project] name = "punkshell" -version = "0.12.41" +version = "0.12.42" license = "BSD-2-Clause" diff --git a/src/AGENTS.md b/src/AGENTS.md index cc41c4ee..ff9762e7 100644 --- a/src/AGENTS.md +++ b/src/AGENTS.md @@ -67,6 +67,7 @@ Recovery after a wrong path guess: - All build/promotion commands (`project`, `packages`, `modules`, `libs`, `vfs`, `vfslibs`, `bin`, `bootsupport`, `vfscommonupdate`) warn similarly when this project's own `src/` has uncommitted fossil/git changes (dirt outside `src/` is ignored). Warn-only by default; pass `-dirty-abort` to make the check aborting. For evaluating uncommitted source without a build, prefer ` src` / ` src shell`. The check is `punkboot::utils::vcs_dirty_warnings` (optional scope argument) loaded guardedly from bootsupport - if the snapshot is stale/missing the check degrades to a skip notice (but `-dirty-abort` then aborts rather than silently losing the requested strictness). - Provenance warnings (dirty-src gate + vendorupdate source-project check) print with a plain column-0 `PROVENANCE-WARNING:` token (grep for it in captured build output) and are recapped at the end of the run via make.tcl's wrapped `::exit`. Interactive terminal runs get a 3-second ctrl-c grace countdown before a dirty build proceeds; piped/agent runs skip it. `tclsh src/make.tcl check` reports the current src provenance status and what the build commands would do. - Use `tclsh src/make.tcl vfscommonupdate` to rebuild `_vfscommon.vfs`. The REPLACE confirmation prompts on an interactive terminal; unattended/agent runs must pass `-confirm 0` (with the default `-confirm 1` and a piped/closed stdin, make.tcl aborts fast with guidance instead of reading stdin - do not pipe `y`). +- `tclsh src/make.tcl workflow` prints an embedded ASCII data-flow overview of the build/release workflow (release-ready command sequence, source→outputs folder flow, kit assembly, keyed notes). The text lives in `::punkboot::workflow_text` in `src/make.tcl` - embedded rather than a data file so it travels with the make.tcl copies seeded into generated projects. **Update contract (agents):** whenever build data flow changes - a make.tcl subcommand added/removed/repurposed, a source or output folder added or rerouted, a propagation target added, a gate (staleness/provenance/confirm) or deploy behaviour changed - update the workflow text in the same change-set. Keep it plain ASCII, max line width 100, and preserve the RELEASE SEQUENCE / DIAGRAM / KEY-NOTES / MAINTENANCE structure; verify by running `tclsh src/make.tcl workflow` (and once under `PUNKBOOT_PLAIN=1`). Adding/changing a subcommand also means: SUMMARIES + HELPTEXTS + SUBOPTS (+ SUBGROUPS) in `::punkboot::argdoc`, `known_commands`, the plain `punkboot_gethelp` text, and a project-version bump (make.tcl interface is product surface per root AGENTS.md). Layout make.tcl copies pick the change up via `make.tcl bootsupport` - do not hand-sync them. - make.tcl subcommands and flags are punk::args-declared (G-030): `tclsh src/make.tcl help ?subcommand?` or ` -help` shows tabled usage; invalid arguments produce punk::args usage errors. The dispatch degrades to plain scan/help when the bootsupport punk::args (or its rendering stack) is stale or unavailable; `PUNKBOOT_PLAIN=1` forces the degraded mode for troubleshooting. The `::punkboot::argdoc` definitions are constructed (string-built) and use the G-045 authoring mechanisms — block-form help values + `@normalize`, explicit `@form -synopsis` — see src/modules/AGENTS.md "punk::args definition authoring ergonomics" before editing them or authoring similar definitions. - Uncommitted `make.tcl`-generated outputs may be batched into one commit, regardless of how many `make.tcl` invocations produced them. This covers punkcheck-managed build outputs that are VCS-tracked: `src/bootsupport/`, `_vfscommon.vfs/modules` + `/lib`, and declared per-kit `*.vfs/lib_tcl/` subfolders. (Root `modules/`, `lib/`, `modules_tcl/`, `lib_tcl/` are gitignored and never committed.) Each module's old→new version rename is atomic; a regeneration reflects one build-output refresh, not independent hand-edits. This is a carve-out from generic "split aggressively" commit guidance for punkcheck-managed build outputs only — it does not cover user-curated VFS content (`_config/`, per-kit `*.vfs/` outside declared `lib_tcl` subfolders, `_aside/`, `mkzipfix.vfs`, `_vfscommon.vfs/doc`), which commits separately per its own concerns. - Use `punk make.tcl project` or `punk902z make.tcl project` inside Punk shell when building binaries through Punk. Driving make.tcl from a built punk executable is supported for informational/update subcommands and for kit builds of *other* kits — the kit whose deployed executable is running the build is skipped with a warning (it cannot be replaced while running, and the pre-deploy process sweep must not kill the build itself; the sweep also excludes the build's own pid in all cases). Rebuild that kit from tclsh or a different kit. diff --git a/src/make.tcl b/src/make.tcl index 2a66f659..3e6aefd5 100644 --- a/src/make.tcl +++ b/src/make.tcl @@ -21,7 +21,7 @@ namespace eval ::punkboot { variable foldername [file tail $scriptfolder] variable pkg_requirements [list]; variable pkg_missing [list];variable pkg_loaded [list] variable help_flags [list -help --help /? -h] - variable known_commands [list project modules libs packages vfs vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion] + variable known_commands [list project modules libs packages vfs vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion workflow] } @@ -1395,6 +1395,8 @@ proc ::punkboot::punkboot_gethelp {args} { append h " - run the punk shell using bootsupport libraries." \n append h " $scriptname projectversion" \n append h " - advisory check: verify CHANGELOG.md matches punkproject.toml and warn if src/ has changes since the last project-version bump." \n \n + append h " $scriptname workflow" \n + append h " - print an ASCII data-flow overview of the build/release workflow (edit -> packages -> bootsupport -> kits)" \n \n append h " $scriptname help ?subcommand?" \n append h " - show usage for $scriptname or one of its subcommands (equivalent: $scriptname -help)" \n \n append h " Flags:" \n @@ -1412,6 +1414,152 @@ proc ::punkboot::punkboot_gethelp {args} { append h [punkboot_availability_note] return $h } +#Embedded build/release workflow overview - the output of the 'workflow' subcommand. +#Embedded (rather than a data file) so it travels with make.tcl wherever it runs, including +#the make.tcl copies seeded into generated projects via the project layouts. +#Contract for updates (see also src/AGENTS.md 'Work Guidance'): when build data flow changes +#(subcommand added/removed/repurposed, source or output folder flow changed, new propagation +#target), this text changes in the same commit. Plain ASCII only, max line width 100. +proc ::punkboot::workflow_text {} { + set txt { +build & release workflow - from module edit to kits + bootsupport (punk project layout) +============================================================================= +Scope: data flow from editing a module under src/ through to a release-ready +rebuild (built packages, bootsupport refresh, kit vfs, kit executables). +All commands run from the projectroot with a native tclsh, e.g: + tclsh src/make.tcl -confirm 0 (see [K6]) + + +RELEASE SEQUENCE (the order that satisfies the staleness + provenance gates) +---------------------------------------------------------------------------- + + (1) edit src/modules/foo-999999.0a1.0.tm code change [K1] + (2) bump src/modules/foo-buildversion.txt module version + changelog comment + punkproject.toml + CHANGELOG.md project version (if shipped behaviour) [K2] + (3) test tclsh src/tests/runtests.tcl ... runs against src/ trees (if present) + (4) commit source changes (git/fossil) clean tree -> committed provenance [K3] + (5) build tclsh src/make.tcl modules -confirm 0 (or 'packages' = modules + libs) + (6) build tclsh src/make.tcl bootsupport -confirm 0 run twice: 2nd pass must copy 0 files [K4] + (7) build tclsh src/make.tcl vfscommonupdate -confirm 0 + (8) build tclsh src/make.tcl project -confirm 0 kits; close running kit shells first [K5] + (9) commit tracked build outputs src/bootsupport, src/project_layouts + copies, src/vfs/_vfscommon.vfs + + +DIAGRAM 1 - DATA FLOW: SOURCE -> BUILT PACKAGES -> PROPAGATION TARGETS +---------------------------------------------------------------------------- + + src/modules/foo-999999.0a1.0.tm [K1] src/lib/ + src/modules/foo-buildversion.txt src/vendorlib/ + src/vendormodules/ (+ *_tcl9 variants) | + | | + | make.tcl modules | make.tcl libs + | (stamp real version, pack #modpod-*, | + | prune superseded) | + v v + modules/ modules_tcl8/ modules_tcl9/ lib/ lib_tcl8/ lib_tcl9/ + e.g. modules/foo-0.12.4.tm + == BUILT PACKAGES (projectroot output trees, punkcheck-recorded [K3]) == + | + +--------------------------------------+ + | | + | make.tcl bootsupport [K4] | make.tcl vfscommonupdate + | (curated subset) | (REPLACE semantics: vfs modules/libs + v | are overwritten with built set) + src/bootsupport/modules/ v + (the module set make.tcl itself src/vfs/_vfscommon.vfs/modules/ + libs + boots from; staleness-gated) (VCS-tracked kit payload source) + | | + | same run, second hop | make.tcl project (or: make.tcl vfs) + v v + src/project_layouts/custom/_project/ src/_build/.exe --deploy--> bin/.exe + /src/bootsupport/ (see DIAGRAM 2) [K5] + (template copies seeded into projects + generated by 'dev project.new') + + +DIAGRAM 2 - KIT ASSEMBLY DETAIL (inside 'make.tcl project' / 'make.tcl vfs') +---------------------------------------------------------------------------- + + src/runtime/mapvfs.config which vfs folder pairs with which runtime -> kit name + src/runtime/.exe bare Tcl runtime (tclkit / tclsfe build) + src/vfs/_vfscommon.vfs/ common payload (built modules + libs, main boot support) + src/vfs/.vfs/ per-kit overlay (main.tcl, kit-only modules/config) + + _vfscommon.vfs .vfs + | | + +-----------+----------+ + | copy common, then merge overlay over it + v + src/_build/.exe.vfs + | + | tcl::zipfs::mkimg (vfs image appended to runtime exe) + v + src/_build/.exe + | + | deploy step: delete old bin/.exe, copy new one in + v + bin/.exe <-- FAILS (kit listed under FAILED KITS) if a + running shell still holds the old exe [K5] + + +KEY / NOTES +---------------------------------------------------------------------------- +[K1] Source modules carry the literal magic version 999999.0a1.0 in the filename. + The real version is the first line of the sibling -buildversion.txt; + bump it per semver (patch=fix, minor=api add, major=breaking) and append a + '# - ...' changelog comment line below it. The modules build stamps + the real version into the output filename and package provide. + (A project may carry manually-versioned exceptions - see src/modules/AGENTS.md + if present.) + +[K2] Project version (punkproject.toml [project] version + matching CHANGELOG.md + entry) is change-driven: bump when the change ships user-visible behaviour. + Advisory check: tclsh src/make.tcl projectversion + +[K3] Every build target root gets a .punkcheck file recording what was installed + from where (punkcheck provenance). Building from a tree with uncommitted + changes under src/ works but emits PROVENANCE-WARNINGs - commit source first + for release builds. Output-tree commits (step 9) come after the builds. + +[K4] Bootsupport staleness gate: make.tcl compares tracked module versions in + src/bootsupport against built sources; a stale bootsupport makes other + subcommands warn/prompt/abort (per bump level) unless -confirm 0. After a + tracked module bump, refresh with 'make.tcl bootsupport' and rerun it until + a pass copies 0 files (layout copies have needed a second pass historically). + +[K5] The deploy step cannot replace a kit exe that is currently executing. Close + running kit shells before step 8, or rerun 'make.tcl vfs -confirm 0' + afterwards - the freshly built kits wait in src/_build. punkcheck records + mean the rerun only redoes the failed deploys. + +[K6] All confirmation prompts follow -confirm: unattended/agent runs must pass + -confirm 0 (non-interactive stdin aborts fast at prompts; piping 'y' is + retired). 'make.tcl help ' shows per-subcommand usage. + +[K7] Testing hooks along the way: + - src/tests/runtests.tcl exercises the src/ trees directly (dev modules). + - '.exe dev' (or ' src') runs a built shell against the + project dev modules - useful for testing built packages before they are + baked into kits via vfscommonupdate + project. + +[K8] What is VCS-tracked where (checkin targets after a build): + tracked: src/** (sources, src/bootsupport, src/project_layouts copies, + src/vfs/_vfscommon.vfs), punkproject.toml, CHANGELOG.md + untracked: modules*/ lib*/ at projectroot, src/_build/, bin/.exe + (bin/ scripts/tools are tracked; kit executables are not) + +MAINTENANCE (agents take note) +---------------------------------------------------------------------------- +This text is embedded in make.tcl (::punkboot::workflow_text). When the build +data flow changes - a make.tcl subcommand added/removed/repurposed, a source or +output folder added or rerouted, a new propagation target, a changed gate or +deploy behaviour - update this text in the same change-set and verify with +'tclsh src/make.tcl workflow'. Plain ASCII only; max line width 100. A make.tcl +interface change is product surface: bump the project version (at least patch). +} + return [string trim $txt \n] +} #Missing/broken bootsupport-package NOTE shown with help output. #Factored out of punkboot_gethelp (G-030) so both the punk::args tabled help path and the #plain-text fallback help append the same information. Returns "" when there is nothing to report. @@ -1508,6 +1656,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO info "Show the name and base folder of the project to be built" check "Show module/library paths and any potentially problematic packages for running this script" projectversion "Advisory check: CHANGELOG.md vs punkproject.toml and src/ changes since last version bump" + workflow "Print an ASCII data-flow overview of the build/release workflow (edit -> packages -> bootsupport -> kits)" shell "Run the punk shell using bootsupport libraries" help "Show usage for make.tcl or one of its subcommands" } @@ -1595,6 +1744,15 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO " Advisory check: verify CHANGELOG.md matches punkproject.toml and warn if src/ has changes since the last project-version bump." + workflow + " + Print a plain-text (ASCII diagram) overview of the build/release + workflow: the release-ready command sequence and how data flows from + editing a module under src/ through built packages to bootsupport, + the kit vfs and the kit executables. + The text is embedded in make.tcl (::punkboot::workflow_text) so it is + available wherever make.tcl runs; its MAINTENANCE key states the + update contract for keeping it in step with build behaviour." } #shared option fragments composed into the per-subcommand definitions below variable OPT_CONFIRM { @@ -1645,6 +1803,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO info {OPT_CONFIRM} check {} projectversion {} + workflow {} } #synopsis fragments matching the shared option fragments (explicit @form -synopsis #so usage shows the real invocation 'make.tcl ...' rather than the @@ -1697,7 +1856,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO variable SUBGROUPS { "build & promotion" {project packages modules libs vfs vfslibs bin} "source maintenance" {vendorupdate bootsupport vfscommonupdate} - "informational" {info check projectversion help} + "informational" {info check projectversion workflow help} "interactive" {shell} } punk::args::define\ @@ -1891,7 +2050,8 @@ set forcekill $::punkboot::opt_forcekill # - minor bump -> prompt user; backward-compat aliases *should* keep old bootsupport functional # - patch bump -> warn and proceed (non-breaking) # 'check' is exempt in all cases — the warning is shown at the end of its output instead. -if {[info exists ::punkboot::stale_bootsupport] && $::punkboot::command ne "check" && $::punkboot::command ne "projectversion"} { +# 'projectversion' and 'workflow' are informational/read-only and are likewise exempt. +if {[info exists ::punkboot::stale_bootsupport] && $::punkboot::command ni {check projectversion workflow}} { set _stale $::punkboot::stale_bootsupport set _have_major 0 set _have_minor 0 @@ -2422,6 +2582,11 @@ if {$::punkboot::command eq "projectversion"} { exit 0 } +if {$::punkboot::command eq "workflow"} { + puts stdout [::punkboot::workflow_text] + exit 0 +} + if {$::punkboot::command eq "shell"} { package require struct::list package require punk