You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

6.0 KiB

G-083 punk::args argument relations: strict mutual exclusivity and parsekey-group integrity

Status: proposed Scope: src/modules/punk/args-999999.0a1.0.tm (resolve/spec compiler, parse paths incl mash, arg_error/synopsis/usage renderers, errorcode vocabulary), src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm (lsearch, clock clicks dogfood), src/tests/modules/punk/args/testsuites/args/ + testsuites/dev/ (GAP flips + new characterization) Goal: punk::args definitions can express hard mutual exclusivity - a per-argument -conflicts relation (keyed on parsekeys, checked only against received arguments so defaults never conflict) and an @opts-level strict mode making distinct-member co-occurrence within a shared-parsekey group an error - while legacy last-wins remains the default, so lsearch-class commands (grouped styles with pairwise incompatibilities like -sorted vs -glob/-regexp and -bisect vs -all/-not) parse and document faithfully without combinatorial @form explosion. Acceptance: parse raises a usage-style error with a structured errorcode (PUNKARGS VALIDATION optionconflict shape) naming both offending received arguments for -conflicts violations and strict-group co-occurrence, through both the ordinary and mash option paths with prefix abbreviations resolved before the check; define time rejects a -parsekey colliding with a distinct defined argument's name (parsekey_collides_with_defined_optname_GAP flips); legacy behaviour is untouched by default (full existing punk::args suite passes, including the pinned last-wins/prepend-defaults override idiom); the lsearch moduledoc models its documented incompatibilities with the new vocabulary and drops its "punk::args fixes required for grouped mutually exclusive options" caveat; usage/synopsis output for conflict rules is pinned by characterization tests.

Context

Review finding (2026-07-14): punk::args has no way to express "error if these arguments are combined". What exists today:

  • -parsekey shared keys give SOFT exclusivity by overwrite: last received member wins under the common key. That semantics is deliberate and pinned (parsekey_repeat_ordering: overriding earlier non -multiple options must always be possible - it protects the prepend-defaults idiom punk::args::parse [list -flag default {*}$userargs]).
  • -group/-grouphelp associate options for usage display only; no parse semantics.
  • Multiple @forms are the only strict mechanism - structural, combinatorially explosive, and they fork the documentation.
  • The namespace which moduledoc entry works around the gap by modelling -command/-variable as one positional with literalprefix(...) choices (exactly-one-of, but only for a fixed position, not free-order flags) and carries ##todo - make mutually exclusive - (separate forms).

Evidence of need in the tclcore moduledoc alone:

  • The lsearch definition states: "(documentation incomplete - punk::args fixes required for grouped mutually exclusive options and prefix calculation)".
  • lsearch -sorted is "mutually exclusive with -glob and -regexp" per the man page - yet it shares the -MATCHSTYLE parsekey group with them, whose members are otherwise last-wins. Both semantics coexist within ONE group, so a per-group boolean alone cannot model lsearch.
  • lsearch -bisect "cannot be used with either -all or -not" - a cross-group conflict with no shared value key.
  • clock clicks -milliseconds/-microseconds carry a definition comment noting they are mutually exclusive and unmodelled.

A define-time integrity hole was found in the same review: nothing prevents a -parsekey value colliding with a DIFFERENT defined option's name (e.g. {-a -parsekey -b} {-b}); the two silently conflate into an implicit shared-key group (pinned by parsekey_collides_with_defined_optname_GAP).

Approach

Design leans (settle and record here during the work):

  • Per-argument -conflicts {parsekey-or-flag ...}: violation checked against RECEIVED arguments only, after prefix/abbreviation resolution, never against defaults. Applies to any pair regardless of grouping.
  • @opts-level strict mode for a shared-parsekey group (name TBD, e.g. -parsekeymode override|error or -groupexclusive): distinct-member co-occurrence errors; same-member repetition stays G-053 territory (-multiple {0 1}), and legacy last-wins remains the default everywhere.
  • The mash (short-flag bundling) parse path implements its own parsekey logic and must share the conflict check - covered explicitly by acceptance.
  • Errorcode vocabulary: extend PUNKARGS VALIDATION with an optionconflict member mirroring the existing optionmissing shape, designed so a later requires-relation slots in alongside.
  • Usage/synopsis rendering: the group rendering machinery (OPT_GROUPS headers, parsekey hints) is most of the display substrate; conflict rules need a representation there.

Alternatives considered

  • Per-group strict boolean only - insufficient: lsearch mixes last-wins and error semantics within one group (see Context).
  • Modelling exclusivity via @form explosion - rejected: combinatorial and forks documentation; the goal exists to avoid this.
  • Folding into G-053 range-valued -multiple - rejected: G-053 is occurrence arity of ONE argument; this goal is relations BETWEEN arguments. They compose (shared error vocabulary, different axes).

Notes

  • -requires/-implies (dependency relations, e.g. lsearch -subindices with -index, -bisect implying -sorted) deliberately deferred - the man page semantics there are mostly soft ("has no effect unless"); design the errorcode vocabulary so they can be added without reshaping it.
  • Test assets already in place (2026-07-14): characterization pins in src/tests/modules/punk/args/testsuites/args/parsekey.test (mash ordering, prefix abbreviation, collision conflation GAP) ready to flip/extend.
  • Related: G-053 (occurrence arity), G-072 (compound clause types - orthogonal), G-084 (parsekey completeness fixes; its cross-member -multiple design decision should be made with this goal's vocabulary in mind).