diff --git a/GOALS.md b/GOALS.md index c176ef0c..4d51c650 100644 --- a/GOALS.md +++ b/GOALS.md @@ -290,3 +290,9 @@ Scope: src/modules/punk/args-999999.0a1.0.tm (parse + usage rendering), src/modu Detail: goals/G-040-punkargs-choicealiases.md Goal: punk::args supports choice aliases (-choicealiases {alias canonical ...}) accepted at parse and normalized to the canonical choice in results, folded into the canonical entry in usage display - and the punk::ns doc-lookup walk resolves choice words by the same rules as the parser (aliases, -choiceprefix, -choiceprefixdenylist, -choiceprefixreservelist) - so alias sets like punk::help's topics|help and console|term|terminal collapse to one displayed entry per topic with `help X` and `i help X` agreeing. Acceptance: a definition using -choicealiases parses an alias (and an alias prefix where -choiceprefix allows) to its canonical choice in the parse result, with -choicerestricted 0 passthrough and the deny/reserve lists honoured unchanged; usage display shows one entry per canonical choice with aliases folded (no duplicate rows; -choicelabels attach to the canonical); punk::ns::cmdinfo/cmd_traverse resolve subcommand words to docids with the same outcome as the parser for alias, prefix, denied, reserved and unknown words (the pre-goal characterization tests updated from pinned-GAP to fixed); punk::help's topic definition adopts the feature so `i help` lists one entry per registered topic while `help h`/`help e` still fall through to command lookup; definitions without -choicealiases behave unchanged (existing punk::args and punk::ns suites pass). + +### G-041 [proposed] punk::args multi-form matching: automated form selection for parsing and documentation +Scope: src/modules/punk/args-999999.0a1.0.tm (parse form selection, arg_error/usage form marking), src/modules/punk/ns-999999.0a1.0.tm (cmdhelp/synopsis closest-form indication), src/tests/modules/punk/args/testsuites/ +Detail: goals/G-041-punkargs-form-matching.md +Goal: for multi-form definitions punk::args determines which form(s) an argument list matches - parse without -form attempts all permitted forms instead of effectively form 0, -form accepts the documented list-of-forms restriction, and the documentation surface indicates the match ('i after cancel ' presents the cancel form; 's after cancel someid' marks the closest synopsis) - with explicit single-form restriction retained for callers that require it. +Acceptance: parsing a multiform definition (after-like fixture) without -form succeeds when the args match exactly one form (the pinned GAP tests in forms.test flip to auto-selected results); an argument list matching no form (or several) produces an error naming the candidate forms rather than a form-0 type error; -form with a list of form names/indices restricts parsing to that subset (currently an 'Expected int 0-N or one of ...' error); 'i ' and synopsis output indicate the best-matching form(s) for supplied args; explicit -form behaviour is unchanged; the full punk::args and punk::ns suites pass. diff --git a/goals/G-041-punkargs-form-matching.md b/goals/G-041-punkargs-form-matching.md new file mode 100644 index 00000000..f18a14c7 --- /dev/null +++ b/goals/G-041-punkargs-form-matching.md @@ -0,0 +1,78 @@ +# G-041 punk::args multi-form matching: automated form selection for parsing and documentation + +Status: proposed +Scope: src/modules/punk/args-999999.0a1.0.tm (parse form selection, arg_error/usage form marking), src/modules/punk/ns-999999.0a1.0.tm (cmdhelp/synopsis closest-form indication), src/tests/modules/punk/args/testsuites/ +Acceptance: parsing a multiform definition (after-like fixture) without -form succeeds when the args match exactly one form (the pinned GAP tests in forms.test flip to auto-selected results); an argument list matching no form (or several) produces an error naming the candidate forms rather than a form-0 type error; -form with a list of form names/indices restricts parsing to that subset (currently an 'Expected int 0-N or one of ...' error); 'i ' and synopsis output indicate the best-matching form(s) for supplied args; explicit -form behaviour is unchanged; the full punk::args and punk::ns suites pass. + +## Context + +Multi-form definitions (@form directive) describe commands whose argument sets are +orthogonal - the motivating example is the Tcl builtin `after`, documented with several +forms (`after ms ?script...?`, `after cancel id`, `after idle script...`, ...). The +definition and display side works: form_names are recorded, `punk::ns::synopsis` renders +every form (## FORM n headers), and `punk::args::parse -form ` parses +against an explicitly chosen form. + +What is missing (characterized 2026-07-08 with an after-like fixture, probe results +pinned as GAP tests in src/tests/modules/punk/args/testsuites/args/forms.test): + +- `punk::args::parse` without -form (default `*`) does NOT attempt the other forms: + arguments that match only a non-zero form (e.g. `cancel after#1`) fail with form 0's + type/arity error ("Bad number of values ... Not enough remaining values", the leading + word rejected by form 0's int type). Effectively `*` parses form 0 only. +- `-form` is documented as "Restrict parsing to the set of forms listed" and typed as a + list, but a list of two form names errors with "invalid -form value ... Expected int + 0-N or one of ''" - only a single name or index is accepted. +- Documentation surface: `i after cancel ` renders help for the default form rather + than determining that the cancel form is the closest match, and `s after cancel someid` + lists all synopses without marking the matching one. +- Internal note: punk::args::parse's own definition is multiform (withid/withdef, + discriminated by literal types) but the proc hand-parses its arguments on the happy + path, so the multiform selection machinery is not exercised internally either. + +User direction (2026-07-08): there are times when restricting to a particular form is +appropriate and times when automated selection is better - both must remain expressible. +This is an advanced improvement, deferred; the immediate prerequisite work was making the +punk::args test suite comprehensive so the current behaviour is pinned before any +form-selection logic lands. + +## Approach (sketch - to be refined when activated) + +1. Form candidacy: for -form * (or a list), attempt each permitted form's parse; classify + outcomes (clean match / match-with-defaults / type-or-arity failure). Exactly one + clean match -> auto-select. None or several -> error naming candidate forms (and for + 'several', possibly a deterministic preference rule - e.g. first-declared - recorded + when decided). +2. Literal/leading-word discrimination as a fast path: many multiform commands (after, + parse itself) discriminate on a leading literal - a pre-pass on literal/literalprefix + leader types can pick the form without full parse attempts. +3. -form list support: accept a subset of names/indices as documented; single value + behaviour unchanged. +4. Documentation surface: cmdhelp/arg_error accept the supplied trailing args (cmdhelp + already parses them for goodargs marking) and use the same candidacy logic to pick or + rank forms; synopsis display marks the matching form(s). +5. Error-message quality: a no-form-matches error should show per-form failure reasons + compactly rather than only form 0's. + +## Alternatives considered + +- Documenting alternate forms as separate subhelp choiceinfo entries (the trace-style + pattern) - works only when a literal subcommand word exists and fragments a command's + documentation into pseudo-subcommands; rejected as the general answer. +- Requiring callers to always pass -form - status quo for parsing, but unusable for the + interactive doc surface ('i after cancel ') where the user supplies args, not form + names. + +## Notes + +- Probe script: scratchpad formprobe.tcl (2026-07-08); findings encoded in + src/tests/modules/punk/args/testsuites/args/forms.test (GAP-labelled tests reference + this goal and flip when it is implemented). +- Related: G-040 (choice aliasing/doc-lookup parity - same "parser and doc surface must + agree" principle); punk::args::parse -cache interaction with per-form attempts will + need review (cache key already includes selected form). +- Incidental find during the same probing: an uncommented debug `puts stderr + ">>>_get_dict_can_assign_value NOT alloc_ok..."` fired on every failed clause type + assignment (punk/args ~l.6186; its happy-path twin was already commented). Fixed + 2026-07-08 (punk::args 0.2.3) - noted here because form-attempt logic will exercise + that failure path heavily.