Browse Source

G-051 achieved: doc-walk choice-prefix parity + truthful doconly cmdtype (punk::ns 0.4.0, punk::lib 0.4.1, project 0.12.13)

Space-form docid prefix parity: cmd_traverse's space-delimited child
docid jump, on an exact-word miss, now resolves the word against the
current level's choices-bearing first leader via
punk::args::choiceword_match (the shared G-040 resolver - -choiceprefix,
-nocase, -choicealiases, denylist, reservelist honoured) and retries
with the canonical word. 'i string is tr' resolves to the
"::tcl::string::is true" documentation exactly when 'string is tr 1'
executes; 'string is bool' -> boolean; ambiguous ('d'), unknown ('zz')
and denied words stay at the parent exactly when parse rejects them.
resolvedargs records the canonical, mirroring parse normalization. No
second matching rule exists.

Truthful cmdtype: cmdinfo classifies cmdwhich-notfound + non-empty docid
as 'doconly' (was 'notfound') - documentation-only levels below real
commands (per-class ids like "::tcl::string::is true", documented TclOO
method docids; the method case adopts doconly per the recorded design
decision, refinable by G-052). Consumers audited: cmdhelp/synopsis/eg
are docid-driven, cmdtrace tests only for 'proc', punk::help topic
fallback uses cmdwhich; punk::lib script analysis updated in step
(doconly accepted alongside notfound, bucketing unchanged).

Tests: the four G-051 GAP pins flipped and renamed
(cmdhelp_pseudo_command_cmdtype_doconly,
cmdhelp_spaceform_docid_prefix_honoured + ambiguous/unknown guard,
cmdhelp_string_is_true_pseudo_doconly,
cmdhelp_string_is_prefix_honoured). punk::ns 53/53 (cmdflow + non-GAP
cmdhelp unchanged), punk::args 193 pass / 1 pre-existing skip,
punk::lib 35/35; full source-tree suite result in the detail file.
Live verification (punk902z src): 'i string is tr' renders
byte-identical to 'i string is true' except the failure banner echoing
the typed words.

Flip edits: G-051 index entry to GOALS-archive.md (achieved 2026-07-13),
detail Status flipped with acceptance review and verification record,
reference sweep updates G-052 Notes. Detail-file move to goals/archive/
follows as a pure rename; goals_lint transiently unclean between the two
commits.

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 2 days ago
parent
commit
deb8f17d72
  1. 4
      CHANGELOG.md
  2. 4
      GOALS-archive.md
  3. 4
      GOALS.md
  4. 39
      goals/G-051-cmdinfo-pseudo-and-prefix.md
  5. 5
      goals/G-052-oo-method-autodef.md
  6. 2
      punkproject.toml
  7. 12
      src/modules/punk/lib-999999.0a1.0.tm
  8. 3
      src/modules/punk/lib-buildversion.txt
  9. 54
      src/modules/punk/ns-999999.0a1.0.tm
  10. 3
      src/modules/punk/ns-buildversion.txt
  11. 29
      src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test

4
CHANGELOG.md

