Browse Source

make.tcl window doc sweep: bake/bakehouse vocabulary across workflow references

Root README, src/README, src/AGENTS.md (full-build guidance, provenance command
list incl. bakehouse's default-on dirty gate, punk-exe-hosted builds,
verification), src/modules + src/lib + src/vfs + src/tests + src/tests/shell +
src/runtime AGENTS.md workflow references, and the rebuild-instruction comments
in scriptexec.test/tclshcmd.test. G-104's G-058 mention gains its archive
marker. Historical CHANGELOG entries untouched; goal-file contract texts
(G-005/G-006/G-057 Acceptance mention 'make.tcl project') left for
proposal-first user approval - the deprecated alias keeps them executable.
Layout make.tcl copies are punkcheck-synced build outputs - they refresh via
the normal sync channels in the acceptance build, never hand-edited.

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 6 days ago
parent
commit
a949414bf8
  1. 4
      README.md
  2. 3
      goals/G-104-maketcl-buildsuite-surface.md
  3. 8
      src/AGENTS.md
  4. 4
      src/README.md
  5. 2
      src/lib/AGENTS.md
  6. 2
      src/modules/AGENTS.md
  7. 2
      src/runtime/AGENTS.md
  8. 2
      src/tests/AGENTS.md
  9. 2
      src/tests/shell/AGENTS.md
  10. 4
      src/tests/shell/testsuites/punkexe/scriptexec.test
  11. 2
      src/tests/shell/testsuites/punkexe/tclshcmd.test
  12. 6
      src/vfs/AGENTS.md

4
README.md

@ -20,8 +20,8 @@ The project uses a Tcl-based build system (`src/make.tcl`). From the project roo
# Build modules and libraries into the project root # Build modules and libraries into the project root
tclsh src/make.tcl packages tclsh src/make.tcl packages
# Full build (modules + libraries + VFS + binaries) # Full consumer build from a clean checkout (packages + baked kit binaries)
tclsh src/make.tcl project tclsh src/make.tcl bakehouse
``` ```
See `src/README.md` for detailed build instructions and `bin/AGENTS.md` for the runtime manager. See `src/README.md` for detailed build instructions and `bin/AGENTS.md` for the runtime manager.

3
goals/G-104-maketcl-buildsuite-surface.md

