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.
 
 
 
 
 
 

12 KiB

G-030 make.tcl dogfoods punk::args: tabled usage, declared subcommands, prompt-free flags

Status: achieved 2026-07-14 Scope: src/make.tcl (dispatch, help, prompts), src/bootsupport/AGENTS.md + src/modules/AGENTS.md (bootstrap-tracked staleness contract), src/modules/punk/args-999999.0a1.0.tm (only as consumed) Goal: make.tcl - the first surface a developer sees - parses its subcommands and options via punk::args and showcases the tabled usage output for help and argument errors, every interactive y/n prompt gains a declared flag equivalent so agents can drive make.tcl with arguments instead of piped input, punk::args joins the bootstrap-tracked staleness set, and the boot phase plus the environment-repair commands keep working with degraded plain help when the bootsupport punk::args (or the table-rendering stack) is stale or unavailable. Acceptance: tclsh src/make.tcl and -help render punk::args tabled usage listing every subcommand with a summary, and make.tcl help <subcommand> (or <subcommand> -help) shows that subcommand's definition; invalid arguments produce a punk::args usage error rather than ad-hoc messages; every y/n prompt has a documented flag equivalent (proven at least for vfscommonupdate and the project-build confirmations: a run with the flag completes non-interactively with stdin closed) and a non-interactive stdin without the flag fails fast with usage rather than hanging or half-aborting; punk::args is added to the bootstrap-tracked buildversion set with the doc contract updated (src/bootsupport/AGENTS.md, src/modules/AGENTS.md); with bootsupport punk::args unavailable or unloadable, make.tcl still boots and check, bootsupport and modules remain usable with plain-text fallback help (the guarded-require degrade rule); layout make.tcl copies follow via the established sync/G-027 channels (noted, not hand-synced).

Context

make.tcl is the first surface a developer meets in a punkshell-derived project, but its command handling predates the ecosystem's own tooling: a hand-built help text, a bare known_commands list, ad-hoc argument handling per subcommand, and interactive y/n prompts (vfscommonupdate's REPLACE confirmation, the project-build confirmations, bootsupport staleness prompts). Eating our own dogfood - punk::args definitions per subcommand with the tabled usage rendering - both showcases the ecosystem where it is most visible and makes the parsing declarative.

The prompts are the practical payoff: agent-driven builds currently pipe y into stdin (fragile, undiscoverable - observed 2026-07-07 while rebuilding tomlish.exe). With punk::args parsing, prompt-free operation is just another declared option per subcommand, and non-interactive stdin without the flag can fail fast with usage instead of hanging on a read or half-aborting.

Precedents already in-tree: src/tests/runtests.tcl parses via punk::args ((script)::runtests definition), and the tomlish cmdline app presents tabled usage as its first surface.

Approach

  • One PUNKARGS definition per subcommand (@cmd -summary/-help + opts), plus a top-level definition enumerating subcommands - replacing punkboot_gethelp and the hand-maintained help strings. make.tcl, make.tcl -help, and per-subcommand help all render through punk::args::usage.
  • Prompt policy: interactive stdin -> prompt as today (default); flag supplied (e.g. -confirm 0 / -y, naming decision recorded here) -> proceed without prompting; non-interactive stdin without the flag -> usage error, fast. The bootsupport staleness prompt keeps its abort/prompt/proceed classification but gains the same flag route.
  • Degradation is a hard requirement (the 2026-07-06/07 incidents are the cautionary tale: a stale bundled fileutil disabled the very make.tcl step needed to fix it). The boot phase stays self-contained; punk::args is guarded-lazily required post-boot (the punkboot::utils pattern documented in src/bootsupport/AGENTS.md); when unavailable, dispatch and the repair commands (check, bootsupport, modules) keep working with plain-text fallback help. Note the tabled rendering also pulls punk::ansi/textblock/punk::char - exactly the modules whose same-version staleness broke shellfilter this week
    • so rendering must degrade independently of parsing (punk::args plain output when the ANSI stack is unhealthy).
  • Staleness tracking: punk::args joins the bootstrap-tracked buildversion set (currently punkcheck, punk::repo, punk::mix, punk::tdl) with the same bump-at-least-minor-on-call-site-API-change discipline; whether the rendering stack is also tracked or left to degrade is an implementation decision to record here (initial lean: track punk::args only - it is the parsing contract; rendering degrades).
  • Layout copies of make.tcl follow through the existing punkcheck-tracked sync (custom/_project) and the G-012/G-027 channels for the rest - noted in completion reports, never hand-synced.