@ -5,6 +5,10 @@ The latest `## [X.Y.Z]` header must match the `version` field in `punkproject.to
Entries are newest-first; one bullet per notable change. See the root `AGENTS.md`
"Project Versioning" section for the bump policy.
## [0.12.13] - 2026-07-13
- G-051 achieved: punk::ns 0.4.0 - the help system's doc walk now accepts the same choice-word abbreviations parsing accepts: 'i string is tr' resolves to the 'string is true' documentation exactly as 'string is tr 1' executes (unique prefixes, aliases, nocase; ambiguous/denied/unknown words stay at the parent exactly when parse rejects them). cmdinfo also reports the truthful cmdtype 'doconly' (was 'notfound') for documentation-only levels such as 'string is <class>' and documented TclOO method docids. punk::lib 0.4.1 adapts its script analysis to the new value with identical behaviour.
## [0.12.12] - 2026-07-12
- punk::ns 0.3.0: 'i <cmd>' with no argument words again signals when the command cannot be called bare - e.g 'i if' shows "Bad number of trailing values for if. Got 0 values. Expected at least 2" in the error scheme above the usage table (regression vs older builds, reported by the user). The G-046-era suppression of that render existed because the old message carried internal-looking attribution ("for punk::args::parse ..."); the G-049 -caller attribution fixed the message wording, so the suppression was reversed rather than reworded - the original 'i string is' complaint case now renders an accurate "Bad number of leading values for string is ..." instead of being hidden.

4
GOALS-archive.md

@ -58,6 +58,10 @@ Acceptance: parsing/argument resolution provably skips -help expansion (a defini
Scope: src/modules/punk/args-999999.0a1.0.tm (arg_error, parse error dispatch, colour-scheme handling), src/modules/punk/ns-999999.0a1.0.tm (cmdhelp), src/tests/modules/punk/args/testsuites/args/usagemarking.test, src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test
Acceptance: cmdhelp -return dict distinguishes an incomplete, a fully-valid and an invalid argument set via per-argument statuses (received/ok/bad + overall scheme/message/form) with the structure documented; the table and string renderers derive their marking from that same structure, with rendered output unchanged except where the pinned GAP tests flip: badarg marking covers type/allocation failures not just choice violations (cmdhelp_GAP_no_badarg_marking_for_failed_typed_value), an explicit -scheme is honoured on the parse-failure path (cmdhelp_GAP_explicit_scheme_ignored_on_failure), the failure message names the queried command instead of cmdhelp's internal parse source line (cmdhelp_GAP_errormsg_leaks_internal_source), and scheme rendering no longer depends on or mutates shared colour state - the documented -scheme choice value 'nocolour' takes effect and repeated renders of the same call are identical regardless of prior scheme renders (usagemarking_GAP_scheme_nocolour_renders_with_leftover_colours, usagemarking_GAP_dash_nocolour_leaks_into_shared_array, usagemarking_GAP_dash_nocolour_leak_affects_later_info_render); all non-GAP characterization tests in usagemarking.test and cmdhelp.test pass unchanged.
### G-051 [achieved 2026-07-13] cmdinfo truthful cmdtype for doc-only pseudo-commands and space-form docid prefix parity → detail: goals/archive/G-051-cmdinfo-pseudo-and-prefix.md
Scope: src/modules/punk/ns-999999.0a1.0.tm (cmdinfo, cmd_traverse), src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test, src/tests/modules/punk/ns/testsuites/ns/cmdflow.test
Acceptance: the pinned GAP tests flip: cmdhelp_GAP_pseudo_command_cmdtype_notfound and cmdhelp_GAP_string_is_true_pseudo report the new cmdtype with the docid unchanged, cmdhelp_GAP_spaceform_docid_prefix_not_honoured and cmdhelp_GAP_string_is_prefix_not_honoured resolve the child docid from a prefix exactly when parse accepts that prefix (honouring -choiceprefix, -choiceprefixdenylist, -choiceprefixreservelist and -choicealiases per G-040 parity); consumers of cmdinfo's cmdtype (cmdhelp, synopsis, eg) handle the new value with no behaviour change for real commands; cmdflow.test and the non-GAP cmdhelp.test tests pass unchanged.
### G-054 [achieved 2026-07-11] tclcore moduledoc: runtime-harvested 'string is' class choices with cross-version behavioural parity pins → detail: goals/archive/G-054-tclcore-stringis-harvest.md
Scope: src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm (+ tclcore-buildversion.txt), src/tests/modules/punk/args/testsuites/args/ (new parity test), TEMP_REFERENCE/tcl9 (read-only reference)
Acceptance: parse/parse_status against ::tcl::string::is and its per-class virtual ids agrees with the real interpreter's error-vs-ok outcome for a pinned probe matrix (missing args, trailing flag-like str word, option/class unique-prefix acceptance and ambiguity rejection, unknown option/class, -failindex var consumption leaving no str, per-version class presence: dict, unicode) on Tcl 9.0.x and 8.6; the rendered choices show only classes the running interp accepts; the parity test derives expectations from the live interpreter (not version arithmetic) and passes under both; existing args/tclcore suites pass; tclcore buildversion bumped with changelog.

4
GOALS.md

@ -222,10 +222,6 @@ Detail: goals/G-048-textblock-table-punkargs.md
Scope: src/modules/punk/ns-999999.0a1.0.tm (synopsis), src/modules/punk/args-999999.0a1.0.tm (synopsis renderer), src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test (synopsis pins)
Detail: goals/G-050-synopsis-validity-marking.md
### G-051 [proposed] cmdinfo truthful cmdtype for doc-only pseudo-commands and space-form docid prefix parity
Scope: src/modules/punk/ns-999999.0a1.0.tm (cmdinfo, cmd_traverse), src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test, src/tests/modules/punk/ns/testsuites/ns/cmdflow.test
Detail: goals/G-051-cmdinfo-pseudo-and-prefix.md
### G-052 [proposed] TclOO method-level autodef documentation
Scope: src/modules/punk/ns-999999.0a1.0.tm (generate_autodef oo branches, cmd_traverse), src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test
Detail: goals/G-052-oo-method-autodef.md

39
goals/G-051-cmdinfo-pseudo-and-prefix.md

@ -1,6 +1,6 @@
# G-051 cmdinfo truthful cmdtype for doc-only pseudo-commands and space-form docid prefix parity
Status: proposed
Status: achieved 2026-07-13
Scope: src/modules/punk/ns-999999.0a1.0.tm (cmdinfo, cmd_traverse), src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test, src/tests/modules/punk/ns/testsuites/ns/cmdflow.test
Goal: cmdinfo reports a distinct cmdtype (e.g 'doconly') when resolution lands on a punk::args id with no corresponding real command instead of today's 'notfound', and the space-delimited docid jump accepts the same word prefixes the parser accepts - via the shared punk::args::choiceword_match resolver, not a second matching rule - so 'i string is tr' documents what 'string is tr' actually executes.
Acceptance: the pinned GAP tests flip: cmdhelp_GAP_pseudo_command_cmdtype_notfound and cmdhelp_GAP_string_is_true_pseudo report the new cmdtype with the docid unchanged, cmdhelp_GAP_spaceform_docid_prefix_not_honoured and cmdhelp_GAP_string_is_prefix_not_honoured resolve the child docid from a prefix exactly when parse accepts that prefix (honouring -choiceprefix, -choiceprefixdenylist, -choiceprefixreservelist and -choicealiases per G-040 parity); consumers of cmdinfo's cmdtype (cmdhelp, synopsis, eg) handle the new value with no behaviour change for real commands; cmdflow.test and the non-GAP cmdhelp.test tests pass unchanged.
@ -53,3 +53,40 @@ cmdhelp_GAP_string_is_prefix_not_honoured (real tclcore docs).
- 'string is' has a second wrinkle out of scope here: its per-class ids are generated
from the parent's -choicelabels at tclcore load time; prefix parity must come from the
walk, not from generating extra prefix ids.
## Progress
### 2026-07-13 implemented (punk::ns 0.4.0, punk::lib 0.4.1) - acceptance complete
- doconly cmdtype: cmdinfo classifies cmdwhich-notfound + non-empty docid as
'doconly' after the curried-alias retry. Design decision (anticipated in
Context): the TclOO documented-method case ("<class> docmeth" docids) ADOPTS
doconly rather than a method-specific value - G-052 may refine when it takes
up method-level autodef; cmdhelp_oo_documented_method's docid assertion holds
unchanged.
- Consumers audited: cmdhelp (docid-driven; its origintype switch only branches
on 'script'; doconly implies docid non-empty so the undocumented fallback is
unreachable for it), synopsis and eg (docid-driven), cmdtrace (tests only for
'proc'), punk::help topic fallback (uses cmdwhich whichtype, not cmdinfo),
punk::lib tclscript analysis (doconly accepted alongside notfound at the
subcommand-walk stop condition and the bucketing switch - identical behaviour
preserved, the 'string is xdigit' comment there anticipated exactly this).
- Space-form prefix parity: cmd_traverse's exact-word space-form jump gains a
choiceword_match retry (current level's choices-bearing first leader; the
shared G-040 resolver, no second matching rule) resolving the canonical word
before the id_exists retest; resolvedargs records the canonical, mirroring
parse normalization.
- GAP flips (renamed): cmdhelp_pseudo_command_cmdtype_doconly,
cmdhelp_spaceform_docid_prefix_honoured (extended with ambiguous/unknown-word
stays-at-parent guard), cmdhelp_string_is_true_pseudo_doconly,
cmdhelp_string_is_prefix_honoured.
- Live verification (punk902z src, Tcl 9.0.2): 'i string is tr' resolves docid
::tcl::string::is true (doconly) and renders byte-identical to
'i string is true' except the failure banner echoing the typed words
("for string is tr" vs "for string is true" - the -caller echo of user
input, considered correct); 'string is bool' -> boolean; ambiguous 'd' and
unknown 'zz' stay at the parent docid exactly as parse rejects them.
- Suites (tclsh 9.0.3): punk::ns 53/53 (cmdflow + non-GAP cmdhelp unchanged),
punk::args 193 pass / 1 pre-existing skip, punk::lib 35/35; full source-tree
suite 827 total, 813 pass, 13 skip, 1 fail = exec-14.3 only (known
pre-existing core-test baseline) - zero regressions.

5
goals/G-052-oo-method-autodef.md

@ -52,5 +52,8 @@ just not wired up as a general method-level (autodef) generation step in the doc
documented, plainmeth undocumented).
- Filters, private methods and `unknown` handlers are marked in choiceinfo today but out
of scope for autodef generation.
- Coordinate the cmdtype reported for method resolutions with G-051's doconly decision.
- G-051 (achieved 2026-07-13 - see goals/archive/G-051-cmdinfo-pseudo-and-prefix.md)
decided the documented-method case ADOPTS the doconly cmdtype (docid-nonempty +
cmdwhich-notfound classification, no method-specific value). Refine here if this
goal's method-level autodef work warrants a distinct method cmdtype.
- Archived-goal references in this file: G-040 achieved 2026-07-08 (goals/archive/G-040-punkargs-choicealiases.md).

2
punkproject.toml

@ -1,4 +1,4 @@
[project]
name = "punkshell"
version = "0.12.12"
version = "0.12.13"
license = "BSD-2-Clause"

12
src/modules/punk/lib-999999.0a1.0.tm

@ -2455,8 +2455,11 @@ namespace eval punk::lib {
#no change in origin - so we are into the arguments of the command, or have an invalid subcommand - stop looking for subcommands
#todo - detect invalid subcommand and count as unknown command?
break
} elseif {[dict get $test_cinfo cmdtype] in {"proc" "native" "notfound"}} {
} elseif {[dict get $test_cinfo cmdtype] in {"proc" "native" "notfound" "doconly"}} {
#we have a subcommand that won't be introspectable at a deeper level.
#(doconly: G-051 - cmdinfo's truthful cmdtype for documentation-only
#levels such as 'string is xdigit', previously reported 'notfound';
#treated identically here to preserve prior analysis behaviour)
set cinfo $test_cinfo
set ctype [dict get $cinfo cmdtype]
break
@ -2714,7 +2717,12 @@ namespace eval punk::lib {
dict lappend resultd commands_native $dispatchwords
}
}
"notfound" {
"notfound" -
"doconly" {
#doconly: G-051 - documentation-only level (e.g 'string is xdigit'),
#previously reported as 'notfound'; bucketed identically to preserve
#prior analysis behaviour (a future refinement may count doconly as a
#valid command word rather than notfound)
if {$dispatchwords ni [dict get $resultd commands_notfound]} {
dict lappend resultd commands_notfound $dispatchwords
}

3
src/modules/punk/lib-buildversion.txt

@ -1,6 +1,7 @@
0.4.0
0.4.1
#First line must be a semantic version number
#all other lines are ignored.
#0.4.1 - G-051 call-site adaptation: tclscript analysis accepts cmdinfo's new 'doconly' cmdtype alongside 'notfound' (subcommand-walk stop condition and the dispatchwords bucketing switch) - bucketed identically to notfound to preserve prior analysis behaviour; a future refinement may count doconly (a documented pseudo-command such as 'string is xdigit') as a valid command word.
#0.4.0 - G-058: snapshot_package_paths and interp_sync_package_paths now also propagate the runtime static/builtin package baseline captured at kit boot (::punkboot::static_prefixes/static_packages - see punk_main.tcl) and seed 'package ifneeded <name> <ver> {load {} <prefix>}' entries in the target thread/interp, so statically-linked runtime packages (e.g Thread/twapi on a tcl-sfe runtime) resolve in fabricated interps whose package search paths punkshell controls. No-op when no baseline was captured (plain tclsh dev launches).
#0.3.1 - Tcl 9.1 compatibility (TIP 746 removed expr behaviour from lseq operands): range (lseq branch) now normalizes int[+-]int offset operands itself via offset_expr - callers such as `range 0 [llength $list]-1` keep working; also aligned the lseq branch with the fallback contract: default by now infers direction (range 5 1 -> descending, previously empty under tcl9) and by 0 returns empty (Tcl 9.1 lseq changed by-0 to return one element). lzipn_tcl9b/lzipn_tcl9c/cols/cols2: lseq expression operands wrapped in expr. check::has_tclbug_safeinterp_compile: Tcl 9.1 safe interps hide tcl::unsupported::* - falls back to interp invokehidden tcl:unsupported:disassemble
#0.3.0 - new: punk::lib::check::has_libbug_udp_threadexit + libbug_udp_threadexit_applies classifier - version-based detection of tcludp < 1.0.13 on Tcl 9 Windows (per-thread exit handler closes process-global event handles; G-036). has_libbug_* is the new check family for bundled/vendored library bugs, surfaced through 'help tcl' alongside has_tclbug_*; buginfo dicts may carry a full 'url' reference key (non tcl-core trackers)

54
src/modules/punk/ns-999999.0a1.0.tm

@ -4845,6 +4845,15 @@ y" {return quirkykeyscript}
return [cmdinfo {*}$next]
}
}
if {$cmdtype eq "notfound" && $docid ne ""} {
#G-051: resolution landed on a punk::args id with no corresponding real
#command - a documentation-only level below (or beside) a real command,
#e.g the per-class id "::tcl::string::is true" documenting a level below
#the real ::tcl::string::is (the class words are arguments, not
#subcommands). Report it distinctly so consumers can tell it from a
#genuinely unknown command. The docid remains authoritative for display.
set cmdtype doconly
}
return [list origin $origin cmdtype $cmdtype args_resolved [list [lindex $commands 0] {*}$consumed_args] args_remaining $remainingargs docid $docid stack $stack]
}
proc cmd_traverse {ns formid args} {
@ -5023,8 +5032,49 @@ y" {return quirkykeyscript}
#(would not support shor-form prefix of subcommand - even if the proc implementation did)
set docid_exists 0
set eparams [list]
set a_spaceform ""
if {[punk::args::id_exists "$origin [lindex $args $i]"]} {
set a [lindex $args $i]
set a_spaceform [lindex $args $i]
} elseif {$docid ne "" && [punk::args::id_exists $docid]} {
#G-051 space-form docid prefix parity: no space-form id exists for the
#exact word - if the current level's definition has a choices-bearing
#first leader, resolve the word with the same shared resolver argument
#parsing uses (punk::args::choiceword_match - honouring -choiceprefix,
#-nocase, -choicealiases, -choiceprefixdenylist,
#-choiceprefixreservelist) and retry the space-form lookup with the
#canonical word - so 'i string is tr' lands on the documentation for
#what 'string is tr' actually executes. No second matching rule: a word
#parse would reject resolves nothing here either, and a canonical with
#no space-form id falls through to the normal per-level handling.
set pf_spec [punk::args::get_spec $docid]
set pf_fid [lindex [dict get $pf_spec form_names] 0]
set pf_leaders [dict get $pf_spec FORMS $pf_fid LEADER_NAMES]
if {[llength $pf_leaders]} {
set pf_arginfo [dict get $pf_spec FORMS $pf_fid ARG_INFO [lindex $pf_leaders 0]]
set pf_allchoices [punk::args::system::Dict_getdef $pf_arginfo -choices {}]
foreach {_pf_g pf_members} [punk::args::system::Dict_getdef $pf_arginfo -choicegroups {}] {
lappend pf_allchoices {*}$pf_members
}
if {[llength $pf_allchoices]} {
set pf_matchinfo [punk::args::choiceword_match [lindex $args $i]\
[punk::args::system::Dict_getdef $pf_arginfo -nocase 0]\
$pf_allchoices\
[punk::args::system::Dict_getdef $pf_arginfo -choicealiases {}]\
[punk::args::system::Dict_getdef $pf_arginfo -choiceprefix 1]\
[punk::args::system::Dict_getdef $pf_arginfo -choiceprefixdenylist {}]\
[punk::args::system::Dict_getdef $pf_arginfo -choiceprefixreservelist {}]\
]
if {[dict get $pf_matchinfo matched]} {
set pf_canonical [dict get $pf_matchinfo canonical]
if {$pf_canonical ne [lindex $args $i] && [punk::args::id_exists "$origin $pf_canonical"]} {
set a_spaceform $pf_canonical
}
}
}
}
}
if {$a_spaceform ne ""} {
set a $a_spaceform
#review - tests?
#puts stderr "cmd_traverse - skipping to documented subcommand '$origin $a'"
#we can only seek beyond an undocumented subcommand level via a space delimited path, as we can make no assumption about the actual location of a subcommand relative to its parent
@ -5034,7 +5084,7 @@ y" {return quirkykeyscript}
set origin [list $origin $a]
incr i
set queryargs [lrange $args $i end]
set resolvedargs [list $a] ;#
set resolvedargs [list $a] ;#the canonical word (a resolved prefix/alias records its canonical, as parse normalization does)
set queryargs_untested $queryargs
} elseif {[punk::args::id_exists $docid]} {
set docid_exists 1

3
src/modules/punk/ns-buildversion.txt

@ -1,6 +1,7 @@
0.3.0
0.4.0
#First line must be a semantic version number
#all other lines are ignored.
#0.4.0 - G-051: (a) cmdinfo reports cmdtype 'doconly' (was 'notfound') when resolution lands on a punk::args id with no corresponding real command - documentation-only levels such as the per-class id "::tcl::string::is true" below the real ::tcl::string::is, and TclOO documented-method docids like "<class> docmeth" (method case adopts doconly; may be refined by G-052). Consumers audited: cmdhelp/synopsis/eg are docid-driven, cmdtrace only tests for 'proc', punk::lib script analysis updated in step (lib 0.4.1). (b) space-form docid prefix parity: cmd_traverse's space-delimited child docid jump, on an exact-word miss, resolves the word against the current level's choices-bearing first leader via punk::args::choiceword_match (the shared G-040 resolver - -choiceprefix/-nocase/-choicealiases/denylist/reservelist honoured) and retries with the canonical word - so 'i string is tr' resolves to "::tcl::string::is true" exactly when 'string is tr' executes, ambiguous/unknown/denied words stay at the parent exactly when parse rejects them, and resolvedargs records the canonical (as parse normalization does). Tests: the four G-051 GAP pins flipped (cmdhelp_pseudo_command_cmdtype_doconly, cmdhelp_spaceform_docid_prefix_honoured incl ambiguous/unknown guard, cmdhelp_string_is_true_pseudo_doconly, cmdhelp_string_is_prefix_honoured).
#0.3.0 - reversal of the G-046-item-5 no-supplied-words suppression (user direction 2026-07-12): cmdhelp's advisory parse failing with NO supplied argument words renders the failure message and error scheme again (both the alias path and the main path; dict returns no longer rewrite the scheme to info), so 'i if'/'i while'/'i foreach' once more signal that the command cannot be called bare - e.g "Bad number of trailing values for if. Got 0 values. Expected at least 2". Rationale: the suppression (ns 0.1.4) existed because the pre-G-049 message was internal-looking ("... for punk::args::parse $args_remaining ..."); the G-049 -caller attribution (ns 0.2.0) made bare-query messages accurate - including the original 'i string is' complaint case, which now reads "Bad number of leading values for string is. Got 0 leaders. Expected exactly 1". Tests: cmdhelp_leader_required_no_args_plain_usage flipped to cmdhelp_leader_required_no_args_error_render; cmdhelp_return_dict_scheme expects scheme error for the bare-query failure.
#0.2.0 - G-049: cmdhelp -return dict - machine-parsable return carrying resolution info (origin/docid/cmdtype/args_remaining) plus the parse-status structure of the supplied argument words (punk::args::parse_status shape; empty for undocumented commands); the scheme field reflects an explicit -scheme and the G-046-item-5 no-supplied-words suppression. cmdhelp's advisory parse now runs via punk::args::parse_status on both the alias path and the main path: an explicit -scheme is honoured on the parse-failure render (previously only on success/tableobject - failures returned parse's internally rendered error with the default error scheme), failure renders consume the structure via arg_error -parsestatus (badarg marking now covers type/allocation failures via the structure), and the failure message names the queried command (parse -caller: querycommand + consumed subcommand words) instead of whatever the %caller% frame walk found - at top call depth that was cmdhelp's own raw 'punk::args::parse $args_remaining ...' source text. Tests: cmdhelp.test G-049 GAP pins flipped + cmdhelp_return_dict_* added
#0.1.4 - G-046 item 5: cmdhelp's advisory goodargs parse failing with NO supplied argument words (e.g 'i string is' where the definition requires leaders) now shows plain info-scheme usage instead of the internal-looking "Bad number of leading values for punk::args::parse ..." error output (both the alias path and the main path; error display for supplied-but-invalid words unchanged). The no-supplied-words advisory parse runs with -errorstyle minimal so its failure doesn't render the full usage table inside the discarded error - large argdocs (e.g 'i punk::args::define') render the table once, not twice (verified parity with pre-G-046 timings: ~5.3s first/~4.1s repeat on punk91 src, table construction dominant). Test: cmdhelp.test cmdhelp_leader_required_no_args_plain_usage

29
src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test

@ -439,7 +439,14 @@ namespace eval ::testspace {
#--- GAP pins: pseudo-command cmdtype + space-delimited docid prefixes (G-051) ------------
test cmdhelp_GAP_pseudo_command_cmdtype_notfound {a space-delimited docid below a real command resolves its documentation but reports cmdtype 'notfound'}\
#G-051 flipped pins (were cmdhelp_GAP_pseudo_command_cmdtype_notfound /
#cmdhelp_GAP_spaceform_docid_prefix_not_honoured / cmdhelp_GAP_string_is_true_pseudo /
#cmdhelp_GAP_string_is_prefix_not_honoured): cmdinfo reports cmdtype 'doconly' when
#resolution lands on a punk::args id with no corresponding real command, and the
#space-form docid jump resolves choice prefixes via punk::args::choiceword_match
#(the shared resolver - no second matching rule) when the exact word has no id.
test cmdhelp_pseudo_command_cmdtype_doconly {a space-delimited docid below a real command resolves its documentation and reports cmdtype 'doconly'}\
-setup $common -body {
set cinfo [punk::ns::cmdinfo ::testspace::helpstr is]
lappend result [dict get $cinfo docid] [dict get $cinfo cmdtype]
@ -448,22 +455,26 @@ namespace eval ::testspace {
}\
-cleanup {
}\
-result [list {::testspace::helpstr is} notfound {::testspace::helpstr is} hello]
-result [list {::testspace::helpstr is} doconly {::testspace::helpstr is} hello]
test cmdhelp_GAP_spaceform_docid_prefix_not_honoured {parse accepts a unique choice prefix for the subcommand word but the space-delimited docid jump requires the exact word}\
test cmdhelp_spaceform_docid_prefix_honoured {the space-delimited docid jump accepts the choice prefixes parse accepts, resolving to the canonical child docid}\
-setup $common -body {
#parse side: unique prefix 'i' of choice 'is' is accepted and normalized
set argd [punk::args::parse {i} withid ::testspace::helpstr]
lappend result [dict get [dict get $argd leaders] subcmd]
#doc-walk side: the same prefix does not reach the child docid
#doc-walk side: the same prefix reaches the child docid with the canonical
#word consumed
set cinfo [punk::ns::cmdinfo ::testspace::helpstr i]
lappend result [dict get $cinfo docid] [dict get $cinfo args_remaining]
#an ambiguous or unknown word still stays at the parent (parse would reject it)
set cinfo [punk::ns::cmdinfo ::testspace::helpstr zz]
lappend result [dict get $cinfo docid] [dict get $cinfo args_remaining]
}\
-cleanup {
}\
-result [list is ::testspace::helpstr i]
-result [list is {::testspace::helpstr is} {} ::testspace::helpstr zz]
test cmdhelp_GAP_string_is_true_pseudo {real-world pin: 'string is true' resolves its tclcore docid but reports cmdtype 'notfound'}\
test cmdhelp_string_is_true_pseudo_doconly {real-world pin: 'string is true' resolves its tclcore docid and reports cmdtype 'doconly'}\
-constraints have_tclcoredocs\
-setup $common -body {
set cinfo [punk::ns::cmdinfo ::string is true]
@ -471,9 +482,9 @@ namespace eval ::testspace {
}\
-cleanup {
}\
-result [list {::tcl::string::is true} notfound]
-result [list {::tcl::string::is true} doconly]
test cmdhelp_GAP_string_is_prefix_not_honoured {real-world pin: 'string is tr' works in Tcl but the doc walk stays at the parent docid}\
test cmdhelp_string_is_prefix_honoured {real-world pin: 'i string is tr' documents what 'string is tr' executes}\
-constraints have_tclcoredocs\
-setup $common -body {
#Tcl itself accepts the class prefix
@ -483,7 +494,7 @@ namespace eval ::testspace {
}\
-cleanup {
}\
-result [list 1 ::tcl::string::is tr]
-result [list 1 {::tcl::string::is true} {}]
#--- TclOO methods (G-052) -----------------------------------------------------------------

Loading…
Cancel
Save