Browse Source
User-approved goal recording the multi-form feature gap characterized 2026-07-08
with an after-like fixture:
- punk::args::parse without -form (default *) does not attempt non-zero forms -
input matching only a later form (e.g. 'cancel after#1') fails with form 0's
type/arity error, so the appropriate form must currently be specified manually
- -form is documented as accepting a set/list of forms but accepts only a single
form name or integer index
- the documentation surface does not determine/mark the closest form
('i after cancel <id>' presents the default form; 's after cancel someid'
lists all synopses unmarked)
Detail file records the probe findings, an approach sketch (form candidacy with
a leading-literal fast path, -form list support, doc-surface marking), the
requirement that explicit single-form restriction remains available, and the
test-first sequencing (forms.test GAP pins flip when this goal is implemented).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
2 changed files with 84 additions and 0 deletions
@ -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 <cmd> <args...>' and synopsis output indicate the best-matching form(s) for supplied args; explicit -form <single-name-or-index> 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 <name-or-index>` 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 '<names>'" - only a single name or index is accepted. |
||||||
|
- Documentation surface: `i after cancel <id>` 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 <id>') 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. |
||||||
Loading…
Reference in new issue