Browse Source

goals: add G-073 (punk::args unavailable choices)

User-approved draft from the 8.6-vs-9 string is dict forward-compat
requirement: a new definition key (candidate -choiceunavailable) for
choices that are recognised but not available in the current runtime -
displayed among the choices with their -choicelabels notes, participating
in prefix disambiguation via the shared choiceword_match resolver (so
abbreviations colliding with forward-version choices are ambiguous
everywhere), and rejected at parse with a tailored recognised-but-
unavailable message. Adoption by the tclcore string is model gives 8.6
users the dict class annotated and reserved (deliberately stricter than
real 8.6 for the di prefix - recorded as a user-sanctioned parity
exemption; full-word behaviour stays parity-true), plus an
i-string-is-dict documentation id generated from the static description.

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 2 days ago
parent
commit
07481e9a47
  1. 4
      GOALS.md
  2. 64
      goals/G-073-punkargs-unavailable-choices.md

4
GOALS.md

@ -285,3 +285,7 @@ Detail: goals/G-070-pure-tcl-tclparser.md
### G-072 [proposed] punk::args compound clause types: named alternates with per-element typing and per-alternate arity (try-class handlers)
Scope: src/modules/punk/args-999999.0a1.0.tm (type-expression parsing, clause allocation, synopsis/help renderers), src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm (::try as proving consumer; ::if/::switch as touched), src/tests/modules/punk/args/testsuites/args/
Detail: goals/G-072-punkargs-compound-clause-types.md
### G-073 [proposed] punk::args unavailable choices: displayed with notes and prefix-reserving, but rejected with a tailored message
Scope: src/modules/punk/args-999999.0a1.0.tm (spec key, choiceword_match pool, choices rendering in arg_error table+string renderers, validation message), src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm ('string is' forward-class adoption + per-class virtual id), src/tests/modules/punk/args/testsuites/args/ (new suite + tclcoreparity.test exemption)
Detail: goals/G-073-punkargs-unavailable-choices.md

64
goals/G-073-punkargs-unavailable-choices.md

@ -0,0 +1,64 @@
# G-073 punk::args unavailable choices: displayed with notes and prefix-reserving, but rejected with a tailored message
Status: proposed
Scope: src/modules/punk/args-999999.0a1.0.tm (spec key, choiceword_match pool, choices rendering in arg_error table+string renderers, validation message), src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm ('string is' forward-class adoption + per-class virtual id), src/tests/modules/punk/args/testsuites/args/ (new suite + tclcoreparity.test exemption)
Goal: an argument definition can declare choices that are recognised but not available in the current runtime (new key, candidate spelling -choiceunavailable <list>): they display among the choices with their ordinary -choicelabels notes (visually distinguished), participate in prefix disambiguation like -choiceprefixreservelist phantoms, and are rejected at parse with a tailored message identifying the unavailability rather than the generic listed-values error - adopted by the tclcore 'string is' model so that Tcl 8.6 shows the dict class annotated "(class not present in Tcl 8.6)", rejects 'string is dict' informatively, treats 'string is di' as ambiguous (deliberately stricter than real 8.6, preparing 8.6 users for 9.x where dict/digit/double collide), and documents 'i string is dict' via a per-class virtual id generated from the static description.
Acceptance: a definition using the new key renders unavailable entries distinguishably among the choices (mechanism decided in the work: dedicated group heading, dim/warn styling, or marker) with their -choicelabels notes, in both the table and string renderers, and synopsis choice-literal display excludes them; parse/parse_status reject an unavailable choice word - exact, or a unique prefix resolving only to it - with a message identifying it as recognised-but-unavailable rather than the generic choice error; unavailable entries participate in prefix disambiguation via choiceword_match (a prefix shared between an available and an unavailable choice is rejected as ambiguous) and are honoured identically by the punk::ns doc walk and the G-071 allocation screen (parity free via the shared resolver - no second matching rule); value-in-effect/goodarg highlighting never marks an unavailable entry; the tclcore 'string is' definition adopts the key on runtimes lacking known forward classes (dict on 8.6; the forward list is explicitly curated in the definition - unicode deliberately excluded as never-released), with a per-class virtual id generated from the static description so 'i string is dict' documents the class with its note on 8.6; the deliberate strictness divergence (real 8.6 accepts 'string is di' as digit; the model rejects it as ambiguous) is recorded in tclcoreparity.test as a user-sanctioned exemption class rather than silently special-cased, with full-word behaviour staying parity-true on both versions; definitions without the key behave unchanged (full punk::args and punk::ns suites pass).
## Context
User requirement 2026-07-12: forward compatibility for the 8.6-vs-9 'string is
dict' difference. The G-054 harvest (archived) makes the class choices accurate
per-runtime, so 8.6 neither displays nor mentions dict - but an 8.6 programmer
who habituates to 'string is di' (unique prefix of digit on 8.6) writes code that
breaks on 9.x where dict makes 'di' ambiguous. The requirement: 8.6 should SEE
dict (with an unavailability note - the description text with its "(class not
present in Tcl 8.6)" annotation already exists in the static
string_is_class_descriptions dict, it just never renders on 8.6), have dict
participate in prefix disambiguation (so 'di' is ambiguous on 8.6 too), and still
reject dict as an actual argument (real 8.6 rejects it).
Capability assessment (2026-07-12/13): the display layer is ready - choicelabels
notes, choicegroups headings and choiceinfo markers all exist; the gap is purely
that choices-cell membership implies parse acceptance under -choicerestricted 1.
The trie mechanics exist as -choiceprefixreservelist (phantom prefix-calculation
members, G-040), but reservelist phantoms deliberately do not display (the
punk::help c/to/tc phantoms must stay invisible) and reject with the generic
choice error. Hence a first-class concept: ~80% parse semantics, ~20% display,
riding the existing rendering pipeline.
## Approach
- New per-argument key (spelling decided in the work; candidate -choiceunavailable
<list>). Entries must not also appear in -choices/-choicegroups (definition
error). Notes come from ordinary -choicelabels entries keyed by the unavailable
word.
- choiceword_match: unavailable entries join the prefix pool like reservelist
members, but a match landing on one returns a distinct indication so validation
can emit the tailored message ("'dict' is a recognised choice but not available
in this runtime - see its note") instead of the generic listed-values error.
The shared-resolver principle keeps parse, parse_status, the G-071 allocation
screen and the (G-051) doc walk automatically consistent.
- Display: render unavailable entries among the choices with their notes,
visually distinguished (group heading vs dim/warn styling vs marker - decided
in the work with display-cost in mind); excluded from value-in-effect and
goodarg marking; excluded from synopsis choice-literal alternates.
- tclcore adoption: the 'string is' define-time harvest computes
unavailable = curated_forward_list - live_classes (forward list: dict;
unicode excluded). The per-class virtual id loop extends to unavailable
classes using the static description so 'i string is dict' works as
documentation on 8.6.
- Parity: tclcoreparity.test gains a recorded exemption class for
prefix-collision strictness (model stricter than real 8.6 for 'di'-shaped
prefixes by user direction); full-word probes stay strict parity.
## Notes
- Related: G-040 (choiceword_match single-resolver principle and the reservelist
precedent), G-051 (doc walk consumes the resolver - achieved 2026-07-13),
G-071 (allocation screen consumes the resolver - achieved 2026-07-12), G-054
archived (harvest + the parity pins this goal amends), G-055 (version-adaptive
definition technique; its workflow guidance gains the forward-class pattern
once proven here).
- The reject-message wording should steer the user: name the note/annotation and
the version boundary, not just "invalid".
Loading…
Cancel
Save