Browse Source

G-168 achieved: selection-sound launch definitions - script/tclsh forms match dispatch reality (punkexe moduledoc 0.7.0)

User-directed activation and implementation in one arc (proposed -> active at
the user's word with the activation-freshness survey recorded, -> achieved +
archived on acceptance). The declarations follow the 2026-08-05 pre-test
findings exactly - no engine change was needed.

(script)::punkexe::script: the file form fences scriptfile with
-regexprefail {^-e$} and a -regexprefailmsg naming the ./-e reachability
(word-1 '-e' is the ONLY fenced word - every other dash-led word remains a
file path, matching app-punkscript's word-1 test); the oneliner form declares
the '-e' word as a real element - a required -type none flag (the
auto_exec::hash -r/-d shape) ahead of the existing required script value, so
a bare {-e} reports noformmatch with the oneliner form verdicting
viable-incomplete via the G-164 re-probe (the app's "-e requires a script
argument" reality) and the file form invalid.

(script)::punkexe::tclsh: scriptfile gains -regexprefail {^-} (stock
tclMain.c: a dash-led word in script-file position means NO script) and the
stdin form's first word is a declared fenced element 'firstarg'
(-regexprefail {^[^-]} - a non-dash first word IS a script file; not an
option, stays in ::argv). Selection now matches stock classification on
every line except the recorded LIMIT: the complete
'-encoding <name> <scriptfile>' shape word-shape-matches both forms (a
dash-led encoding NAME included - the engine consumes dash-led option
values, matching stock's unconstrained argv[2]) and stock's arity-priority
rule is not expressible per-word - the pair is declared
@form -overlapallowed {scriptfile} on the stdin form (formcheck sanction)
while parse raises multipleformmatches naming both forms per the G-041
no-silent-preference contract. Dispatch never parses these ids, so the
ambiguity surfaces only in declaration-driven consumers (help dry-runs,
completion), where the two-form diagnosis is the honest answer.

Decisions recorded in the archived detail file: dispatch parse-gating NOT
adopted (punkboot_core.tcl untouched; script/tclsh stay declared passthrough
surfaces - boot-path parse cost, stock-parity conflict with the LIMIT, app
error surfaces already honest and pinned, and the declaration-driven
consumers get parse-trueness without gating; no latency delta applicable);
the <punkexe> @form -synopsis overrides KEPT (neither the raw (script) id
nor @cmd -name is an invocable name; the stdin override keeps the
user-facing '?arg ...?' line over the model's firstarg/arg split) - the
G-144 archived follow-on flipped to declined accordingly (make.tcl's own
override retirement had already landed in the 0.41.0 arc). A real-vs-model
probe matrix (G-055 method; bin/punk91 dispatch + app-punkscript real side)
is recorded in the detail file - model matches real classification on every
line except the two complete-'-encoding' rows (the sanctioned LIMIT).

Tests: new args/punkexemodel.test (6 - script/tclsh selection matrices
against the real ids with the real-side oracle referenced, the bare-'-e'
viable-incomplete verdict, the ./-e fence message, -encoding fall-through
statuses (scriptfile invalid vs incomplete, stdin selected), the LIMIT pins
naming {scriptfile stdin} for both complete shapes); formcheck.test punkexe
GAPs flipped deliberately per the acceptance:
formcheck_punkexe_script_forms_discriminated (zero findings),
formcheck_punkexe_tclsh_forms_sanctioned (unsanctioned empty + the stdin
form's -overlapallowed pinned via get_spec; the positional-chain witness
derivation misses option-dependent overlaps - formcheck's documented miss
direction - so the sanction also future-proofs improved derivation),
formcheck_punkexe_primary_inputs_selection_sound (dispatch-true forms for
every primary line; empty input still selects file/stdin uniquely). Full
modules/punk/args subtree 337 passed / 3 pre-existing skips / 0 failed on
BOTH native tclsh90 (9.0.3) and tclsh87;
src/tests/shell/testsuites/punkexe/launcherhelp.test 24/24 unchanged per
acceptance (its 'help script'/'help tclsh' pins glob only @cmd -name
strings - row additions verified safe post-bake as well). Minted
modules/punk/args/moduledoc/punkexe-0.7.0.tm via make.tcl modules;
kits/bootsupport carry 0.6.1 until the next promotion/bake cycle.

Goals: G-168 entry moved to GOALS-archive.md, detail file to goals/archive/
with the probe matrix, both decisions and verification evidence; one open
Follow-on (arity-priority expressibility would flip the LIMIT pins; the
broader selection-soundness sweep stays recorded in G-150's archive).
Activation survey Related: line added (G-169 back-pointer). Reference sweep:
G-169 coordination note updated (G-168 landed first - the re-homed
definitions carry this fencing shape), G-170 dependency marked satisfied
(its dry-run arm inherits the recorded LIMIT). src/tests/modules AGENTS.md
punk/args bullet extended. goals_lint clean (82 active / 88 archived).

Claude-Session: https://claude.ai/code/session_0156PuejSCGjgeGb7jiABrDU
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 1 week ago
parent
commit
2339e4065e
  1. 4
      GOALS-archive.md
  2. 4
      GOALS.md
  3. 73
      goals/G-168-selection-sound-launch-definitions.md
  4. 10
      goals/G-169-app-owned-launch-docs.md
  5. 7
      goals/G-170-launcher-help-depth.md
  6. 2
      goals/archive/G-144-punkargs-synopsis-name-fallback.md
  7. 210
      goals/archive/G-168-selection-sound-launch-definitions.md
  8. 56
      src/modules/punk/args/moduledoc/punkexe-999999.0a1.0.tm
  9. 3
      src/modules/punk/args/moduledoc/punkexe-buildversion.txt
  10. 2
      src/tests/modules/AGENTS.md
  11. 67
      src/tests/modules/punk/args/testsuites/args/formcheck.test
  12. 165
      src/tests/modules/punk/args/testsuites/args/punkexemodel.test

4
GOALS-archive.md

@ -20,6 +20,10 @@ Do not edit archived records here except to fix a broken path. Archived detail f
## Archived goals
### G-168 [achieved 2026-08-05] Selection-sound launch definitions: script/tclsh forms match dispatch reality → detail: goals/archive/G-168-selection-sound-launch-definitions.md
Scope: src/modules/punk/args/moduledoc/punkexe-999999.0a1.0.tm ((script)::punkexe::script + ::tclsh form discrimination); src/lib/app-punkscript/punkscript.tcl (behaviour oracle, error-surface decision); src/vfs/_config/punkboot_core.tcl (only if the dispatch-parse decision adopts gating, + synced copies via established channels); src/tests/modules/punk/args/testsuites/args/ (new model-parity suite); src/tests/shell/testsuites/punkexe/launcherhelp.test (as touched)
Acceptance: against the script definition, parse/parse_status select oneliner for {-e <code> ...}, select file for {<word> ...} where <word> ne -e, and {-e} alone reports noformmatch with oneliner viable-incomplete (the app's "-e requires a script argument" reality); against tclsh, {file args} selects scriptfile, a leading-dash word selects stdin, and an incomplete -encoding tail falls through to stdin (stock parity); formcheck reports no unsanctioned findings; a real-vs-model probe matrix (G-055 method) against actual dispatch/app-punkscript behaviour is recorded in this file; whether DISPATCH adopts parse-gating for script/tclsh (tabled pointed errors replacing app-punkscript's plain ones) is decided and recorded with rationale and, if adopted, a measured script-launch latency delta; the new behaviour is pinned in the args testsuite and launcherhelp.test passes unchanged (or with deliberately updated pins named here). (Achieved at punkexe moduledoc 0.7.0: file form scriptfile -regexprefail {^-e$} + ./-e message, oneliner '-e' as required solo flag ('-e' alone verdicts viable-incomplete via the G-164 re-probe); tclsh scriptfile {^-} fence + stdin firstarg {^[^-]} fence with the complete '-encoding <name> <scriptfile>' shape the recorded sanctioned LIMIT (@form -overlapallowed; parse raises multipleformmatches per G-041 no-silent-preference); dispatch parse-gating decided NOT adopted; probe matrix + decisions in the detail file; new punkexemodel.test + 3 formcheck GAP flips, args subtree green tclsh90+tclsh87, launcherhelp.test 24/24 unchanged.)
### G-151 [achieved 2026-08-05] punk::args annotated success render (received-args landing report) → detail: goals/archive/G-151-punkargs-annotated-success-render.md
Scope: src/modules/punk/args-999999.0a1.0.tm (parse-result presentation); src/tests/modules/punk/args/testsuites/args/
Acceptance: given a successful parse result (or the words plus definition id), a punk::args surface renders per-argument received-vs-default annotation covering leaders, opts and values including -multiple aggregation - the canonical demonstration being a flag-like word consumed as a VALUE (the 'punk91 -confirm 0'-as-three-values class) visibly attributed to its consuming argument; failure-side rendering is unchanged (existing arg_error pins pass); the behaviour is pinned in the args testsuite. make.tcl retiring its interim one-line 'dry-run: line accepted ...' report in favour of this render is recorded as consumer follow-through after a bootsupport promotion, not part of this acceptance. (Achieved as punk::args::parse_report - result-dict and words+withid entry forms, Argument|Source|Value landing table in table/tableobject/string/dict returns with the dict form never elided; type-aware always-marked display elision over the new ansistring TRUNCATE grapheme primitive (punk::ansi 0.2.0); caller -valuewidth > @cmd -reportvaluewidth > 48 width cascade; punk::args 0.18.0, new parsereport.test, args+ansi subtrees green on tclsh90 and tclsh87.)

4
GOALS.md

@ -402,10 +402,6 @@ Detail: goals/G-166-cmdinfo-unavailable-surfacing.md
Scope: src/modules/punk/args-999999.0a1.0.tm (form selection/candidacy availability filter + tailored raises, option-scan unavailable-name recognition, synopsis/table renderers - annotated form lines, unavailable option rows, automated other-shapes note, formstatus 'available' field, -form display-vs-parse split); src/modules/punk/ns-999999.0a1.0.tm (cmdhelp -return text form-section heading annotation; form narrowing inherits the availability filter); src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm (adoption on curated real 8.6-vs-9 deltas); src/tests/modules/punk/args/testsuites/args/ (new suite + formviability/tclcoreparity extensions)
Detail: goals/G-167-punkargs-version-delta-availability.md
### G-168 [proposed] Selection-sound launch definitions: script/tclsh forms match dispatch reality
Scope: src/modules/punk/args/moduledoc/punkexe-999999.0a1.0.tm ((script)::punkexe::script + ::tclsh form discrimination); src/lib/app-punkscript/punkscript.tcl (behaviour oracle, error-surface decision); src/vfs/_config/punkboot_core.tcl (only if the dispatch-parse decision adopts gating, + synced copies via established channels); src/tests/modules/punk/args/testsuites/args/ (new model-parity suite); src/tests/shell/testsuites/punkexe/launcherhelp.test (as touched)
Detail: goals/G-168-selection-sound-launch-definitions.md
### G-169 [proposed] App-owned launch-subcommand documentation consumed by the launcher
Scope: src/lib/app-punkscript/punkscript.tcl (carries its subcommand's punk::args definition via inert registration); src/modules/punk/args/moduledoc/punkexe-999999.0a1.0.tm (single-definer handover); src/vfs/_config/punkboot_core.tcl (built-in help resolution via app-owned ids, *_main.tcl declaration surface documented, + synced copies via established channels); src/tests/shell/testsuites/punkexe/launcherhelp.test
Detail: goals/G-169-app-owned-launch-docs.md

73
goals/G-168-selection-sound-launch-definitions.md

@ -1,73 +0,0 @@
# G-168 Selection-sound launch definitions: script/tclsh forms match dispatch reality
Status: proposed
Scope: src/modules/punk/args/moduledoc/punkexe-999999.0a1.0.tm ((script)::punkexe::script + ::tclsh form discrimination); src/lib/app-punkscript/punkscript.tcl (behaviour oracle, error-surface decision); src/vfs/_config/punkboot_core.tcl (only if the dispatch-parse decision adopts gating, + synced copies via established channels); src/tests/modules/punk/args/testsuites/args/ (new model-parity suite); src/tests/shell/testsuites/punkexe/launcherhelp.test (as touched)
Goal: The two multi-form launch-subcommand definitions are parse-discriminable with existing punk::args vocabulary - form auto-selection agrees with actual dispatch/app behaviour: the file form excludes exactly '-e' (-regexprefail {^-e$}, message naming ./-e), the oneliner form declares the '-e' word as a real element, and tclsh's scriptfile-vs-stdin split (leading-dash words stay argv; incomplete -encoding falls through, stock-style) is expressed through candidacy fall-through - so parse_status verdicts, noformmatch diagnoses and downstream consumers (help depth, completion) see the truth instead of a display-only model.
Acceptance: against the script definition, parse/parse_status select oneliner for {-e <code> ...}, select file for {<word> ...} where <word> ne -e, and {-e} alone reports noformmatch with oneliner viable-incomplete (the app's "-e requires a script argument" reality); against tclsh, {file args} selects scriptfile, a leading-dash word selects stdin, and an incomplete -encoding tail falls through to stdin (stock parity); formcheck reports no unsanctioned findings; a real-vs-model probe matrix (G-055 method) against actual dispatch/app-punkscript behaviour is recorded in this file; whether DISPATCH adopts parse-gating for script/tclsh (tabled pointed errors replacing app-punkscript's plain ones) is decided and recorded with rationale and, if adopted, a measured script-launch latency delta; the new behaviour is pinned in the args testsuite and launcherhelp.test passes unchanged (or with deliberately updated pins named here).
## Context
2026-08-05 discussion (formhint arc): 'punk9-dev -e' / 'script -e' error - word-1
'-e' is RESERVED by behaviour (app-punkscript punkscript.tcl:78-88; a file so
named needs ./-e), but the file form declares scriptfile as any string - the
definition is display-honest, parse-dishonest, and the forms cleanly double-match.
The blocker assumed earlier (G-072 negation) is not needed: -regexprefail is
honoured during form matching (verified in the G-143 make.tcl arc, achieved -
goals/archive/G-143-maketcl-multiform-help.md; the G-150 selection-sound hash
declaration is the dash-led-form-word precedent).
## Notes
- Enacts the punkexe portion of the G-150 follow-on "sweep other flat multi-form
definitions for selection-soundness" (goals/archive/G-150-cmdhelp-form-narrowing.md);
that follow-on stays open - the sweep is broader than these two definitions.
- The G-144 follow-on (punkexe moduledoc @form -synopsis override set drops once
auto-synopsis serves - goals/archive/G-144-punkargs-synopsis-name-fallback.md,
disposition flipped to this goal) is decided in this work: keep the <punkexe>
placeholder overrides or adopt @cmd -name auto lines - recorded either way.
- Related: G-089 (proposed) - script's lib:name resolution text is consumed scope.
- Related: G-055 (proposed) - the real-vs-model probe method borrowed here.
- Related: G-072 (proposed) - deliberate non-dependency: negation NOT required.
- Related: G-170 (proposed) - consumer: its dry-run arm requires this goal's
parse-trueness.
- Overlap survey 2026-08-05: goals_xref paths over the Scope - G-089 (named
above) is the only substantive live intersection on punkboot_core.tcl;
moduledoc-sibling matches (G-055 G-068 G-072 G-083 G-084 G-166 G-167) are
parser/spec mechanisms or other moduledocs, no availability interaction.
- 2026-08-05 pre-test findings (engine primitives probed on tclsh 9.0.3 and
pinned green on tclsh90+tcl87: forms.test fencing/fall-through group,
formviability_dangling_optional_option_conservative,
errsel_dangling_option_trailing_value_overflow, formcheck_GAP_punkexe_*):
- A -regexprefail rejection on an OPTIONAL value slot is fatal to that form's
candidacy - the word does NOT re-land on a later permissive slot (contrast
optional-CHOICE rejection, errsel_rejected_word_lands_later) - so per-slot
fencing fences whole forms (forms_fence_optional_slot_no_reland).
- Unknown options, dangling option words and option-satisfied-but-values-unmet
tails each fail only their form: auto-selection falls through to a sibling
as a SUCCESSFUL parse, and an option VALUE's -regexprefail participates in
candidacy too - the stock "-encoding recognised only before a non-dash word"
primitive is expressible (forms_fallthrough_* pins).
- LIMIT for the tclsh model: a complete '-encoding <name> <file>' line
wordwise-matches both a fenced scriptfile form and any dash-tolerant stdin
form; per-word constraints cannot express stock's "scriptfile wins when
complete" priority, so the no-silent-preference contract (G-041, achieved -
goals/archive/G-041-punkargs-form-matching.md) raises
multipleformmatches (forms_fenced_pair_residual_overlap). The tclsh
declaration must design around this class - form restructuring, an
-overlapallowed sanction (display-only; parse still raises), or the
dispatch-parse decision this goal already tables.
- The {-e}-alone viable-incomplete acceptance rides the re-probe of G-164
(achieved 2026-08-04 - goals/archive/G-164-viability-alternative-allocation.md),
which re-seats only words naming missing REQUIRED options: declare '-e' as a
required -type none flag plus a separate required script value (the
auto_exec::hash -r/-d shape), NOT as a value-taking option - a stolen word
naming a value-taking or OPTIONAL option keeps verdict invalid
(formviability_reprobe_value_taking_option_conservative and the new
formviability_dangling_optional_option_conservative twin).
- Before-state pinned as GAP: both punkexe multi-form definitions carry
unsanctioned structural formcheck findings and every primary launch line
double-matches ({-e X} / {file args} / {file} / {-encoding enc file});
empty input selects file/stdin uniquely (formcheck_GAP_punkexe_script_forms_overlap,
formcheck_GAP_punkexe_tclsh_forms_overlap,
formcheck_GAP_punkexe_primary_inputs_double_match - flipped deliberately
by this goal per its Acceptance).

10
goals/G-169-app-owned-launch-docs.md

@ -18,8 +18,14 @@ core-owned (tclcore precedent: separation + parity pins).
## Notes
- Coordination with G-168: either order works; whichever lands second edits the
definition at its then-current home (never two definers).
- Coordination with G-168 (achieved 2026-08-05 - goals/archive/G-168-selection-sound-launch-definitions.md):
G-168 landed first, so THIS goal is the one that lands second and edits the
definitions at their then-current home (never two definers) - the re-homed
script definition carries G-168's fencing shape (file form scriptfile
-regexprefail {^-e$} + ./-e message, oneliner '-e' as a required solo flag)
and any tclsh re-home carries the {^-}/{^[^-]} fences plus the stdin form's
-overlapallowed {scriptfile} sanction; the punkexemodel.test /
formcheck.test pins guard the handover.
- Related: G-075 (proposed) - sibling documentation-reachability surface.
- Related: G-042/G-043 (proposed) - adjacent declaration-composition patterns;
deliberate non-overlap (launch surface, not repl subshells).

7
goals/G-170-launcher-help-depth.md

@ -14,7 +14,12 @@ builds the destination, then points at it.
## Notes
- Depends on G-168 (proposed) for the dry-run arm (narrowing arm is standalone).
- Depends on G-168 (achieved 2026-08-05 - goals/archive/G-168-selection-sound-launch-definitions.md)
for the dry-run arm (narrowing arm is standalone) - now satisfied: the
script/tclsh forms are parse-discriminable and the dry-run arm inherits one
recorded LIMIT (the complete '-encoding <name> <scriptfile>' shape raises a
sanctioned multipleformmatches naming both forms - the honest two-form
diagnosis for that line; G-168's Progress records the rationale).
- Related: G-169 (proposed) - the defs' home determines where templates land.
- Related: G-151 (achieved 2026-08-05 - goals/archive/G-151-punkargs-annotated-success-render.md) -
the dry-run arm's received-args report is G-151's punk::args-level annotated

2
goals/archive/G-144-punkargs-synopsis-name-fallback.md

@ -45,4 +45,4 @@ The goal text named "(shared)/(package)-style doc ids" alongside (script) as ben
## Follow-ons
Follow-on: make.tcl drops its per-definition @form -synopsis overrides and the punkexe moduledoc's override set once the @cmd -name fallback serves them => goal G-168
Follow-on: make.tcl drops its per-definition @form -synopsis overrides and the punkexe moduledoc's override set once the @cmd -name fallback serves them => declined 2026-08-05 (decided in G-168, achieved - goals/archive/G-168-selection-sound-launch-definitions.md: the punkexe moduledoc override set is KEPT - neither the raw (script) id nor @cmd -name 'punkexe <sub>' is an invocable name, the <punkexe> placeholder matches the file's prose convention, and the tclsh stdin form's override keeps the user-facing '?arg ...?' line over the G-168 firstarg/arg fencing split; make.tcl's own override retirement had already landed in the 0.41.0 G-143/G-144 arc)

210
goals/archive/G-168-selection-sound-launch-definitions.md

@ -0,0 +1,210 @@
# G-168 Selection-sound launch definitions: script/tclsh forms match dispatch reality
Status: achieved 2026-08-05
Scope: src/modules/punk/args/moduledoc/punkexe-999999.0a1.0.tm ((script)::punkexe::script + ::tclsh form discrimination); src/lib/app-punkscript/punkscript.tcl (behaviour oracle, error-surface decision); src/vfs/_config/punkboot_core.tcl (only if the dispatch-parse decision adopts gating, + synced copies via established channels); src/tests/modules/punk/args/testsuites/args/ (new model-parity suite); src/tests/shell/testsuites/punkexe/launcherhelp.test (as touched)
Goal: The two multi-form launch-subcommand definitions are parse-discriminable with existing punk::args vocabulary - form auto-selection agrees with actual dispatch/app behaviour: the file form excludes exactly '-e' (-regexprefail {^-e$}, message naming ./-e), the oneliner form declares the '-e' word as a real element, and tclsh's scriptfile-vs-stdin split (leading-dash words stay argv; incomplete -encoding falls through, stock-style) is expressed through candidacy fall-through - so parse_status verdicts, noformmatch diagnoses and downstream consumers (help depth, completion) see the truth instead of a display-only model.
Acceptance: against the script definition, parse/parse_status select oneliner for {-e <code> ...}, select file for {<word> ...} where <word> ne -e, and {-e} alone reports noformmatch with oneliner viable-incomplete (the app's "-e requires a script argument" reality); against tclsh, {file args} selects scriptfile, a leading-dash word selects stdin, and an incomplete -encoding tail falls through to stdin (stock parity); formcheck reports no unsanctioned findings; a real-vs-model probe matrix (G-055 method) against actual dispatch/app-punkscript behaviour is recorded in this file; whether DISPATCH adopts parse-gating for script/tclsh (tabled pointed errors replacing app-punkscript's plain ones) is decided and recorded with rationale and, if adopted, a measured script-launch latency delta; the new behaviour is pinned in the args testsuite and launcherhelp.test passes unchanged (or with deliberately updated pins named here).
## Context
2026-08-05 discussion (formhint arc): 'punk9-dev -e' / 'script -e' error - word-1
'-e' is RESERVED by behaviour (app-punkscript punkscript.tcl:78-88; a file so
named needs ./-e), but the file form declares scriptfile as any string - the
definition is display-honest, parse-dishonest, and the forms cleanly double-match.
The blocker assumed earlier (G-072 negation) is not needed: -regexprefail is
honoured during form matching (verified in the G-143 make.tcl arc, achieved -
goals/archive/G-143-maketcl-multiform-help.md; the G-150 selection-sound hash
declaration is the dash-led-form-word precedent).
## Notes
- Enacts the punkexe portion of the G-150 follow-on "sweep other flat multi-form
definitions for selection-soundness" (goals/archive/G-150-cmdhelp-form-narrowing.md);
that follow-on stays open - the sweep is broader than these two definitions.
- The G-144 follow-on (punkexe moduledoc @form -synopsis override set drops once
auto-synopsis serves - goals/archive/G-144-punkargs-synopsis-name-fallback.md,
disposition flipped to this goal) is decided in this work: keep the <punkexe>
placeholder overrides or adopt @cmd -name auto lines - recorded either way.
- Related: G-089 (proposed) - script's lib:name resolution text is consumed scope.
- Related: G-055 (proposed) - the real-vs-model probe method borrowed here.
- Related: G-072 (proposed) - deliberate non-dependency: negation NOT required.
- Related: G-170 (proposed) - consumer: its dry-run arm requires this goal's
parse-trueness.
- Overlap survey 2026-08-05: goals_xref paths over the Scope - G-089 (named
above) is the only substantive live intersection on punkboot_core.tcl;
moduledoc-sibling matches (G-055 G-068 G-072 G-083 G-084 G-166 G-167) are
parser/spec mechanisms or other moduledocs, no availability interaction.
- Activation survey 2026-08-05 (goals_xref score G-168, activation-freshness
rule): Related: G-169 (proposed) - back-pointer added at activation (G-169
already points here): the definitions this goal makes selection-sound are
the same ones G-169 re-homes under app ownership; G-169's handover carries
whatever fencing shape this goal lands. Other new hits (G-069 dev-lint)
are path-coincidental (same moduledoc/test directories), no mechanism
interaction.
- 2026-08-05 pre-test findings (engine primitives probed on tclsh 9.0.3 and
pinned green on tclsh90+tcl87: forms.test fencing/fall-through group,
formviability_dangling_optional_option_conservative,
errsel_dangling_option_trailing_value_overflow, formcheck_GAP_punkexe_*):
- A -regexprefail rejection on an OPTIONAL value slot is fatal to that form's
candidacy - the word does NOT re-land on a later permissive slot (contrast
optional-CHOICE rejection, errsel_rejected_word_lands_later) - so per-slot
fencing fences whole forms (forms_fence_optional_slot_no_reland).
- Unknown options, dangling option words and option-satisfied-but-values-unmet
tails each fail only their form: auto-selection falls through to a sibling
as a SUCCESSFUL parse, and an option VALUE's -regexprefail participates in
candidacy too - the stock "-encoding recognised only before a non-dash word"
primitive is expressible (forms_fallthrough_* pins).
- LIMIT for the tclsh model: a complete '-encoding <name> <file>' line
wordwise-matches both a fenced scriptfile form and any dash-tolerant stdin
form; per-word constraints cannot express stock's "scriptfile wins when
complete" priority, so the no-silent-preference contract (G-041, achieved -
goals/archive/G-041-punkargs-form-matching.md) raises
multipleformmatches (forms_fenced_pair_residual_overlap). The tclsh
declaration must design around this class - form restructuring, an
-overlapallowed sanction (display-only; parse still raises), or the
dispatch-parse decision this goal already tables.
- The {-e}-alone viable-incomplete acceptance rides the re-probe of G-164
(achieved 2026-08-04 - goals/archive/G-164-viability-alternative-allocation.md),
which re-seats only words naming missing REQUIRED options: declare '-e' as a
required -type none flag plus a separate required script value (the
auto_exec::hash -r/-d shape), NOT as a value-taking option - a stolen word
naming a value-taking or OPTIONAL option keeps verdict invalid
(formviability_reprobe_value_taking_option_conservative and the new
formviability_dangling_optional_option_conservative twin).
- Before-state pinned as GAP: both punkexe multi-form definitions carry
unsanctioned structural formcheck findings and every primary launch line
double-matches ({-e X} / {file args} / {file} / {-encoding enc file});
empty input selects file/stdin uniquely (formcheck_GAP_punkexe_script_forms_overlap,
formcheck_GAP_punkexe_tclsh_forms_overlap,
formcheck_GAP_punkexe_primary_inputs_double_match - flipped deliberately
by this goal per its Acceptance).
## Progress
Achieved 2026-08-05 in one session (user-directed activation and implementation
same day; punk::args::moduledoc::punkexe 0.7.0). The declarations follow the
pre-test findings exactly - no engine change was needed.
Mechanism landed ((script)::punkexe::script):
- file form: scriptfile gains -regexprefail {^-e$} with -regexprefailmsg naming
the ./-e reachability ("reserved for the -e one-liner form; a file literally
named -e is reachable as ./-e") - word-1 '-e' is the ONLY fenced word; every
other dash-led word remains a file path, matching app-punkscript's word-1
test.
- oneliner form: the '-e' word is now a real declared element - a required
-type none flag (@opts -e -optional 0, the auto_exec::hash -r/-d shape)
ahead of the existing required script value. A bare {-e} therefore reports
noformmatch with the oneliner form verdicting viable-incomplete (the G-164
re-probe re-seats the reservation-stolen '-e' as the flag it names and finds
pure exhaustion) and the file form invalid - the app's "-e requires a script
argument" reality.
Mechanism landed ((script)::punkexe::tclsh):
- scriptfile form: scriptfile gains -regexprefail {^-} (stock tclMain.c: a
dash-led word in script-file position means NO script) with a stock-parity
message.
- stdin form: the first word is now a declared fenced element 'firstarg'
(-regexprefail {^[^-]} - a NON-dash first word IS a script file), remaining
args unchanged; its -help states it is not an option and stays in ::argv.
- The complete '-encoding <name> <scriptfile>' shape is the recorded LIMIT:
it word-shape-matches both forms (a dash-led encoding NAME included - the
engine consumes a dash-led option value, matching stock's unconstrained
argv[2]) and stock's arity-priority rule (scriptfile wins when the triple is
complete) is not expressible per-word - the pair is declared
@form -overlapallowed {scriptfile} on the stdin form (formcheck sanction)
and parse raises multipleformmatches naming both forms per the G-041
no-silent-preference contract. Dispatch never parses these ids, so the
ambiguity surfaces only in declaration-driven consumers (help dry-runs,
completion), where the two-form diagnosis is the honest answer.
Real-vs-model probe matrix (G-055 method; real side = bin/punk91 dispatch +
app-punkscript probes 2026-08-05, model side = parse/parse_status against the
0.7.0 definitions on tclsh90 - punkexemodel.test pins the model column):
script words | real behaviour | model selection
---------------------|-----------------------------------------------|----------------
(empty) | piped-stdin script mode | file
-e 'puts one' | oneliner runs, exit 0 | oneliner
-e 'expr 1+1' | oneliner, result echo '2' | oneliner
-e code x -y | oneliner, argv0=-e argv={x -y} | oneliner
-e | usage error "-e requires a script argument" 1 | noformmatch, oneliner viable-incomplete
nosuchfile.tcl | file class: not-found, exit 1 | file
-x | file class: not-found naming '-x', exit 1 | file
hi.tcl a b | file runs, argv={a b} | file
./-e | file named -e runs | file
-e foo.tcl | oneliner evaluates the TEXT 'foo.tcl' | oneliner
tclsh words | real behaviour | model selection
---------------------|-----------------------------------------------|----------------
(empty) | stdin (repl/piped) | stdin
hi.tcl a b | scriptfile runs, argv={a b} | scriptfile
-foo bar | stdin, ARGV=-foo bar | stdin
-encoding | stdin, ARGV=-encoding | stdin (scriptfile invalid)
-encoding utf-8 | stdin, ARGV=-encoding utf-8 | stdin (scriptfile incomplete)
-encoding utf-8 hi.tcl a | scriptfile with encoding, argv={a} | multipleformmatches (the LIMIT, sanctioned)
-encoding utf-8 -bar | stdin, ARGV=all three words | stdin
-encoding -foo hi.tcl| scriptfile attempt (unknown encoding error) | multipleformmatches (same LIMIT class)
Divergence summary: model matches real classification on every line except
the two complete-'-encoding'-shape rows, where the model deliberately raises
the sanctioned multipleformmatches instead of silently preferring scriptfile
(rationale above; the G-041 contract).
Decision - dispatch parse-gating: NOT adopted (punkboot_core.tcl untouched;
no latency delta applicable). Rationale: (a) script/tclsh are declared
PASSTHROUGH surfaces (G-032 decision) - their arguments belong to the launched
script/app, and a dispatch parse would add punk::args resolve+parse cost to
every script/tclsh launch on the boot path; (b) stock parity: the complete
-encoding line is stock-valid and dispatch-classified scriptfile, but the
model deliberately raises multipleformmatches on it - a parse gate would turn
a working stock line into a launch error, or need a priority override that
reintroduces the silent preference G-041 removed; (c) app-punkscript's error
surfaces are already honest and pinned (usage errors exit 1, no launch
chatter - G-077, launcherhelp.test); (d) the consumers that want the parse
(G-170 help-depth dry-run, G-044 completion) get parse-trueness without
gating.
Decision - G-144 follow-on (@form -synopsis overrides): KEPT. Neither the raw
(script) id nor @cmd -name ('punkexe tclsh') is an invocable name; the
<punkexe> placeholder matches the file's prose convention ("'<punkexe>' below
stands for any punk kit executable"), and the stdin form's override keeps the
user-facing '?arg ...?' line over the model's firstarg/arg fencing split. The
G-144 archived follow-on line's disposition flipped accordingly (make.tcl's
own override retirement had already landed in the 0.41.0 arc).
Verification evidence:
- New suite src/tests/modules/punk/args/testsuites/args/punkexemodel.test
(6 tests): both selection matrices, the {-e} viable-incomplete verdict
(ok 0 / status incomplete / form oneliner / formstatus {oneliner incomplete
file invalid}), the ./-e fence message, the -encoding fall-through statuses
(scriptfile invalid vs incomplete, stdin selected), and the LIMIT pins
(multipleformmatches naming {scriptfile stdin} for both complete shapes).
- formcheck.test GAP flips: formcheck_punkexe_script_forms_discriminated
(zero findings), formcheck_punkexe_tclsh_forms_sanctioned (unsanctioned
empty + the stdin form's -overlapallowed {scriptfile} pinned via get_spec),
formcheck_punkexe_primary_inputs_selection_sound (dispatch-true forms for
every primary line; the sanctioned LIMIT raise named).
- Full modules/punk/args subtree 337 passed / 3 pre-existing skips / 0 failed
on BOTH native tclsh90 (Tcl 9.0.3) and tclsh87.
- src/tests/shell/testsuites/punkexe/launcherhelp.test 24/24 unchanged (the
acceptance gate; its 'help script'/'help tclsh' pins glob only @cmd -name
strings and row additions do not disturb them - verified for post-bake
robustness too).
- Minted modules/punk/args/moduledoc/punkexe-0.7.0.tm via make.tcl modules;
kits/bootsupport carry 0.6.1 until the next promotion/bake cycle (the
moduledoc rides the established channels; no synced-copy obligations - the
punkboot_core.tcl copies were not touched).
- G-151 composition smoke: punk::args::parse_report over an accepted
'{-e {puts hi} x -y}' line renders the landing rows (-e received, script
received, arg received x2) - the G-170 dry-run arm's ingredients compose.
## Follow-ons
Follow-on: stock's arity-priority for the complete '-encoding <name> <scriptfile>' shape becomes expressible if punk::args grows a form-priority or arity-conditional fencing mechanism - the -overlapallowed sanction and the punkexemodel/formcheck LIMIT pins flip deliberately then => open
(The broader flat-multi-form selection-soundness sweep stays recorded as the
open follow-on in goals/archive/G-150-cmdhelp-form-narrowing.md - the punkexe
portion is enacted by this goal, per the Notes; no duplicate line here.)

56
src/modules/punk/args/moduledoc/punkexe-999999.0a1.0.tm

@ -278,6 +278,19 @@ tcl::namespace::eval punk::args::moduledoc::punkexe {
interactive form (console stdin, no script) fails fast
with a usage error instead of blocking in a console read."
#G-168 selection-sound forms: scriptfile is fenced against any leading
#'-' word (stock tclMain.c parity - such a word means NO script) and
#the stdin form's FIRST word is fenced against non-dash words (a
#non-dash first word IS a script file) - so form auto-selection
#matches stock classification for every line except the complete
#'-encoding <name> <scriptfile>' shape, which word-shape-matches both
#forms: stock's arity-priority rule (scriptfile wins when the triple
#is complete) is not expressible per-word, so the pair is declared
#@form -overlapallowed and a parse of that shape raises
#multipleformmatches naming both forms (G-041 no-silent-preference;
#the recorded G-168 LIMIT - dispatch itself never parses this
#definition, so the ambiguity surfaces only in declaration-driven
#consumers such as help dry-runs).
@form -form {scriptfile} -synopsis "<punkexe> tclsh ?-encoding name? scriptfile ?arg ...?"
@leaders -min 0 -max 0
@opts
@ -288,16 +301,32 @@ tcl::namespace::eval punk::args::moduledoc::punkexe {
-encoding form falls through to the no-script form (stock
behaviour)."
@values -min 1 -max -1
scriptfile -type string -optional 0 -help -&
"Script file to source and exit. ::argv0 and 'info script' are
scriptfile -type string -optional 0 -&
-regexprefail {^-} -&
-regexprefailmsg -&
"a tclsh script file argument may not begin with '-' (stock parity: a line whose script-file position holds a dash-led word is the no-script form - all arguments stay in ::argv)" -&
-help -&
"Script file to source and exit. May not begin with '-' (stock
classification - a dash-led word in this position selects the
no-script form instead). ::argv0 and 'info script' are
the (normalized) script path; remaining args are ::argv. The
script may set ::tclsh(dorepl) 1 (piperepl runtimes) to enter
the interactive repl after it completes."
arg -type any -optional 1 -multiple 1 -help -&
"Arguments passed to the script in ::argv."
@form -form {stdin} -synopsis "<punkexe> tclsh ?arg ...?"
@form -form {stdin} -synopsis "<punkexe> tclsh ?arg ...?" -overlapallowed {scriptfile}
@values -min 0 -max -1
firstarg -type string -optional 1 -&
-regexprefail {^[^-]} -&
-regexprefailmsg -&
"a non-dash first word after 'tclsh' is a script file (the scriptfile form applies) - the no-script form takes only a leading '-' word here" -&
-help -&
"First argument. In this no-script form it must begin with '-'
(stock classification: a non-dash first word is a script file
and selects the scriptfile form). It is not an option - it
stays in ::argv untouched, exactly like the remaining
arguments."
arg -type any -optional 1 -multiple 1 -help -&
"With no script file all arguments (including any leading '-'
arguments) stay in ::argv; ::argv0 is the executable path.
@ -353,12 +382,29 @@ tcl::namespace::eval punk::args::moduledoc::punkexe {
use '<punkexe> help script' for this usage."
@form -form {file} -synopsis "<punkexe> script ?scriptfile|lib:name? ?arg ...?"
@values -min 0 -max -1
scriptfile -type string -optional 1 -help -&
scriptfile -type string -optional 1 -&
-regexprefail {^-e$} -&
-regexprefailmsg -&
"the script subcommand's scriptfile may not be exactly '-e' (reserved for the -e one-liner form; a file literally named -e is reachable as ./-e)" -&
-help -&
"Script file path, or lib:name for scriptlib resolution.
Omitted: the script is read from piped stdin."
Omitted: the script is read from piped stdin.
Any first word other than exactly '-e' is a file path here -
including other dash-led words ('-x' names a file, not an
option; G-168 selection-soundness: the fence on exactly '-e'
makes form auto-selection agree with dispatch)."
arg -type any -optional 1 -multiple 1 -help -&
"Arguments passed to the script in ::argv."
@form -form {oneliner} -synopsis "<punkexe> script -e <script> ?arg ...?"
@opts
-e -type none -optional 0 -help -&
"The one-liner selector (G-077): required, and only meaningful
as the first word after 'script' - a later '-e' is an
ordinary script/file argument (the file form applies). '-e'
with no following script argument is a usage error - never an
interactive fall-through. (G-168: declared as a required solo
flag so a bare '-e' verdicts the form viable-incomplete -
matching the app's 'requires a script argument' reality.)"
@values -min 1 -max -1
script -type string -optional 0 -help -&
"Tcl code to evaluate as a one-liner (G-077): errors print

3
src/modules/punk/args/moduledoc/punkexe-buildversion.txt

@ -1,6 +1,7 @@
0.6.1
0.7.0
#First line must be a semantic version number
#all other lines are ignored.
#0.7.0 - G-168 selection-sound launch definitions: the two multi-form definitions become parse-discriminable so form auto-selection agrees with actual dispatch/app behaviour (previously display-honest but parse-dishonest - every primary launch line double-matched). (script)::punkexe::script: the file form fences scriptfile with -regexprefail {^-e$} (+ -regexprefailmsg naming ./-e reachability - word-1 '-e' is reserved by app-punkscript behaviour, any OTHER dash word is a file); the oneliner form declares the '-e' word as a real element: a required -type none flag plus the existing required script value (the auto_exec::hash shape) so a bare {-e} reports noformmatch with the oneliner form verdicting viable-incomplete via the G-164 re-probe (the app's '-e requires a script argument' reality). (script)::punkexe::tclsh: scriptfile gains -regexprefail {^-} (stock tclMain.c: a dash-led word in script-file position means NO script) and the stdin form's first word is declared as a fenced 'firstarg' (-regexprefail {^[^-]} - a non-dash first word IS a script file) with the remaining args unchanged; selection now matches stock classification for every line except the complete '-encoding <name> <scriptfile>' shape (word-shape-matches both forms; stock's arity-priority is not expressible per-word) - that pair is declared @form -overlapallowed {scriptfile} on the stdin form (formcheck sanction; parse still raises multipleformmatches naming both forms per the G-041 no-silent-preference contract - the recorded G-168 LIMIT, surfacing only in declaration-driven consumers since dispatch never parses these ids). @form -synopsis overrides kept (G-144 follow-on decision): the <punkexe> placeholder matches the file's prose convention and neither the raw id nor @cmd -name ('punkexe tclsh') is an invocable name; the stdin form's override also keeps the user-facing '?arg ...?' line over the model's firstarg/arg split. Dispatch parse-gating deliberately NOT adopted (decision recorded in goals/archive/G-168-*): script/tclsh stay declared passthrough surfaces. Verified by a real-vs-model probe matrix (G-055 method) against bin/punk91 dispatch + app-punkscript (recorded in the goal file); pinned in args testsuites (formcheck.test GAP flips + new punkexemodel.test).
#0.6.1 - G-149-adjacent interim (user direction 2026-08-05): the two multi-form definitions ((script)::punkexe::script, ::tclsh) declare @cmd -formhint "" - the usage table's per-form hint labels are suppressed (renders under punk::args 0.17.0+; older snapshots ignore the key and show the ' i -form N ...' default). Rationale: the repl-oriented default is not typeable at the CLI where these tables render (and the (script) ids live in the boot interp, invisible to the repl's 'i'), while a make.tcl-style actionable replacement does not exist - launcher help is deliberately subject-only (trailing words ignored, the prepend-help idiom; G-032 single-mechanism revision), so there is no per-form destination a hint could name, and a ' <punkexe> help <sub>' pointer would be circular on the help path and redundant on the dispatch-error path (that table already shows all forms). Interim: if launcher help gains form-name narrowing (candidate direction discussed 2026-08-05 - 'help script oneliner' via usage -form, the G-150 cmdhelp precedent), replace the suppression with a real ' <punkexe> help <sub> %formname%' template.
#0.6.0 - single-mechanism revision (2026-08-05, user direction): all -help flag documentation withdrawn - 'help ?subcommand? ?arg ...?' is the sole help entry (trailing words accepted/ignored - the prepend-help idiom); (script)::punkexe::help gains the arg row + max -1; tclsh parity stated exception-free; per-subcommand -help paragraphs replaced with 'help <sub>' pointers; buildinfo refuses help flags like any argument
#0.5.0 - G-077 -e one-liner forms documented: (script)::punkexe::script gains the oneliner @form + -help paragraph; top-level (script)::punkexe documents the '-e' first-argument reclassification and gains its oneliner @form; (script)::punkexe::tclsh boundary text now points at the live forms

2
src/tests/modules/AGENTS.md

@ -43,7 +43,7 @@ Unit tests for editable source modules under `src/modules/`, `src/modules_tcl8/`
- `commandstack/` — commandstack (cooperative command renaming) tests (`testsuites/commandstack/commandstack.test`, 2026-08-03 - characterisation suite + the G-160 hygiene-pass contract at commandstack 0.6.0 + the 0.7.0 convenience removal forms + the 0.7.1 reload-contract state guards (G-160 follow-ons, 2026-08-04); usage-driven from punk::packagepreference/packagetrace/packagesuppress/punk-auto_execok/punk::nav::fs-cd): record shape as a contract (token first/renamer second dict key order for the lsearch -index 1/-index 3 convention, trailing `did_rename` 0|1, `{implementation {} did_rename 0}` no-rename signal), COMMANDSTACKNEXT/COMMANDSTACKNEXT_ORIGINAL delegation + the `commandstack::next` helper (caller-context parity with the manual uplevel convention pinned), unique+monotonic per-(renamer,command) tokenids (same-renamer re-renames chain and are removable by exact token, third rename succeeds), multi-renamer stacking with removal in any order (bottom-removal re-linking), builtin renames (next_implementor `original`), remove_rename's three argument forms + unknown-renamer errors, the 0.7.0 convenience removal forms (pop_rename - command form pops topmost-for-renamer and returns the removed record, bare form searches live stacks with a multi-command ambiguity error; remove_renamer - all of a renamer's entries across live stacks with correct re-linking, Rename_stack-parked stacks skipped, removed records returned keyed by command; restore_original - whole-stack unwind to the original returning the record count, deliberately registering stack-evidenced renamers so it survives a known_renamers reset while the renamer-explicit forms keep the gate; all silent with debug off), the token->implementation map get_next_command resolves through (map/stack consistency pinned across rename/remove; parked stacks keep dispatching), channel discipline (silent full cycle with debug off; warnings only under debug), debug argument validation, -renamer misplacement errors, get_stack raw-key-first retrieval of Rename_stack-parked records + Rename_stack 1/0 returns, Delete_stack live-record guard (errors; empty/missing return 1), get_IMPLEMENTOR classification incl builtin-where-cmdtype-exists (dynamic expectation - undetermined on 8.6), lib::split_body round-trip, lib::splitx, show_stack fallback render, the reload contract (a module re-source preserves ALL state - stacks/token counters/token map/known_renamers/debug each info-exists guarded; delegation and exact-token removal keep working after reload), the help overview, and lazy punk::args registration of the PUNKARGS docs. Behavioural tests run in fresh child interps per test (module sourced by path relative to the test file; a ::puts shim captures module output for silence/warning assertions and keeps runner output clean); descriptions are single-line per the tcltestrun banner-parsing style guidance in src/tests/AGENTS.md (a hard contract until G-161 made the parser multi-line tolerant). Green on tclsh90 (9.0.3) and punk86 (8.6)
- `punkcheck/` — punkcheck module tests (install, summarize_install_resultdict, installtrack)
- `punk/ansi/` — punk::ansi tests (`testsuites/ansi/`): ansistrip/ansimerge, plus characterization of the ANSI-at-position mechanisms (`ansistring.test`: INDEX/INDEXCODE/INDEXCHAR/RANGE/INSERT grapheme indexing with SGR-prefix merging, INDEXCOLUMNS/COLUMNINDEX double-wide column mapping, trim/VIEW; extended 2026-08-05 by the G-151 pre-modification coverage survey - VIEW -lf 0/1/2 single-line-ization modes + always-on NUL + silent unknown-option tolerance (load-bearing for overtype's '-nul 1' sites) + C1/zero-width visuals, RANGE end-relative/clamping plus the merged-code-stack re-emission and trailing-code-drop semantics a truncate primitive must respect, COUNT-vs-length combining-accent divergence, NEW object basics, and the KNOWN-DEFICIENCY pin that VIEWCODES/VIEWSTYLE raise invalid-command in a plain punk::ansi interp (bare 'a+'/'a' interactive-alias dependency; pinned in a fresh child interp); plus the TRUNCATE primitive pins landed with G-151 (punk::ansi 0.2.0) - fits-unchanged byte identity incl styled fixtures, grapheme-exact capping with marker budget participation and marker-alone truncation, SGR-reset-before-marker on styled prefixes, CJK/combining-cluster grapheme safety, and strict option errors (deliberately unlike VIEW's pinned silent tolerance)), code splitting invariants (`ta.test`: detect/detectcode distinction, split_codes/split_codes_single/split_at_codes shapes and round-trip) and single-code/effective-state semantics (`codetype.test`: is_sgr_reset/has_sgr_leadingreset, has_any/all_effective, sgr_merge, sequence_type classify), grepstr characterization (`grepstr.test`: return modes incl summarydict (linemap pinned as always-present - the -help says -n-only, reconciliation deferred to the planned hygiene pass), exact highlight SGR wrapping, -n line numbering, invert + empty-highlight strip, -C context/breaks, capture groups, and the tab deficiency: warns once per call on stderr, single-pass tab line survives - the multi-pass mangling is pinned at consumer level in punk/ns corp.test), and untabify characterization (`untabify.test`: -stops int/list/terminal, -with spaces/unicode/custom-pair, multiline, errors, plus the EXPERIMENTAL -plastic elastic-tabstop mode deliberately pinned-as-interim and retained for possible repl editbuf use). Console queries (get_tabstops/get_size + punk::console::tabwidth) are mocked per the overtype renderline.test pattern - they emit live terminal queries that block/error headless. ANSI codes in these tests are literal escape strings so results are colour-state independent
- `punk/args/` — punk::args tests (`testsuites/args/`): parsing, choices/choicegroups, forms (incl the 2026-08-05 candidacy fencing/fall-through primitive pins ahead of G-168: -regexprefail on optional value slots is form-fatal with no re-landing, unknown-option/dangling-option/option-value-fence failures fall through to sibling forms as successful parses, and the documented per-word limit - a complete option+value+file line double-matches a fenced scriptfile form and a dash-tolerant stdin form), registered-namespace lazy definition loading (`docpackages.test`, G-169 pre-work: inert registration/scan-vs-load split, id_exists never triggers loading, real_id/usage lazy resolution incl tag-prefixed script-level id families, duplicate-definer last-loaded-wins characterization), the G-151 landing report (`parsereport.test`, punk::args 0.18.0 parse_report: the canonical flag-like-word-consumed-as-VALUE attribution row, parsed-result vs words+withid entry parity, machine dict shape with declaration-section row order and absent-optional row omission, received xN multiplicity for solos/-multiple opts, type-aware always-marked elision at the default width plus the caller > @cmd -reportvaluewidth > built-in width cascade and never-elided dict returns, VIEW-style single-line-ization of control-bearing values, aliased-optionset storage-key row bridging, bordered-table/tableobject renders, words-form failure errorcode parity with parse, and the registered two-form definition's own render), rendering/indentation characterization, synopsis display characterization (`synopsis.test`: basic italic argname/`<type>` styling, longopt `--x=` alias forms, literal/literalprefix/stringstartswith/stringendswith type-alternates rendering unitalicised, option alternate parenthesization, multi-element clause display incl `?type?` members and argname tail-word hints, `-typesynopsis` value-element lists and option passthrough incl documenter ANSI, and the small-restricted-choice-set literal rule: 1-3 restricted choices render as unitalicised `|`-joined literals in leader/option/value positions with choicegroups counted, >3 or `-choicerestricted 0` falling back to italics, `-typesynopsis` taking precedence), usage-marking characterization (`usagemarking.test`: -parsedargs/-badarg/-parsestatus/-scheme marking primitives plus goodchoice highlighting of selected/default-in-effect choice words, asserted by SGR-parameter subset against the live colour arrays; the G-049 nocolour/colour-leak GAP pins flipped 2026-07-10 to scheme-statelessness assertions), the G-049 parse-status structure (`parsestatus.test`: punk::args::parse_status overall/per-argument statuses, badarg for type/allocation failures, -caller attribution, errorcode -argspecs stripping), -parsekey characterization (`parsekey.test`: result/received/solos/multis keying, shared-key required satisfaction and defaults, mash-path and prefix-abbreviation keying, plus GAP pins for last-defined-member default precedence, cross-member -multiple value loss, parsekey/optname collision conflation, and values/leaders parsekey breakage - desired-behaviour pins disabled behind punkargsKnownBug in `testsuites/dev/parsekey-knownbugs.test`), and tclcore doc/interpreter behavioural parity (`tclcoreparity.test`, G-054, gated on have_tclcoredocs: 'string is' class choices equal the live-harvested set, per-class docids exist, error-vs-ok agreement across the probe matrix, version-note labels conditional on class presence - expectations derived from the running interpreter, green on 8.6/8.7/9.0; under 8.6 run the file directly via a plain tclkit + tcltest driver since runtests' harness needs newer infrastructure)
- `punk/args/` — punk::args tests (`testsuites/args/`): parsing, choices/choicegroups, forms (incl the 2026-08-05 candidacy fencing/fall-through primitive pins ahead of G-168: -regexprefail on optional value slots is form-fatal with no re-landing, unknown-option/dangling-option/option-value-fence failures fall through to sibling forms as successful parses, and the documented per-word limit - a complete option+value+file line double-matches a fenced scriptfile form and a dash-tolerant stdin form), registered-namespace lazy definition loading (`docpackages.test`, G-169 pre-work: inert registration/scan-vs-load split, id_exists never triggers loading, real_id/usage lazy resolution incl tag-prefixed script-level id families, duplicate-definer last-loaded-wins characterization), the G-168 launch-definition model parity (`punkexemodel.test`, punkexe moduledoc 0.7.0: script/tclsh selection matrices against the real (script)::punkexe ids with the real-side dispatch/app oracle recorded in goals/archive/G-168, the bare-'-e' viable-incomplete verdict, the ./-e fence message, -encoding fall-through statuses, and the sanctioned complete-'-encoding' multipleformmatches LIMIT pins; the formcheck.test punkexe GAPs flipped to discriminated/sanctioned/selection-sound pins in the same arc), the G-151 landing report (`parsereport.test`, punk::args 0.18.0 parse_report: the canonical flag-like-word-consumed-as-VALUE attribution row, parsed-result vs words+withid entry parity, machine dict shape with declaration-section row order and absent-optional row omission, received xN multiplicity for solos/-multiple opts, type-aware always-marked elision at the default width plus the caller > @cmd -reportvaluewidth > built-in width cascade and never-elided dict returns, VIEW-style single-line-ization of control-bearing values, aliased-optionset storage-key row bridging, bordered-table/tableobject renders, words-form failure errorcode parity with parse, and the registered two-form definition's own render), rendering/indentation characterization, synopsis display characterization (`synopsis.test`: basic italic argname/`<type>` styling, longopt `--x=` alias forms, literal/literalprefix/stringstartswith/stringendswith type-alternates rendering unitalicised, option alternate parenthesization, multi-element clause display incl `?type?` members and argname tail-word hints, `-typesynopsis` value-element lists and option passthrough incl documenter ANSI, and the small-restricted-choice-set literal rule: 1-3 restricted choices render as unitalicised `|`-joined literals in leader/option/value positions with choicegroups counted, >3 or `-choicerestricted 0` falling back to italics, `-typesynopsis` taking precedence), usage-marking characterization (`usagemarking.test`: -parsedargs/-badarg/-parsestatus/-scheme marking primitives plus goodchoice highlighting of selected/default-in-effect choice words, asserted by SGR-parameter subset against the live colour arrays; the G-049 nocolour/colour-leak GAP pins flipped 2026-07-10 to scheme-statelessness assertions), the G-049 parse-status structure (`parsestatus.test`: punk::args::parse_status overall/per-argument statuses, badarg for type/allocation failures, -caller attribution, errorcode -argspecs stripping), -parsekey characterization (`parsekey.test`: result/received/solos/multis keying, shared-key required satisfaction and defaults, mash-path and prefix-abbreviation keying, plus GAP pins for last-defined-member default precedence, cross-member -multiple value loss, parsekey/optname collision conflation, and values/leaders parsekey breakage - desired-behaviour pins disabled behind punkargsKnownBug in `testsuites/dev/parsekey-knownbugs.test`), and tclcore doc/interpreter behavioural parity (`tclcoreparity.test`, G-054, gated on have_tclcoredocs: 'string is' class choices equal the live-harvested set, per-class docids exist, error-vs-ok agreement across the probe matrix, version-note labels conditional on class presence - expectations derived from the running interpreter, green on 8.6/8.7/9.0; under 8.6 run the file directly via a plain tclkit + tcltest driver since runtests' harness needs newer infrastructure)
- `punk/nav/ns/` — punk::nav::ns tests (`testsuites/nav/navns.test`): the n/ n// n/// navigation state machine (ns/ transitions absolute/relative/glob-no-nav, failed-nav state preservation, quad-colon normalization, v-form content selection, ensemble annotation) and the ::punk::nav::ns::ns_current variable contract the repl/codethread/subshell seeding all consume; display content is covered in punk/ns nslist.test
- `punk/repl/` — punk::repl tests (`testsuites/repl/`): opunk console backend integration (`consolebackends.test`) and repl current-namespace retention (`nscurrent.test`: real codethread via repl::init driven by synchronous runscript sends - inscope evaluation of ns_current, retention across submissions, n/-navigation retained, auto-create-with-notice for missing namespaces, the 2026-07-14 stray-namespace seeding fix pinned behaviourally plus a source-text guard on repl::start's inline template; the end-to-end piped subshell session is covered at shell level by shell/testsuites/punkexe/shellnavns.test - which found the first-subshell shared-code-interp asymmetry and the piped-inscope gap recorded there)
- `punk/ns/` — punk::ns tests (`testsuites/ns/`): cmdwhich/cmdinfo/cmd_traverse doc-lookup flow (`cmdflow.test`, G-040 parity), n/ display machinery characterization (`nslist.test`: tier A get_ns_dicts classification buckets as the machine contract for display reworks - incl package tail/prefix derivation, alias edge cases, usageinfo scan-dependence; tier B per-element layout-agnostic marking - underline/underdouble/underdotted namespace package styles, command type tag colours, exported/imported markers, the punkargs doc icon; tier C REWORK-flagged pins of the current hardcoded 2-col/4-col layout and nspath subtables, to flip deliberately with the planned punk-tables/width-responsive rework; plus the flipped nslist_types_default pin - bare nslist without -types displays all member types since punk::ns 0.7.1 fixed the braced-literal -types default), corp proc-retrieval and syntax/untabify interplay (`corp.test`: name edge cases, -ranges/-n line handling, basic-highlight ansistrip equivalence, -untabify spaces/unicode tab-free output, the KNOWN-DEFICIENCY pin for default -untabify none on tabbed bodies - grepstr warns per pass and brace overlays mangle tabbed lines, deterministic under mocked console tabstops - and a ::tcl::CopyDirectory -untabify spaces smoke test; precursor coverage for the planned punk::ns hygiene pass), cmdtrace characterization (`cmdtrace.test`: -pause 0 non-interactive runs, linedict line-mark keys for flat and 2-word-form nested switches as correct-mark guards, and GAP pins for the upstream nested-switch mismark - core.tcl-lang.org tktview 5d5b1052280c976ea3d4, arm bodies whose split-list index lands on a literal switch-command word report container-relative lines; mark tests gated on have_tclcoredocs because cmdtrace's arm-offset correction parses against the ::switch argdoc; plus the fixed-canary asserting punk::lib::check::has_tclbug_nestedswitch_tracelines still reports the bug - a live behavioural probe, so a fixed Tcl release fails the canary first and triggers the documented flip workflow), cmdhelp usage-rendering integration (`cmdhelp.test`: scheme selection, goodarg/badarg marking incl type/allocation failures, goodchoice highlighting of supplied/default choice words, alias path, cmdinfo result shape, queried-command failure attribution, and `-return dict` parse-status returns (G-049 - its GAP pins flipped 2026-07-10); remaining GAP pins for pseudo-command cmdtype + space-form docid prefixes (G-051, real `string is` pins behind the have_tclcoredocs constraint), TclOO undocumented-method fallback (G-052), and synopsis marking absence (G-050); plus the G-150 flag-led form-narrowing + selection-soundness pins against punk::auto_exec::hash - bare-parse selection contract (incl the dash-led-name noformmatch cost), no-word/unknown-flag/ambiguity whole-render fallbacks, and hash runtime-behaviour-unchanged), and name/path primitive characterization (`nsprimitives.test`: string pins for nsparts/nsprefix/nstail/nsjoin/nsjoinall incl weird colon-run (`:::`) splitting, the trailing-colon parse ambiguity (`::x:` + `y` joins to the same string as `::x` + `:y` and reparses leading-colon-greedy), and prefix/tail/join round-trip and its absolutizing exceptions (the original twin-divergence pins for nsparts1/nsprefix1/nsprefix_orig/nstail1/nstail_orig served as safe-deletion evidence and were removed with the twins in the punk::ns 0.7.0 hygiene pass - divergence record in this file's git history, commit 0c7168a1); plus nseval fq-requirement/create-on-eval/evaluator-proc caching, the native-vs-punk `p:::x` resolution divergence (native namespace eval reaches child `x`, nseval creates/reaches literal `:x`), nseval_ifexists no-create + error propagation on plain and genuinely weird namespaces, nsexists/nschildren/nstree_raw weird-ns and relative-resolution pins, globmatchns `*`/`**`/`?` semantics (incl `*` matching a single inner colon - a formerly stale 'should be fixed' comment above nsglob_as_re was corrected in the 0.7.0 hygiene pass), and nspath_to_absolute/nspath_here_absolute caller-resolution pins; the nsjoinall error-message wart pin ('nsjoin:' prefix) flipped when punk::ns 0.7.1 fixed it)

67
src/tests/modules/punk/args/testsuites/args/formcheck.test

@ -194,64 +194,75 @@ namespace eval ::testspace {
#formcheck reports an unsanctioned structural overlap for each and every
#primary-use input double-matches. G-168 (selection-sound launch definitions)
#flips these deliberately when the forms become parse-discriminable.
test formcheck_GAP_punkexe_script_forms_overlap {the punkexe script definition's file/oneliner pair reports an unsanctioned structural overlap whose witness parses against both forms}\
#flipped 2026-08-05 (agent, G-168) from formcheck_GAP_punkexe_script_forms_overlap:
#the file form fences scriptfile against exactly '-e' (-regexprefail {^-e$}) and
#the oneliner form declares '-e' as a required solo flag - no witness arglist
#parses against both forms any more
test formcheck_punkexe_script_forms_discriminated {the punkexe script definition's file/oneliner pair reports no findings - the forms are parse-discriminated (G-168)}\
-constraints have_punkexedocs\
-setup $common -body {
set r [punk::args::formcheck (script)::punkexe::script]
lappend result [dict size [dict get $r findings]]
lappend result [dict get $r unsanctioned]
set finding [dict get $r findings {file oneliner}]
lappend result [dict get $finding class] [dict get $finding sanctioned]
set w [dict get $finding witness]
lappend result [dict get [punk::args::parse_status $w -form file withid (script)::punkexe::script] ok]
lappend result [dict get [punk::args::parse_status $w -form oneliner withid (script)::punkexe::script] ok]
}\
-cleanup {
}\
-result [list {{file oneliner}} structural 0 1 1]
-result [list 0 {}]
#added 2026-08-05 (agent, G-168)
test formcheck_GAP_punkexe_tclsh_forms_overlap {the punkexe tclsh definition's scriptfile/stdin pair reports an unsanctioned structural overlap whose witness parses against both forms}\
#flipped 2026-08-05 (agent, G-168) from formcheck_GAP_punkexe_tclsh_forms_overlap:
#scriptfile fenced against leading '-' words, stdin's first word fenced against
#non-dash words - the positional-chain witness derivation finds no confirmed
#pair (the residual overlap needs the -encoding OPTION, outside chain
#enumeration - formcheck's documented miss direction). The pair is additionally
#sanctioned @form -overlapallowed {scriptfile} on the stdin form for the
#complete '-encoding <name> <scriptfile>' shape (the G-168 LIMIT: parse still
#raises multipleformmatches, pinned below), so a future improved witness
#derivation reports it sanctioned - unsanctioned stays empty either way (the
#G-168 acceptance gate)
test formcheck_punkexe_tclsh_forms_sanctioned {the punkexe tclsh definition reports no unsanctioned findings and the stdin form carries the -overlapallowed sanction for the residual -encoding overlap (G-168)}\
-constraints have_punkexedocs\
-setup $common -body {
set r [punk::args::formcheck (script)::punkexe::tclsh]
lappend result [dict get $r unsanctioned]
set finding [dict get $r findings {scriptfile stdin}]
lappend result [dict get $finding class] [dict get $finding sanctioned]
set w [dict get $finding witness]
lappend result [dict get [punk::args::parse_status $w -form scriptfile withid (script)::punkexe::tclsh] ok]
lappend result [dict get [punk::args::parse_status $w -form stdin withid (script)::punkexe::tclsh] ok]
lappend result [dict get [punk::args::get_spec (script)::punkexe::tclsh] FORMS stdin -overlapallowed]
}\
-cleanup {
}\
-result [list {{scriptfile stdin}} structural 0 1 1]
-result [list {} scriptfile]
#added 2026-08-05 (agent, G-168) - the parse reality behind the findings: the
#primary launch lines double-match today (the definitions are consulted for
#display only, so the defect is latent until declaration-driven consumers -
#help depth, dry-run, completion - parse against them); empty input selects
#the piped-stdin readings uniquely
test formcheck_GAP_punkexe_primary_inputs_double_match {every primary-use launch line double-matches the current punkexe script/tclsh forms (multipleformmatches); empty input selects the stdin readings}\
#flipped 2026-08-05 (agent, G-168) from formcheck_GAP_punkexe_primary_inputs_double_match:
#the primary launch lines now single-match their dispatch-true forms (the
#before-state had every one of them raising multipleformmatches). The one
#deliberate residual is the complete '-encoding <name> <scriptfile>' shape:
#it word-shape-matches both tclsh forms, stock's arity-priority rule is not
#expressible per-word, and the G-041 no-silent-preference contract raises
#multipleformmatches naming both forms - sanctioned via -overlapallowed
#(pinned above); dispatch itself never parses these ids
test formcheck_punkexe_primary_inputs_selection_sound {every primary-use launch line selects its dispatch-true form; the complete -encoding shape stays a deliberate sanctioned multipleformmatches (G-168)}\
-constraints have_punkexedocs\
-setup $common -body {
foreach {id words} {
(script)::punkexe::script {-e {puts hi}}
(script)::punkexe::script {foo.tcl bar}
(script)::punkexe::tclsh {foo.tcl}
(script)::punkexe::tclsh {-encoding utf-8 foo.tcl}
(script)::punkexe::tclsh {-foo bar}
} {
if {[catch {punk::args::parse $words -errorstyle minimal withid $id} errmsg erroropts]} {
set classinfo [lindex [dict get $erroropts -errorcode] 2]
lappend result [lindex $classinfo 0]
} else {
lappend result UNEXPECTED-parsed
}
lappend result [dict get [punk::args::parse $words withid $id] form]
}
if {[catch {punk::args::parse {-encoding utf-8 foo.tcl} -errorstyle minimal withid (script)::punkexe::tclsh} errmsg erroropts]} {
set classinfo [lindex [dict get $erroropts -errorcode] 2]
lappend result [lindex $classinfo 0]
lappend result [lsort [dict get [lrange $classinfo 1 end] forms]]
} else {
lappend result UNEXPECTED-parsed
}
lappend result [dict get [punk::args::parse {} withid (script)::punkexe::script] form]
lappend result [dict get [punk::args::parse {} withid (script)::punkexe::tclsh] form]
}\
-cleanup {
}\
-result [list multipleformmatches multipleformmatches multipleformmatches multipleformmatches file stdin]
-result [list oneliner file scriptfile stdin multipleformmatches {scriptfile stdin} file stdin]
#fixture cleanup
catch {punk::args::undefine ::testspace::fc_afterish 1}

165
src/tests/modules/punk/args/testsuites/args/punkexemodel.test

@ -0,0 +1,165 @@
package require tcltest
package require punk::args
package require punk::lib
#G-168 model parity: the (script)::punkexe::script and ::tclsh multi-form launch
#definitions are selection-sound - form auto-selection (parse) and parse_status
#verdicts agree with actual dispatch/app behaviour. The real-side oracle is the
#probe matrix recorded in goals/archive/G-168-selection-sound-launch-definitions.md
#(bin/punk91 dispatch + app-punkscript probes, 2026-08-05):
# script: word-1 exactly '-e' selects the one-liner ('-e' alone is the usage
# error "-e requires a script argument", exit 1); ANY other first word -
# dash-led included - is a file path ('script -x' fails file-not-found naming
# '-x'; a file literally named -e runs as './-e'); no words = the piped-stdin
# script form.
# tclsh (stock tclMain.c triple-check in punkboot_core.tcl): '-encoding name
# file' recognised only when the THIRD word does not begin with '-'; otherwise
# a non-dash first word is the script file; otherwise (leading dash, incomplete
# -encoding tails included) NO script - all words stay in ::argv, input from
# stdin.
#Model mechanisms (punkexe moduledoc 0.7.0): file form fences scriptfile with
#-regexprefail {^-e$}; oneliner declares '-e' as a required -type none flag
#(so a bare {-e} verdicts viable-incomplete via the G-164 re-probe); tclsh
#scriptfile fenced {^-}; stdin's first word fenced {^[^-]}; the complete
#'-encoding <name> <scriptfile>' shape is the recorded LIMIT - it matches both
#tclsh forms and raises multipleformmatches (G-041 no-silent-preference),
#sanctioned @form -overlapallowed (formcheck gate pinned in formcheck.test).
namespace eval ::testspace {
namespace import ::tcltest::*
variable common {
set result ""
}
testConstraint have_punkexedocs [expr {![catch {package require punk::args::moduledoc::punkexe}]}]
if {[testConstraint have_punkexedocs]} {
#trigger the docpackages load of the (script)::punkexe id family
catch {punk::args::real_id (script)::punkexe::script}
}
#added 2026-08-05 (agent, G-168)
test punkexemodel_script_selection_matrix {script subcommand: '-e <code> ...' selects oneliner, any other first word (dash-led included) selects file, empty selects file (the stdin-script reading), '-e' alone raises noformmatch}\
-constraints have_punkexedocs\
-setup $common -body {
foreach words {
{}
{-e {puts hi}}
{-e {puts hi} a -b}
{foo.tcl bar}
{foo.tcl}
{-x}
{./-e}
{-e foo.tcl}
} {
lappend result [dict get [punk::args::parse $words withid (script)::punkexe::script] form]
}
if {[catch {punk::args::parse {-e} -errorstyle minimal withid (script)::punkexe::script} errmsg erroropts]} {
lappend result [lindex [lindex [dict get $erroropts -errorcode] 2] 0]
} else {
lappend result UNEXPECTED-parsed
}
}\
-cleanup {
}\
-result [list file oneliner oneliner file file file file oneliner noformmatch]
#added 2026-08-05 (agent, G-168) - the acceptance's '-e requires a script
#argument' reality: the oneliner form verdicts viable-incomplete (the G-164
#re-probe re-seats the reservation-stolen '-e' as the required solo flag it
#names and finds pure exhaustion); the file form is invalid (scriptfile
#fenced against exactly '-e')
test punkexemodel_script_e_alone_viable_incomplete {a bare '-e' reports noformmatch with the oneliner form viable-incomplete and the file form invalid}\
-constraints have_punkexedocs\
-setup $common -body {
set ps [punk::args::parse_status {-e} withid (script)::punkexe::script]
lappend result [dict get $ps ok] [dict get $ps status] [dict get $ps form]
lappend result [dict get $ps formstatus oneliner status]
lappend result [dict get $ps formstatus file status]
}\
-cleanup {
}\
-result [list 0 incomplete oneliner incomplete invalid]
#added 2026-08-05 (agent, G-168) - the file form's fence message names the
#./-e reachability (the Goal's 'message naming ./-e' clause)
test punkexemodel_script_fence_message_names_dote {forcing the file form on '-e' surfaces the -regexprefailmsg naming ./-e}\
-constraints have_punkexedocs\
-setup $common -body {
catch {punk::args::parse {-e} -errorstyle minimal -form file withid (script)::punkexe::script} m
lappend result [string match "*reachable as ./-e*" $m]
lappend result [string match "*one-liner form*" $m]
}\
-cleanup {
}\
-result [list 1 1]
#added 2026-08-05 (agent, G-168)
test punkexemodel_tclsh_selection_matrix {tclsh subcommand: a non-dash first word selects scriptfile (with or without a complete -encoding prefix pending the LIMIT), leading-dash words and incomplete -encoding tails select stdin, empty selects stdin}\
-constraints have_punkexedocs\
-setup $common -body {
foreach words {
{}
{foo.tcl a b}
{foo.tcl}
{-foo bar}
{-foo}
{-encoding}
{-encoding utf-8}
{-encoding utf-8 -bar}
} {
lappend result [dict get [punk::args::parse $words withid (script)::punkexe::tclsh] form]
}
set result
}\
-cleanup {
}\
-result [list stdin scriptfile scriptfile stdin stdin stdin stdin stdin]
#added 2026-08-05 (agent, G-168) - stock fall-through parity in the verdicts:
#a dangling '-encoding' (value missing mid-form) is invalid for scriptfile;
#a complete '-encoding utf-8' pair with the script file still missing is
#viable-incomplete; both lines PARSE as stdin (the fall-through)
test punkexemodel_tclsh_encoding_fallthrough_statuses {incomplete -encoding tails fall through to a successful stdin parse; the scriptfile form verdicts invalid (dangling value) vs incomplete (missing scriptfile)}\
-constraints have_punkexedocs\
-setup $common -body {
set ps [punk::args::parse_status {-encoding} withid (script)::punkexe::tclsh]
lappend result [dict get $ps ok] [dict get $ps form]
lappend result [dict get $ps formstatus scriptfile status]
set ps [punk::args::parse_status {-encoding utf-8} withid (script)::punkexe::tclsh]
lappend result [dict get $ps ok] [dict get $ps form]
lappend result [dict get $ps formstatus scriptfile status]
}\
-cleanup {
}\
-result [list 1 stdin invalid 1 stdin incomplete]
#added 2026-08-05 (agent, G-168) - the recorded LIMIT: complete
#'-encoding <name> <scriptfile>' shapes (a dash-led encoding NAME included -
#the engine consumes a dash-led option value, matching stock's unconstrained
#argv[2]) word-shape-match both forms; parse raises multipleformmatches
#naming both (real dispatch classifies these scriptfile - the arity-priority
#rule per-word constraints cannot express; sanctioned via -overlapallowed)
test punkexemodel_tclsh_complete_encoding_limit {complete -encoding shapes raise multipleformmatches naming both forms - the deliberate sanctioned LIMIT}\
-constraints have_punkexedocs\
-setup $common -body {
foreach words {
{-encoding utf-8 foo.tcl a}
{-encoding -foo foo.tcl}
} {
if {[catch {punk::args::parse $words -errorstyle minimal withid (script)::punkexe::tclsh} errmsg erroropts]} {
set classinfo [lindex [dict get $erroropts -errorcode] 2]
lappend result [lindex $classinfo 0]
lappend result [lsort [dict get [lrange $classinfo 1 end] forms]]
} else {
lappend result UNEXPECTED-parsed
}
}
set result
}\
-cleanup {
}\
-result [list multipleformmatches {scriptfile stdin} multipleformmatches {scriptfile stdin}]
}
tcltest::cleanupTests ;#needed to produce test summary.
Loading…
Cancel
Save