@ -51,7 +51,8 @@ products appear in info output), G-105 (target dimension forwarded when it exist
doc pointers; build forwards args and exits with the driver's status doc pointers; build forwards args and exits with the driver's status
(unknown-option run exit 1 streamed; unknown suite/action exit 2; list exit (unknown-option run exit 1 streamed; unknown suite/action exit 2; list exit
0); works under native tclsh90 AND punk91-kit-hosted (script-mode launcher 0); works under native tclsh90 AND punk91-kit-hosted (script-mode launcher
selection via the G-058 static-capture marker); a throwaway COPY of selection via the static-capture marker from archived G-058 - see
goals/archive/G-058-static-runtime-packages.md); a throwaway COPY of
suite_tcl90 with an edited description appeared in list/info automatically suite_tcl90 with an edited description appeared in list/info automatically
and was removed after the check. suite.tcl direct CLI re-verified and was removed after the check. suite.tcl direct CLI re-verified
(usage-error path through the new config-load position). (usage-error path through the new config-load position).

8
src/AGENTS.md

@ -59,19 +59,19 @@ Recovery after a wrong path guess:
## Work Guidance ## Work Guidance
- Run `tclsh src/make.tcl packages` once after cloning to populate generated module and library assets. - Run `tclsh src/make.tcl packages` once after cloning to populate generated module and library assets.
- Use `tclsh src/make.tcl project` for full builds. - Use `tclsh src/make.tcl bakehouse` for full builds from a clean checkout (packages + bake; refuses uncommitted src by default - `-dirty-abort 0` overrides). The deprecated `project` alias maps to it with a notice.
- Use `tclsh src/make.tcl modules` to build just the module packages. - Use `tclsh src/make.tcl modules` to build just the module packages.
- Use `tclsh src/make.tcl libs` to build just the library packages. - Use `tclsh src/make.tcl libs` to build just the library packages.
- Use `tclsh src/make.tcl packages` to build both modules and libraries. - Use `tclsh src/make.tcl packages` to build both modules and libraries.
- make.tcl colour is terminal-aware (G-113): piped/redirected runs (agent harnesses, CI, log capture) automatically produce fully ESC-free output with no caller action required - an ansistrip channel transform on stdout+stderr guarantees zero ESC bytes for every emitter, including module-side ones (punkcheck summaries, punk::args tables). Interactive terminal runs keep colour (stdout tty probe via the `-winsize` channel option, Tcl 8.7+/9). Precedence: `NO_COLOR` (any value) always suppresses colour; `PUNK_FORCE_COLOR`/`FORCE_COLOR` (value other than 0/false/no/off) re-enables ANSI on piped output; otherwise the probe decides. Tcl 8.6 has no boot-phase probe - colour fails OFF there (use the force vars for 8.6 interactive colour). stderr follows the stdout decision; `make.tcl shell` pops the transform (repl colour is the shell's own concern). `tclsh src/make.tcl check` reports the active policy (`colour policy (G-113): mode=...` line; modes tty|forced|nocolor|piped-plain|tcl86-plain). Pinned by `src/tests/shell/testsuites/punkexe/maketclcolour.test`. Agents no longer need to set NO_COLOR for captured runs (setting it remains harmless). - make.tcl colour is terminal-aware (G-113): piped/redirected runs (agent harnesses, CI, log capture) automatically produce fully ESC-free output with no caller action required - an ansistrip channel transform on stdout+stderr guarantees zero ESC bytes for every emitter, including module-side ones (punkcheck summaries, punk::args tables). Interactive terminal runs keep colour (stdout tty probe via the `-winsize` channel option, Tcl 8.7+/9). Precedence: `NO_COLOR` (any value) always suppresses colour; `PUNK_FORCE_COLOR`/`FORCE_COLOR` (value other than 0/false/no/off) re-enables ANSI on piped output; otherwise the probe decides. Tcl 8.6 has no boot-phase probe - colour fails OFF there (use the force vars for 8.6 interactive colour). stderr follows the stdout decision; `make.tcl shell` pops the transform (repl colour is the shell's own concern). `tclsh src/make.tcl check` reports the active policy (`colour policy (G-113): mode=...` line; modes tty|forced|nocolor|piped-plain|tcl86-plain). Pinned by `src/tests/shell/testsuites/punkexe/maketclcolour.test`. Agents no longer need to set NO_COLOR for captured runs (setting it remains harmless).
- Use `tclsh src/make.tcl vendorupdate` to refresh vendormodules from config. It warns (non-fatal) for each source project whose fossil/git checkout is dirty - vendored artifacts built from a dirty tree have no committed provenance; commit in the source project to clear the warning (enforcement policy tracked by goal G-026). - Use `tclsh src/make.tcl vendorupdate` to refresh vendormodules from config. It warns (non-fatal) for each source project whose fossil/git checkout is dirty - vendored artifacts built from a dirty tree have no committed provenance; commit in the source project to clear the warning (enforcement policy tracked by goal G-026).
- 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 `<builtexe> src` / `<builtexe> 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). - All build/promotion commands (`bakehouse`, `packages`, `modules`, `libs`, `bake`, `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 EXCEPT `bakehouse` (aborts by default; `-dirty-abort 0` overrides); pass `-dirty-abort` elsewhere to make the check aborting. For evaluating uncommitted source without a build, prefer `<builtexe> src` / `<builtexe> 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. - 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`). - 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. - `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 `<subcommand> -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. - make.tcl subcommands and flags are punk::args-declared (G-030): `tclsh src/make.tcl help ?subcommand?` or `<subcommand> -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`, declared per-kit `*.vfs/lib_tcl<N>/<pkg>` subfolders, the thin-layout sync copies (`src/project_layouts/vendor/punk/<layout>/src/{make.tcl,build.tcl}` + bootsupport manifest copies), and the module-shipped layout payload under `src/modules/punk/mix/#modpod-templates-*/templates/project_layouts/` (G-087: synced from `src/project_layouts` - never hand-edit the modpod copy). (Root `modules/`, `lib/`, `modules_tcl<N>/`, `lib_tcl<N>/` 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<N>` subfolders, `_aside/`, `mkzipfix.vfs`, `_vfscommon.vfs/doc`), which commits separately per its own concerns. - 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`, declared per-kit `*.vfs/lib_tcl<N>/<pkg>` subfolders, the thin-layout sync copies (`src/project_layouts/vendor/punk/<layout>/src/{make.tcl,build.tcl}` + bootsupport manifest copies), and the module-shipped layout payload under `src/modules/punk/mix/#modpod-templates-*/templates/project_layouts/` (G-087: synced from `src/project_layouts` - never hand-edit the modpod copy). (Root `modules/`, `lib/`, `modules_tcl<N>/`, `lib_tcl<N>/` 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<N>` 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. - Use `punk make.tcl bakehouse` or `punk902z make.tcl bakehouse` inside Punk shell when building binaries through Punk (the deprecated `project` alias still maps). 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.
- **Punk-exe-hosted make.tcl runs in a pre-loaded interp, not a virgin one** — the kit's script-mode boot has already loaded much of the punk stack (punk, punk::lib, punk::repl, punk::console, punk::du, flagfilter, struct::set ...) and set process state (app-punkscript forces `::tcl_interactive 0` for script semantics; libunknown/packagepreference are active). Consequences make.tcl must (and now does) handle explicitly: `package require` of an already-provided package is a no-op, so anything make.tcl breaks in the interp (the accelerator-reload block forgets+destroys sha1/md5/struct::* — it re-requires what was loaded), and anything computed at package-load time (punk::repl's `::tcl_interactive` probe — the shell branch recomputes it before `repl::start`), must be restored deliberately rather than relying on later loads to re-fire. Also note the copies that run in this mode are the *kit's* pre-loaded modules, not the bootsupport snapshots make.tcl's paths would otherwise prefer — silent provenance mixing when versions diverge. When adding interp-surgery or load-time-state assumptions to make.tcl, test under both `tclsh src/make.tcl ...` and `<punkexe> src/make.tcl ...`. - **Punk-exe-hosted make.tcl runs in a pre-loaded interp, not a virgin one** — the kit's script-mode boot has already loaded much of the punk stack (punk, punk::lib, punk::repl, punk::console, punk::du, flagfilter, struct::set ...) and set process state (app-punkscript forces `::tcl_interactive 0` for script semantics; libunknown/packagepreference are active). Consequences make.tcl must (and now does) handle explicitly: `package require` of an already-provided package is a no-op, so anything make.tcl breaks in the interp (the accelerator-reload block forgets+destroys sha1/md5/struct::* — it re-requires what was loaded), and anything computed at package-load time (punk::repl's `::tcl_interactive` probe — the shell branch recomputes it before `repl::start`), must be restored deliberately rather than relying on later loads to re-fire. Also note the copies that run in this mode are the *kit's* pre-loaded modules, not the bootsupport snapshots make.tcl's paths would otherwise prefer — silent provenance mixing when versions diverge. When adding interp-surgery or load-time-state assumptions to make.tcl, test under both `tclsh src/make.tcl ...` and `<punkexe> src/make.tcl ...`.
- Binary images are platform-specific; build on each target platform rather than expecting a cross-platform flag. - Binary images are platform-specific; build on each target platform rather than expecting a cross-platform flag.
- Remove `_build/` artifacts only when a clean/resync is needed, then rerun the relevant `make.tcl` command. Avoid partial cleans that break boot modules. - Remove `_build/` artifacts only when a clean/resync is needed, then rerun the relevant `make.tcl` command. Avoid partial cleans that break boot modules.
@ -93,7 +93,7 @@ Recovery after a wrong path guess:
- VS Code Tcl lint diagnostics are reviewed for modified Tcl files when available. - VS Code Tcl lint diagnostics are reviewed for modified Tcl files when available.
- Relevant tests pass, either `tclsh src/tests/runtests.tcl` or a specific `tclsh src/tests/modules/<modulehierarchypath>/tests/all.tcl`. - Relevant tests pass, either `tclsh src/tests/runtests.tcl` or a specific `tclsh src/tests/modules/<modulehierarchypath>/tests/all.tcl`.
- `tclsh src/make.tcl packages` is verified when touching build-critical code. - `tclsh src/make.tcl packages` is verified when touching build-critical code.
- `tclsh src/make.tcl project` completes without errors when changing build, runtime, or VFS behavior. - `tclsh src/make.tcl bakehouse` (with `-dirty-abort 0` when verifying a deliberately dirty tree) completes without errors when changing build, runtime, or VFS behavior.
- Documentation/comments are updated for new behavior, flags, workflow, or ownership rules. - Documentation/comments are updated for new behavior, flags, workflow, or ownership rules.
- Diffs are reviewed so no stray whitespace or debugging output remains. - Diffs are reviewed so no stray whitespace or debugging output remains.

4
src/README.md

@ -36,7 +36,9 @@ e.g
# If make.tcl dependencies are modified: # If make.tcl dependencies are modified:
# tclsh src/make.tcl bootsupport ;# src/modules -> src/bootsupport/modules, src/lib -> src/bootsupport/lib (etc) # tclsh src/make.tcl bootsupport ;# src/modules -> src/bootsupport/modules, src/lib -> src/bootsupport/lib (etc)
tclsh src/make.tcl project tclsh src/make.tcl bake ;# assemble kit/zipkit executables from the promoted vfs payload + runtimes
# (consumer path from a CLEAN checkout: 'tclsh src/make.tcl bakehouse' = packages + bake in one run;
# 'make.tcl workflow' prints the full data-flow overview. 'project'/'vfs' remain as deprecated aliases.)
``` ```

2
src/lib/AGENTS.md

@ -26,7 +26,7 @@ Source of truth for all editable `pkgIndex.tcl`-based library packages. These ar
## Work Guidance ## Work Guidance
- Prefer generic or version-specific source trees over built, installed, VFS, or generated copies unless explicitly targeting those. - Prefer generic or version-specific source trees over built, installed, VFS, or generated copies unless explicitly targeting those.
- After editing a library, run `tclsh src/make.tcl libs` to rebuild, then `tclsh src/make.tcl project` for a full rebuild. - After editing a library, run `tclsh src/make.tcl libs` to rebuild, then `tclsh src/make.tcl bakehouse` for a full rebuild from a clean checkout (the deprecated `project` alias still maps).
- New libraries should include a `pkgIndex.tcl` that correctly references the implementation file. - New libraries should include a `pkgIndex.tcl` that correctly references the implementation file.
## Verification ## Verification

2
src/modules/AGENTS.md

@ -43,7 +43,7 @@ Source of truth for all editable Punk project modules. This is where agents shou
- Prefer Unix-style LF line endings for `.tm` source files in this tree. - Prefer Unix-style LF line endings for `.tm` source files in this tree.
- If the same proc exists in both `src/modules/` and `src/modules_tcl<major>/`, prefer `src/modules/` unless version-specific behavior is relevant or only the version-specific file is active. - If the same proc exists in both `src/modules/` and `src/modules_tcl<major>/`, prefer `src/modules/` unless version-specific behavior is relevant or only the version-specific file is active.
- Use `deck module.new <name>` or `punk::mix::commandset::module::new` to scaffold new modules. - Use `deck module.new <name>` or `punk::mix::commandset::module::new` to scaffold new modules.
- Run `tclsh src/make.tcl modules` to build modules, or `tclsh src/make.tcl project` for a full build. - Run `tclsh src/make.tcl modules` to build modules, or `tclsh src/make.tcl bakehouse` for a full build from a clean checkout (the deprecated `project` alias still maps).
- When adding a new proc to a `.tm` file, add a PUNKARGS `argdoc` block immediately before it — even if the proc parses arguments manually and the PUNKARGS is documentation-only. "User-facing" includes any proc in an exported namespace, not just shell commands. Developer-facing utility procs (e.g `punk::lib::*`) are not exempt. - When adding a new proc to a `.tm` file, add a PUNKARGS `argdoc` block immediately before it — even if the proc parses arguments manually and the PUNKARGS is documentation-only. "User-facing" includes any proc in an exported namespace, not just shell commands. Developer-facing utility procs (e.g `punk::lib::*`) are not exempt.
### Formatting And Layout ### Formatting And Layout

2
src/runtime/AGENTS.md

@ -22,7 +22,7 @@ Houses the `mapvfs.config` that maps VFS payloads to platform runtimes, plus the
## Verification ## Verification
- `tclsh src/make.tcl project` uses `mapvfs.config` correctly. - `tclsh src/make.tcl bake` uses `mapvfs.config` correctly.
- Built binaries launch and boot the Punk REPL. - Built binaries launch and boot the Punk REPL.
## Child DOX Index ## Child DOX Index

2
src/tests/AGENTS.md

@ -42,7 +42,7 @@ Top-level test harness and source-tree tests for ShellSpy/Punk. Tests here exerc
- Select an appropriate interpreter, such as `tclsh`, `tclsh90`, or a built Punk executable such as `punk902z`. - Select an appropriate interpreter, such as `tclsh`, `tclsh90`, or a built Punk executable such as `punk902z`.
- Native Tcl 8.6 tclsh is a supported runner interpreter (2026-07-21): `runtests.tcl` loads punk::lib's validated forward-compat command family (lpop etc - builtin parity pinned by `modules/punk/lib/testsuites/lib/compat.test`) at both boot levels (toplevel and testinterp) when the builtins are absent. The guards are no-ops on Tcl 8.7+/9, preserving the G-093 fast two-stage `-discover-only` boot. - Native Tcl 8.6 tclsh is a supported runner interpreter (2026-07-21): `runtests.tcl` loads punk::lib's validated forward-compat command family (lpop etc - builtin parity pinned by `modules/punk/lib/testsuites/lib/compat.test`) at both boot levels (toplevel and testinterp) when the builtins are absent. The guards are no-ops on Tcl 8.7+/9, preserving the G-093 fast two-stage `-discover-only` boot.
- Kit-hosted runner hardening (2026-07-21): the runner's own package requires carry minimum-version floors (punk::args in `runtests.tcl`, punk::path in `testsupport/discovery.tcl`, punk::lib in the 8.6 guards). Rationale: a punk-kit `[interpreter]` boot pre-registers its kit-stamped package versions, and an unversioned require satisfiable by such a registration never fires `package unknown` - the freshly-added bootsupport tm path is never even scanned, so a fossilized kit copy silently wins and then skews against modern modules pulled in by versioned requires (the historic punk86 failure: kit punk::args 0.1.0 loaded, then punk::path 0.4.0- died on `invalid command name "punk::args::define"`). Floored requires reject the fossil and resolve the bootsupport copy. The punk86 kit itself is mapped in `src/runtime/mapvfs.config` (8.6.17 dyn tclkit + punk8win.vfs, remapped 2026-07-21). Suites that spawn children of `[info nameofexecutable]` additionally need kit content to be current: kit children boot with kit-stamped modules preloaded from `_vfscommon.vfs`, so run `make.tcl vfscommonupdate` + `make.tcl vfs` after module changes such suites depend on (punkcheck's concurrency.test floors its child-side punkcheck require so a stale kit fails loud in the child log instead of mysteriously). Native tclsh remains the preferred runner interpreter. - Kit-hosted runner hardening (2026-07-21): the runner's own package requires carry minimum-version floors (punk::args in `runtests.tcl`, punk::path in `testsupport/discovery.tcl`, punk::lib in the 8.6 guards). Rationale: a punk-kit `[interpreter]` boot pre-registers its kit-stamped package versions, and an unversioned require satisfiable by such a registration never fires `package unknown` - the freshly-added bootsupport tm path is never even scanned, so a fossilized kit copy silently wins and then skews against modern modules pulled in by versioned requires (the historic punk86 failure: kit punk::args 0.1.0 loaded, then punk::path 0.4.0- died on `invalid command name "punk::args::define"`). Floored requires reject the fossil and resolve the bootsupport copy. The punk86 kit itself is mapped in `src/runtime/mapvfs.config` (8.6.17 dyn tclkit + punk8win.vfs, remapped 2026-07-21). Suites that spawn children of `[info nameofexecutable]` additionally need kit content to be current: kit children boot with kit-stamped modules preloaded from `_vfscommon.vfs`, so run `make.tcl vfscommonupdate` + `make.tcl bake` after module changes such suites depend on (punkcheck's concurrency.test floors its child-side punkcheck require so a stale kit fails loud in the child log instead of mysteriously). Native tclsh remains the preferred runner interpreter.
- Run the full source-tree suite with `<tcl_interpreter> src/tests/runtests.tcl`. - Run the full source-tree suite with `<tcl_interpreter> src/tests/runtests.tcl`.
- Use `-include-paths` with directory glob patterns relative to `src/tests/`, forward slashes — `modules/punk/args/***` runs that whole subtree (`X/***` deliberately excludes files directly in `X`; bare `X` is files-directly-in-X only). The flag accepts a space-separated list of patterns and may also be repeated, with all occurrences accumulating (`-multiple 1` as of 2026-07-10; previously the last flag silently won). Single-file targeting: `-include-paths modules/punk/args/testsuites/args dynamic.test`. - Use `-include-paths` with directory glob patterns relative to `src/tests/`, forward slashes — `modules/punk/args/***` runs that whole subtree (`X/***` deliberately excludes files directly in `X`; bare `X` is files-directly-in-X only). The flag accepts a space-separated list of patterns and may also be repeated, with all occurrences accumulating (`-multiple 1` as of 2026-07-10; previously the last flag silently won). Single-file targeting: `-include-paths modules/punk/args/testsuites/args dynamic.test`.
- Use `-exclude-paths` (same syntax and accumulation) to remove directories from discovery — `**`|`***` tails prune the matched subtree, other matches drop only that directory's files, and exclusion wins for the same file. It gives broad runs a middle ground between full and targeted: e.g `-exclude-paths shell/***` when no built kit is present, or skipping a heavy suite family unrelated to the change. - Use `-exclude-paths` (same syntax and accumulation) to remove directories from discovery — `**`|`***` tails prune the matched subtree, other matches drop only that directory's files, and exclusion wins for the same file. It gives broad runs a middle ground between full and targeted: e.g `-exclude-paths shell/***` when no built kit is present, or skipping a heavy suite family unrelated to the change.

2
src/tests/shell/AGENTS.md

@ -19,7 +19,7 @@ Tests for shell-level behavior, command-line execution, and stdin/stdout interac
- `testsuites/punkexe/shellexit.test` guards piped-stdin termination behaviour of the built executable (no `invalid thread handle` on shutdown races, no console-reopen hang on eof/error paths, exitcode propagation); do not weaken these tests - a red result means a regression in punk::repl shutdown or app-punkshell eof handling. - `testsuites/punkexe/shellexit.test` guards piped-stdin termination behaviour of the built executable (no `invalid thread handle` on shutdown races, no console-reopen hang on eof/error paths, exitcode propagation); do not weaken these tests - a red result means a regression in punk::repl shutdown or app-punkshell eof handling.
- `testsuites/punkexe/shellnavns.test` proves the namespace-navigation session contract end-to-end over a piped 'src'-mode session (dev modules - deliberate, so current punk::repl/nav source is exercised without a rebuild): n/ sets ns_current, the current namespace continues into `subshell punk` and back out (currently via the documented first-subshell shared-code-interp asymmetry - the SHARED marker pins it; the repl::start seeding template for genuinely separate interps is proven in modules/punk/repl nscurrent.test), the punk::repl 0.5.2 stray-namespace fix holds live, and the session exits cleanly. KNOWN GAP pinned there: piped submissions evaluate at :: despite ns_current (interactive and module-level inscope behaviour differ) - investigate alongside G-038. - `testsuites/punkexe/shellnavns.test` proves the namespace-navigation session contract end-to-end over a piped 'src'-mode session (dev modules - deliberate, so current punk::repl/nav source is exercised without a rebuild): n/ sets ns_current, the current namespace continues into `subshell punk` and back out (currently via the documented first-subshell shared-code-interp asymmetry - the SHARED marker pins it; the repl::start seeding template for genuinely separate interps is proven in modules/punk/repl nscurrent.test), the punk::repl 0.5.2 stray-namespace fix holds live, and the session exits cleanly. KNOWN GAP pinned there: piped submissions evaluate at :: despite ns_current (interactive and module-level inscope behaviour differ) - investigate alongside G-038.
- `testsuites/punkexe/scriptexec.test` covers the `script` subcommand (app-punkscript, G-015): piped execution + honest exit codes, result echo, file-form argv, the `lib:<name>` scriptlib-resolution mechanism (incl. punk::path 0.3.0 extensionless-tcl matching: first-line identification, called-spelling precedence over a `.tcl` sibling, sh-trampoline shebang acceptance, and the non-tcl skip note on not-found), and the tclsh-matching Tk main-loop behaviour. The `lib:` and Tk cases resolve committed fixtures under `scriptlib/_punktest/` (test-owned; a `lib:`-resolvable fixture cannot live in a tcltest temp dir since resolution only searches scriptlib locations relative to the exe). Tk cases are gated by the `punktk` constraint, auto-detected by probing whether the kit can load Tk. - `testsuites/punkexe/scriptexec.test` covers the `script` subcommand (app-punkscript, G-015): piped execution + honest exit codes, result echo, file-form argv, the `lib:<name>` scriptlib-resolution mechanism (incl. punk::path 0.3.0 extensionless-tcl matching: first-line identification, called-spelling precedence over a `.tcl` sibling, sh-trampoline shebang acceptance, and the non-tcl skip note on not-found), and the tclsh-matching Tk main-loop behaviour. The `lib:` and Tk cases resolve committed fixtures under `scriptlib/_punktest/` (test-owned; a `lib:`-resolvable fixture cannot live in a tcltest temp dir since resolution only searches scriptlib locations relative to the exe). Tk cases are gated by the `punktk` constraint, auto-detected by probing whether the kit can load Tk.
- punkexe tests run against the built binary: after changing punk::repl or app-punkshell source, rebuild via `make.tcl packages`, `make.tcl vfscommonupdate -confirm 0` (unattended runs must pass the flag - the REPLACE confirmation aborts fast on non-interactive stdin instead of reading a piped `y`), then `make.tcl project` before trusting results; `make.tcl project` alone does not refresh `_vfscommon.vfs`. - punkexe tests run against the built binary: after changing punk::repl or app-punkshell source, rebuild via `make.tcl packages`, `make.tcl vfscommonupdate -confirm 0` (unattended runs must pass the flag - the REPLACE confirmation aborts fast on non-interactive stdin instead of reading a piped `y`), then `make.tcl bake` before trusting results; `make.tcl bake`/`bakehouse` alone does not refresh `_vfscommon.vfs` (vfscommonupdate is the promotion gate).
- `testsuites/punkexe/tclshcmd.test` covers the `tclsh` subcommand (punk_main.tcl dispatch): script-file sourcing (argv0/argv/info-script state, honest exit codes incl. explicit exit), piped no-arg stdin evaluation, stock argument forms (leading `-` arg = no script, all args stay in `::argv`; `-encoding name file` sources with the named encoding, incomplete `-encoding` forms fall through to argv; verified byte-level via a utf-8/iso8859-1 fixture), the `lib:` refusal (plain-tclsh semantics - pointer to the `script` subcommand, exit 1), and - on kits built on a TCLSH_PIPEREPL-patched runtime (G-096/G-103, see `src/buildsuites/suite_tcl90/patches/README.md`) - the piperepl launch-state contract: ::tclsh(istty) published, piped script-arg launch state all-zero, unconsumed piped input NOT evaluated unless the script sets `::tclsh(evalinput) 1`, and the script's right to consume stdin itself; plus the degraded-mode notice on unpatched runtimes. Patched-kit resolution: `env(PUNK_PIPEREPL_TEST_EXE)` if it probes as patched, else the punkexe if patched, else `bin/punk9_beta.exe`/`bin/punk9bi_beta.exe`. HANG RULE: no PIPED test or fixture may set `::tclsh(dorepl)` - that path reopens stdin from the console (CONIN$) and blocks under the piped punk_run harness. Console-reopen coverage exists but is env-gated (G-118 item 11; constraint `punkconsole` = windows + env `PUNK_TEST_CONSOLE=1`, normal runs skip): two tests drive the dorepl path end-to-end in the child's OWN hidden console per the G-106 recipe - an outer `Start-Process -WindowStyle Hidden` powershell wrapper owns a fresh console and runs `<kit> tclsh` there with std handles redirected to files, then `testsupport/consoleinject.ps1` attaches to that console and types the verification lines + `exit 0` as key events. They pin: `::tclsh(reopened)` flips 0 -> 1 at reopen while `istty` stays 0 (immutable launch fact), `::tclsh(inputbuffer)` appears empty (the repl loop consumed all piped input), the reopen notice is silent by default and appears on STDERR only under `TCLSH_PIPEREPL_DEBUG=1`, and the injected exit completes the process (exit code 0). Deadlines plus wrapper-tree kill keep them hang-proof. - `testsuites/punkexe/tclshcmd.test` covers the `tclsh` subcommand (punk_main.tcl dispatch): script-file sourcing (argv0/argv/info-script state, honest exit codes incl. explicit exit), piped no-arg stdin evaluation, stock argument forms (leading `-` arg = no script, all args stay in `::argv`; `-encoding name file` sources with the named encoding, incomplete `-encoding` forms fall through to argv; verified byte-level via a utf-8/iso8859-1 fixture), the `lib:` refusal (plain-tclsh semantics - pointer to the `script` subcommand, exit 1), and - on kits built on a TCLSH_PIPEREPL-patched runtime (G-096/G-103, see `src/buildsuites/suite_tcl90/patches/README.md`) - the piperepl launch-state contract: ::tclsh(istty) published, piped script-arg launch state all-zero, unconsumed piped input NOT evaluated unless the script sets `::tclsh(evalinput) 1`, and the script's right to consume stdin itself; plus the degraded-mode notice on unpatched runtimes. Patched-kit resolution: `env(PUNK_PIPEREPL_TEST_EXE)` if it probes as patched, else the punkexe if patched, else `bin/punk9_beta.exe`/`bin/punk9bi_beta.exe`. HANG RULE: no PIPED test or fixture may set `::tclsh(dorepl)` - that path reopens stdin from the console (CONIN$) and blocks under the piped punk_run harness. Console-reopen coverage exists but is env-gated (G-118 item 11; constraint `punkconsole` = windows + env `PUNK_TEST_CONSOLE=1`, normal runs skip): two tests drive the dorepl path end-to-end in the child's OWN hidden console per the G-106 recipe - an outer `Start-Process -WindowStyle Hidden` powershell wrapper owns a fresh console and runs `<kit> tclsh` there with std handles redirected to files, then `testsupport/consoleinject.ps1` attaches to that console and types the verification lines + `exit 0` as key events. They pin: `::tclsh(reopened)` flips 0 -> 1 at reopen while `istty` stays 0 (immutable launch fact), `::tclsh(inputbuffer)` appears empty (the repl loop consumed all piped input), the reopen notice is silent by default and appears on STDERR only under `TCLSH_PIPEREPL_DEBUG=1`, and the injected exit completes the process (exit code 0). Deadlines plus wrapper-tree kill keep them hang-proof.
- `testsuites/binscripts/runtimebash_wsl.test` (G-059) exercises the punk-runtime.cmd unix payload (`src/scriptapps/bin/punk-runtime.bash`) through WSL: active/use/run resolution, env override, stale-active guidance, single-candidate fallback, and `list -remote` local-vs-server comparison (offline via a crafted cached sha1sums.txt + `PUNKBIN_URL` pointed at an unreachable address). Gated by the `wsllinux` capability constraint from `src/tests/testsupport/wslprobe.tcl`; all execution happens in a WSL-native staging dir, and a final test asserts the Windows checkout's git status is unchanged by the run. - `testsuites/binscripts/runtimebash_wsl.test` (G-059) exercises the punk-runtime.cmd unix payload (`src/scriptapps/bin/punk-runtime.bash`) through WSL: active/use/run resolution, env override, stale-active guidance, single-candidate fallback, and `list -remote` local-vs-server comparison (offline via a crafted cached sha1sums.txt + `PUNKBIN_URL` pointed at an unreachable address). Gated by the `wsllinux` capability constraint from `src/tests/testsupport/wslprobe.tcl`; all execution happens in a WSL-native staging dir, and a final test asserts the Windows checkout's git status is unchanged by the run.
- `testsuites/binscripts/runtimecmd_freshness.test` (G-119) exercises the punk-runtime freshness verdict (active-vs-server-default: current/ahead/behind/incomparable) in BOTH payloads against a fixture punkbin server: a child-process http file server (`testsupport/httpfixture.tcl`) serves a crafted layout (defaults.txt, sha1sums, artifacts + metadata tomls) via the `PUNKBIN_URL` override, with all execution in a tempdir staging area on a fixture platform folder (`testplat-x86_64` - the real `bin/runtime` store is untouched). The powershell payload runs as the staged committed `bin/punk-runtime.cmd` via cmd.exe (the wrap-pinned path); the bash payload is driven DIRECTLY under a probed msys/git bash (uname MINGW*/MSYS*; WSL bash is rejected - under WSL2 it cannot reach the 127.0.0.1 fixture server, and on windows the polyglot routes unix shells to the powershell payload anyway). Asserts the G-119 acceptance scenarios (ahead/behind+guidance/current-annotation/pre-family no-basis and hash-identity/no-name-fetch note) with ps1-vs-bash verdict-line parity, plus the identity middle column row shapes (2026-07-25 follow-on): `from=<artifact>` working-copy rows with content-verified Remote statuses (Same version / CONTENT DIFFERS / artifact-not-listed), `sha1=<name>` byte-copy strays, and the identity-following `(server default)` row annotation. Gated by capability constraints (windows, committed cmd, bash source, certutil, msys bash, fixture server started); skips cleanly elsewhere. - `testsuites/binscripts/runtimecmd_freshness.test` (G-119) exercises the punk-runtime freshness verdict (active-vs-server-default: current/ahead/behind/incomparable) in BOTH payloads against a fixture punkbin server: a child-process http file server (`testsupport/httpfixture.tcl`) serves a crafted layout (defaults.txt, sha1sums, artifacts + metadata tomls) via the `PUNKBIN_URL` override, with all execution in a tempdir staging area on a fixture platform folder (`testplat-x86_64` - the real `bin/runtime` store is untouched). The powershell payload runs as the staged committed `bin/punk-runtime.cmd` via cmd.exe (the wrap-pinned path); the bash payload is driven DIRECTLY under a probed msys/git bash (uname MINGW*/MSYS*; WSL bash is rejected - under WSL2 it cannot reach the 127.0.0.1 fixture server, and on windows the polyglot routes unix shells to the powershell payload anyway). Asserts the G-119 acceptance scenarios (ahead/behind+guidance/current-annotation/pre-family no-basis and hash-identity/no-name-fetch note) with ps1-vs-bash verdict-line parity, plus the identity middle column row shapes (2026-07-25 follow-on): `from=<artifact>` working-copy rows with content-verified Remote statuses (Same version / CONTENT DIFFERS / artifact-not-listed), `sha1=<name>` byte-copy strays, and the identity-following `(server default)` row annotation. Gated by capability constraints (windows, committed cmd, bash source, certutil, msys bash, fixture server started); skips cleanly elsewhere.

4
src/tests/shell/testsuites/punkexe/scriptexec.test

@ -16,8 +16,8 @@ package require tcltest
#then <projectroot>/bin/punkshell902. Skipped (constraint punkexeavailable) if none found. #then <projectroot>/bin/punkshell902. Skipped (constraint punkexeavailable) if none found.
# #
#NOTE: exercises the BUILT executable - after changing app-punkscript / punk::path / punk_main #NOTE: exercises the BUILT executable - after changing app-punkscript / punk::path / punk_main
#dispatch, rebuild with 'make.tcl libs' (or packages), 'make.tcl vfscommonupdate' (interactive y), #dispatch, rebuild with 'make.tcl libs' (or packages), 'make.tcl vfscommonupdate -confirm 0',
#then 'make.tcl project', or these tests run against a stale binary. #then 'make.tcl bake', or these tests run against a stale binary.
namespace eval ::testspace { namespace eval ::testspace {
namespace import ::tcltest::* namespace import ::tcltest::*

2
src/tests/shell/testsuites/punkexe/tclshcmd.test

@ -43,7 +43,7 @@ package require tcltest
#whose runtime lacks the patch. #whose runtime lacks the patch.
# #
#NOTE: exercises BUILT executables - after changing the tclsh dispatch in #NOTE: exercises BUILT executables - after changing the tclsh dispatch in
#src/vfs/_config/punk_main.tcl, rebuild the kit under test ('make.tcl project' for the #src/vfs/_config/punk_main.tcl, rebuild the kit under test ('make.tcl bake' for the
#standard punkexe; family kits like punk9_beta come from src/buildsuites wrap runs) or #standard punkexe; family kits like punk9_beta come from src/buildsuites wrap runs) or
#these tests run against a stale binary. #these tests run against a stale binary.

6
src/vfs/AGENTS.md

@ -12,7 +12,7 @@ VFS (Virtual File System) folders define the runtime payloads that get wrapped i
## Local Contracts ## Local Contracts
- `*.vfs` folders are build artifacts consumed by `tclsh src/make.tcl project`. - `*.vfs` folders are build artifacts consumed by the kit-assembly stage `tclsh src/make.tcl bake` (and its consumer umbrella `bakehouse`).
- A `*.vfs` folder built against a runtime is expected to carry a root-level startup script: an actual `main.tcl`, or a root fauxlink resolving to the name `main.tcl` whose target exists and is a `.tcl` file. `make.tcl` warns when neither is present (column-0 `BUILD-WARNING:` token, ANSI-highlighted, recapped at end of run like provenance warnings) but still builds - a kit without a startup script is legal. Overlay-only folders with no runtime mapping (e.g `_vfscommon.vfs`) are not checked. - A `*.vfs` folder built against a runtime is expected to carry a root-level startup script: an actual `main.tcl`, or a root fauxlink resolving to the name `main.tcl` whose target exists and is a `.tcl` file. `make.tcl` warns when neither is present (column-0 `BUILD-WARNING:` token, ANSI-highlighted, recapped at end of run like provenance warnings) but still builds - a kit without a startup script is legal. Overlay-only folders with no runtime mapping (e.g `_vfscommon.vfs`) are not checked.
- VFS content must be compatible with the target platform runtime. - VFS content must be compatible with the target platform runtime.
- `_vfscommon.vfs/` is an auto-generated merge of common libraries; manually editing it will be overwritten. - `_vfscommon.vfs/` is an auto-generated merge of common libraries; manually editing it will be overwritten.
@ -23,13 +23,13 @@ VFS (Virtual File System) folders define the runtime payloads that get wrapped i
## Work Guidance ## Work Guidance
- To add a module to a VFS build, update the VFS folder's module set, then run `tclsh src/make.tcl project`. - To add a module to a VFS build, update the VFS folder's module set, then run `tclsh src/make.tcl bake`.
- The `src/runtime/mapvfs.config` file maps VFS folders to platform runtimes. - The `src/runtime/mapvfs.config` file maps VFS folders to platform runtimes.
- Describe regeneration steps in commit messages when touching VFS payloads. - Describe regeneration steps in commit messages when touching VFS payloads.
## Verification ## Verification
- `tclsh src/make.tcl project` builds without errors. - `tclsh src/make.tcl bake` builds without errors.
- Built binary starts and loads the expected module set. - Built binary starts and loads the expected module set.
## Child DOX Index ## Child DOX Index

Loading…
Cancel
Save