Alternatives considered

  • Ad-hoc -y flags bolted onto the current hand parsing - rejected: solves the agent problem but leaves the first-surface help un-showcased and the parsing divergent from the ecosystem's own conventions.
  • Requiring punk::args at boot (no fallback) - rejected: make.tcl must be able to repair the very bootsupport snapshot it loads punk::args from.

Notes

  • Related: G-015 (agents driving punk tooling non-interactively), G-024 (mapvfs toml errors deserve the same declared-argument quality), G-025 (the version-report subcommand should be born punk::args-defined), G-027 (pull updates deliver the improved make.tcl to derived projects).
  • Observation parked here from the same session: runtests/make.tcl-adjacent tooling that returns result dicts should document their key shape (see the runx -tcl exitcode note in G-015's detail).
  • Archived-goal references in this file: G-015 achieved 2026-07-07 (goals/archive/G-015-script-subcommand-piped-stdin.md).

Progress

2026-07-14: implemented whole and verified; punkproject 0.12.24.

What shipped (src/make.tcl)

  • Declarative dispatch: punk::args definitions (script)::punkboot (top level: subcommand leader with -choicegroups/-choicelabels subtables) and (script)::punkboot::<subcommand> for all 15 subcommands, built in ::punkboot::argdoc from single-source dicts (SUMMARIES/HELPTEXTS/SUBOPTS/ OPT_SYNOPSES) plus shared option fragments (OPT_CONFIRM/OPT_DIRTYABORT/ OPT_FORCEKILL) composed via multi-part punk::args::define. Explicit @form -synopsis per definition so usage shows the real invocation (make.tcl modules ?-dirty-abort? ?-confirm 0|1?) rather than the internal id.
  • make.tcl / -help / help ?subcommand? / <subcommand> -help all render punk::args tabled usage (the missing/broken bootsupport-package NOTE was factored into punkboot_availability_note and is appended to both the tabled and the plain-fallback help). Invalid flags and unknown subcommands raise punk::args usage errors (exit 1); unambiguous subcommand prefixes resolve (make.tcl vfsc...).
  • shell is a declared passthrough: its definition documents that trailing args go to the repl unparsed.
  • Prompt policy - naming decision: -confirm 0|1 (boolean, default 1), declared on every subcommand that can hit a confirmation point:
    • -confirm 1 (default): prompt when stdin is an interactive terminal; when stdin is NOT interactive, abort fast at the confirmation point with guidance instead of reading stdin (no more piped y, no half-aborts - the old vfscommonupdate decline path printed "done" and exited 0; it now exits 1 with "-aborted-").
    • -confirm 0: never prompt; documented per-site resolutions: staleness minor-bump gate -> proceed, vfscommonupdate REPLACE -> proceed, kit source/target type mismatch -> skip that kit (only an interactive 'y' can force building a mismatched kit). All three gets stdin confirmation sites reworked; interactivity probe is ::punkboot::lib::stdin_is_interactive (8.7+/9 -inputmode on terminal channels only; Tcl 8.6 caveat: no probe exists, stdin is assumed interactive there - piped 8.6 runs should pass -confirm explicitly; documented in the option help and bootsupport AGENTS.md).
  • Staleness tracking: punk::args joined _runtime_deps (punk/args-buildversion.txt). Decision recorded: track punk::args only - it is the parsing contract; the tabled-rendering stack (punk::ansi, textblock) stays untracked and degrades instead.
  • Degrade rule implemented at three levels: (1) boot requires for punk::args/punk::ansi/textblock are guarded (stderr note, no abort); (2) definition build is caught - any failure falls back to a self-contained scan (rewritten from the old hand parser; handles -k/-dirty-abort/-confirm and help) plus plain-text punkboot_gethelp; (3) rendering degrades independently of parsing (errorstyle minimal when the ANSI stack is unhealthy; usage render failure falls back to plain help). PUNKBOOT_PLAIN=1 forces the degraded mode (troubleshooting/test hook).
  • Flag plumbing: -k (project/vfs/bin), -dirty-abort (the nine build/promotion commands) and -confirm now flow from parsed opts into ::punkboot::opt_forcekill/opt_dirty_abort/opt_confirm; the old lsearch $::argv sites read those variables instead.

Verification (all under tclsh 9.0.2, from repo root)

  • Bare/-help/help <sub>/<sub> -help: tabled usage with grouped subcommand/summary subtables; help with a bad subject and an unknown subcommand both raise choiceviolation usage errors (exit 1); modules -bogus raises invalidoption (exit 1).
  • vfscommonupdate </dev/null -> fast abort exit 1 with -confirm guidance, no changes; vfscommonupdate -confirm 0 </dev/null -> completed exit 0, idempotent (no git churn).
  • Staleness flag route proven live: adding punk::args to _runtime_deps immediately tripped the minor gate (bootsupport 0.5.0 vs source 0.12.0): info </dev/null aborted fast exit 1; modules -confirm 0 and bootsupport -confirm 0 proceeded non-interactively and refreshed the snapshot (args 0.12.0 + punk 0.2.6, lib 0.4.3, ns 0.5.0, repl 0.5.1, tclcore moduledoc 0.3.4), after which the gate is silent.
  • Degraded mode: PUNKBOOT_PLAIN=1 runs of bare help / check / info -confirm 0 / unknown-command all work on the plain scan + gethelp (exit codes preserved). The guarded-require path was also exercised for real during development (a transient condition inversion ran the whole session on the fallback - plain help rendered, flags worked).
  • Full project -k -confirm 0 regression build with stdin a pipe: completed, kits built/installed (see repo CHANGELOG 0.12.24 entry).
  • Layout make.tcl + bootsupport copies followed via the established punkcheck channel (make.tcl bootsupport run; not hand-synced) - G-027 remains the delivery route to derived projects.

Findings on punk::args (dogfooding yield)

  • Optional-arg choice-mismatch error-quality regression between 0.5.0 and 0.12.0: a leader/value with -optional 1 and restricted -choices that receives a non-matching word now falls through to a generic "Received more values than can be assigned" (toomanyarguments) instead of the pointed choiceviolation that 0.5.0 reported (verified: identical defs, only the loaded punk::args version differs; -choicegroups and @form presence are NOT factors). Worked around here by declaring subcommand/subject -optional 0 (dispatch only parses when a word is present, so the empty case never reaches parse). Candidate punk::args improvement: single-form error selection should prefer a nearby choiceviolation over toomanyarguments when a rejected optional arg explains the overflow (adjacent to the rank_form_failures work; relates to proposed G-073).
  • @cmd -name is displayed in the COMMAND header but the auto-generated synopsis uses the definition id - script-level definitions with ids like (script)::punkboot::<sub> want an explicit @form -synopsis (adopted here; possible future punk::args nicety: fall back to @cmd -name for synopsis rendering).

Deferred / out of scope

  • The kit-type-mismatch confirmation cannot be triggered without a mismatched runtime/target configuration - its -confirm handling is code-reviewed, not runtime-proven (the prompt sites share the same policy helper).
  • punk::args error-selection improvement above left to punk::args goals (G-072/G-073 territory) rather than patched mid-goal.
  • Old echo y | make.tcl vfscommonupdate agent workflow is retired; docs updated (src/AGENTS.md, src/tests/shell/AGENTS.md, src/bootsupport/AGENTS.md, src/modules/AGENTS.md).