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.
 
 
 
 
 
 

8.7 KiB

G-084 punk::args -parsekey completeness: cross-member -multiple collection, leaders/values support, defined default precedence

Status: achieved 2026-08-07 Scope: src/modules/punk/args-999999.0a1.0.tm (parse paths, resolve directive handling for @leaders/@values); src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm (sites carrying '#todo - fix -parsekey for leaders and values'); src/tests/modules/punk/args/testsuites/args/parsekey.test + testsuites/dev/parsekey-knownbugs.test (GAP/known-bug flips) Goal: -parsekey behaves as a complete, position-independent result-keying mechanism: distinct -multiple members sharing a parsekey are rejected at define time unless the whole group is mutually exclusive (-parsekeymode error), under which -multiple per member is well-defined (no silent value loss), -parsekey on leaders and values renames their result/received keys the same way it does for options (or is rejected at define time everywhere it is unsupported - no silent ignore, no parse-time abort), and the precedence rule for multiple defaulted members of one group is documented behaviour rather than an in-code '? review'. Acceptance: the three punkargsKnownBug tests in testsuites/dev/parsekey-knownbugs.test are enabled and pass (or are amended to the settled design and pass); the corresponding _GAP pins in parsekey.test are flipped or retired; the '#todo - fix -parsekey for leaders and values' moduledoc comment is resolved; the full existing punk::args suite passes untouched.

Context

Probe findings from the 2026-07-14 parsekey coverage review, each pinned by a _GAP test in src/tests/modules/punk/args/testsuites/args/parsekey.test:

  • Cross-member -multiple value loss: with -add and -sub both -multiple 1 sharing parsekey -op, parsing -add a -sub b -add c returns -op b - the collected -add occurrences {a c} vanish. Occurrences are collected per member flag and the shared-key resolution then returns only one member's list (parsekey_shared_key_multiple_collection_GAP).
  • -parsekey on a value is accepted at define time but ABORTS parsing with an internal error; on a leader it is silently ignored; the @values directive line rejects it as an unrecognised key (parsekey_values_leaders_GAP). The tclcore moduledoc carries #todo - fix -parsekey for leaders and values next to a definition using it, and choices.test notes a leaders/values parsekey mechanism would help multi-element clause choice grouping.
  • When more than one member of a shared-parsekey group declares -default, the last-defined member's default wins - the ordered_opts default handling in the source carries a literal ? review (parsekey_shared_key_member_defaults_GAP).

Approach

  • Cross-member -multiple collection SETTLED 2026-08-07 as define-time rejection (the G-083-informed alternative): accumulate-in-received-order was the original lean, but cross-member collection on one storage key is ambiguous (collect-vs-replace undefined; one member's collected list would silently displace another's) and rejection eliminates the silent loss without inventing new collection semantics. -multiple per member remains available when ALL members share one @opts group marked -parsekeymode error (G-083 mutual exclusivity makes it well-defined); a single -multiple member with its own parsekey is unrestricted. The check runs after the G-053 canonicalisation so range forms verdict correctly ({0 1} is replace-shape and allowed).
  • Leaders/values support should reuse the option path's keying rules (result + received dicts, required-list satisfaction) rather than a parallel mechanism; where support is deliberately not implemented, define time must reject the key with a clear message instead of deferring failure to parse.
  • The defaulted-members precedence rule (whatever is settled) gets stated in the -parsekey documentation and the ? review comment removed.

Notes

  • Desired-behaviour pins: settled 2026-08-07 - testsuites/dev/parsekey-knownbugs.test holds no disabled pins (retained as the home for future punkargsKnownBug pins); the settled assertions live in testsuites/args/parsekey.test (parsekey_value_result_key_settled, parsekey_values_line_rejects_parsekey, parsekey_leader_parsekey_rejected, parsekey_shared_key_multiple_rejected, parsekey_value_parsekey_integrity).
  • Related: G-083 (argument relations - shared design context for the cross-member collection decision; achieved - see goals/archive/G-083-punkargs-argument-relations.md), G-053 (occurrence arity of a single argument; achieved - see goals/archive/G-053-punkargs-multiple-ranges.md).
  • Related: G-151 (achieved 2026-08-05 - goals/archive/G-151-punkargs-annotated-success-render.md) - its parse_report landing report bridges the parse-result storage-key folds AT DISPLAY LEVEL (pinned by parsereport.test parsereport_aliased_optionset_row_bridged). NARROWED 2026-08-07 (inc 2, punk::args 0.24.0): private::parse_status_build now resolves UNIQUE storage keys itself (a value's -parsekey, an option's declared -parsekey, an optset's '='-suffixed trimmed tail) for received attribution AND value-in-effect, so the parse_report bridge and the build's miss now apply only to SHARED-parsekey groups.
  • Remaining display gap (shared groups only, as of inc 2): parse_report's Source column and parse_status's per-arg received count still report default/0 for an explicitly-supplied SHARED-parsekey member (e.g parse_report {-exact ...} withid ::lsearch shows every MATCHSTYLE member as (default) though the group value is bridged onto each member row) - per-member received attribution does not survive the storage fold, and which member was received is genuinely unrecoverable from the parse result dict alone. Retirement needs engine-level per-member tracking in the parse result (get_dict's optsets_received exists internally but is not exposed). Pinned as the remaining gap by parsereport.test parsereport_storagekey_attribution (the shared-group default/default row).

Progress

  • 2026-08-07 (inc 1, commit abd8616f, punk::args 0.23.0): value -parsekey supported (result values slot and received keyed by parsekey, -multiple collection, VAL_DEFAULTS/values_dict parsekey keying, api_valnames_received tracking, val_pk2name reverse map); leader -parsekey rejected at define time; defaulted-members precedence documented as last-defined-member-wins and the in-code ? review removed; tclcore moduledoc todo resolved; parsekey.test value/leader/@values-line/defaults GAPs flipped to settled pins; knownbugs value/leader disabled pins retired.
  • 2026-08-07 (inc 2, punk::args 0.24.0): cross-member -multiple decision SETTLED as define-time rejection (allowed only when ALL members share one @opts group marked -parsekeymode error; check placed after the G-053 canonicalisation so {0 1} range replace-shapes stay allowed - an earlier pre-canonicalisation placement raised a raw non-boolean error for range forms); value-parsekey integrity settled (duplicate value parsekeys and dash-led value parsekeys rejected at define time - previously silent positional overwrite / internal parse abort); parse_status/parse_report unique-storage-key received+value attribution (shared groups remain the recorded display gap); undefine/undefine_deflist return ""; define -help -parsekey documentation added (first user-facing -parsekey doc, includes the defaults-precedence rule per this goal's Approach); dead-code and stale-comment sweep (val_ident/values-side seen_pks, leader reverse map, pre-G-084 comment claims). Suites: punk/args 401/0, testbody_lint clean.
  • 2026-08-07 (flip): acceptance verified met - knownbug pins settled and passing, _GAP pins flipped/retired, moduledoc comment resolved, full suite green (punk/args 401/0; modules tree 1313 pass / 11 constraint-skipped / 0 fail on the zig-built tclsh90s 9.0.5 runner; testbody_lint and goals_lint clean). The Goal line's accumulate-in-received-order wording was amended to the settled define-time-rejection design with the -parsekeymode error escape at the user's explicit approval, and the goal flipped achieved and archived. The shared-parsekey-group received-attribution display gap is recorded below as a Follow-on (=> open).

Follow-ons

Follow-on: engine-level per-member received attribution for shared-parsekey groups - expose per-member tracking (e.g get_dict's internal optsets_received) in the parse result so parse_status/parse_report Source columns can attribute WHICH member of a shared-parsekey group was received; retires the parse_report display bridge and parse_status_build's shared-key miss (pinned today by parsereport.test parsereport_storagekey_attribution's shared-group default/default row) => open