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.
 
 
 
 
 
 

12 KiB

G-167 punk::args version-delta availability: unavailable @forms for shape deltas, unavailable option names for flag deltas

Status: proposed Scope: src/modules/punk/args-999999.0a1.0.tm (form selection/candidacy availability filter + tailored raises, option-scan unavailable-name recognition, synopsis/table renderers - annotated form lines, unavailable option rows, automated other-shapes note, formstatus 'available' field, -form display-vs-parse split); src/modules/punk/ns-999999.0a1.0.tm (cmdhelp -return text form-section heading annotation; form narrowing inherits the availability filter); src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm (adoption on curated real 8.6-vs-9 deltas); src/tests/modules/punk/args/testsuites/args/ (new suite + formviability/tclcoreparity extensions) Goal: version/context deltas of a command's interface are declarable and honestly surfaced without delta computation, layered by delta kind: an @form may be declared unavailable - it participates in candidacy and diagnosis, displays annotated in synopsis/form listings, an input matching only unavailable forms earns a tailored rejection naming the form and its note, an input matching an available and an unavailable form resolves silently to the available one (the deliberate exception to no-silent-preference: documentation never competes with reality), and explicit -form selection displays but refuses parse; option NAMES may be declared unavailable (the G-073 mirror at the option-name level) - displayed among the options with their notes, recognised at option scan and rejected with a tailored message naming the flag; the default render stays on available forms, carrying an automated note that unavailable shapes exist (naming each form, its note, and how to view it - no computed delta); formstatus gains an additive 'available' field as the machine surface, and authoring guidance prescribes choices (-choiceunavailable) for subcommand-shaped deltas so the same concept never surfaces through two inconsistent paths. Acceptance: a fixture (and the tclcore adoption below) declaring an unavailable @form pins: an arglist matching ONLY unavailable forms raises a tailored formunavailable-class PUNKARGS VALIDATION error naming the form and its declared note; an arglist matching an available and an unavailable form parses via the available form with no multipleformmatches (the silent-preference exception pinned as deliberate); explicit -form selection of an unavailable form renders the usage display but parse refuses with the tailored error; a declared unavailable option NAME displays among the option rows with its note in both renderers, is recognised at option scan (exact, and per the option prefix rules) and rejected with a tailored optionunavailable-class error naming the flag, while genuinely unknown flags keep the existing unknown-option error; the default usage render shows the available form's argument table with annotated per-form synopsis lines and an automated note enumerating each unavailable form with its note and a navigation hint (no computed delta anywhere); cmdhelp -return text renders unavailable forms' argument sections under annotated headings; formstatus records carry the documented additive 'available' field with G-152's verdict semantics otherwise unchanged; formcheck reports no findings for the adopted era forms (availability-implied or -overlapallowed sanctioning); the tclcore model adopts both layers on curated real 8.6-vs-9 deltas (option-layer candidate: lsearch -stride, absent on 8.6; shape-delta candidate selected during the work) with tclcoreparity outcome parity maintained and any deliberate divergence recorded as a sanctioned exemption; authoring guidance (define -help and/or src/modules/AGENTS.md) prescribes -choiceunavailable for subcommand-shaped deltas; full punk/args and punk/ns suites pass apart from deliberately flipped pins.

Context

Design discussion 2026-08-05, immediately after G-073 achieved and G-166 drafted: how does the recognised-but-unavailable concept extend to a retired or added FLAG or POSITIONAL argument? Splicing per-argument unavailability into the machinery works only where a NAME is recognisable: option names are matched by name (with prefix/alias rules) exactly as choice words are, so a per-option mirror of G-073 keeps attribution pointed ("-stride is recognised but this runtime's lsearch has no such option"). A positional delta has no name to hang recognition on - allocation is positional, and what actually differs between runtimes is the command's SHAPE. Shape is the @form axis, and the multiform machinery already diagnoses per-form: candidacy parses every form, formstatus carries per-form verdicts, and the noformmatch renderer marks per-form lines after a stable anchor. Hence the layered model (user direction 2026-08-05): @form availability for shape deltas, per-option-name unavailability for flag deltas, one shared vocabulary.

Display decision (user direction 2026-08-05): the strict G-073 display-among-peers principle is deliberately relaxed for shape deltas. Named things keep per-name display (unavailable option rows render in the default argument table, as unavailable choices do), but an argument existing only in an unavailable form is NOT delta-merged into the default render - instead the render carries an AUTOMATED note that unavailable shapes exist. The note needs no delta computation: the renderer already holds the form set, each form's availability flag and its authored note, and the multiform synopsis block above the table already shows one (annotated) line per form. One generated line under the table names each unavailable form, its note, and how to view it (-form display, or -return text which renders every form's argument section). A computed form-delta upgrading that note is possible later - deliberately outside this goal's acceptance.

Silent-preference rationale: G-041's multiform contract raises multipleformmatches on several clean matches ("no silent preference - deliberate"). Availability introduces the first sanctioned exception: an unavailable form is documentation, not an alternative - preference between reality and documentation is not the ambiguity that rule protects against. The exception is confined to available-vs-unavailable pairs; ambiguity among available forms still raises.

The two-paths trap: a retired SUBCOMMAND could be modelled either as a leader's -choiceunavailable entry (G-073 treatment: choiceunavailable error, G-166 cmdinfo key, prefix habit-breaking via the shared pool) or as an unavailable form with a literal leader (formstatus treatment, no cross-form prefix pooling). Same user-level concept, two surfacing paths and two prefix behaviours - so this goal PRESCRIBES the authoring style: subcommand-shaped deltas use -choiceunavailable; forms are reserved for true shape deltas.

Approach

  • @form availability key (spelling decided in the work; candidates -unavailable 1 plus a note key, or a combined -availability value) with the note text authored per form (the harvest pattern: tclcore computes the flag per runtime at define time, as string_is_unavailable does for choices).
  • Era authoring is linear, not combinatorial: shared argument lines carry -form {era86 era90}, delta elements carry one form tag - one form per version era.
  • Engine sites: form_selection/candidacy availability filter (available beats unavailable silently; unavailable-only match raises the tailored class); rank_form_failures/noformmatch message annotation (G-152's per-form marking precedent); formstatus 'available' field (additive to the documented contract); -form explicit selection split (display renders, parse refuses).
  • Option layer: unavailable option names join option-name recognition (exact + prefix rules) with a tailored optionunavailable-class raise at the scan site; display rows + synopsis annotation; shares private::unavailable_choice_msg-style wording with G-073.
  • formcheck: era forms sanctioned via availability (or explicit -overlapallowed) so version-modelled commands do not light up findings.
  • Viability probe: unavailable forms participate in candidacy re-parses unchanged; their formstatus records carry available 0 alongside the verdict.
  • Consumers: cmdhelp narrowing inherits the filter (no ns-side re-derivation); G-044 completion must not complete toward unavailable forms/options - consume the formstatus field and option flags rather than re-deriving.

Notes

  • Related: G-073 (achieved 2026-08-05 - goals/archive/G-073-punkargs-unavailable-choices.md) - the foundation: concept, resolver indication, tailored-message wording and display vocabulary this goal extends to option names and forms.
  • Related: G-166 (proposed) - sibling surfacing goal: word-level cmdinfo availability key + cmdhelp marking. This goal's machine surface is the formstatus 'available' field; the two must share marking vocabulary and styling, and whichever lands first owns it. (G-149, formerly named here as a third owner candidate, achieved 2026-08-05 without introducing any form-line marking vocabulary - its hint labels are the LEFT label column of the Synopsis cell, composing freely with form-line annotations - so ownership is between this goal and G-166.)
  • Related: G-152 (achieved 2026-08-02 - goals/archive/G-152-punkargs-form-viability-verdict.md) - the formstatus consumer contract the 'available' field extends additively.
  • Related: G-041 (achieved - goals/archive/G-041-punkargs-form-matching.md) - the multiform candidacy machinery and the no-silent-preference rule this goal carves the documented availability exception into.
  • Related: G-074 (achieved - goals/archive/G-074-punkargs-multiform-ambiguity-lint.md) - formcheck and the -overlapallowed sanctioning vocabulary era forms consume.
  • Related: G-150 (achieved 2026-08-04 - goals/archive/G-150-cmdhelp-form-narrowing.md) - cmdhelp form narrowing inherits the availability filter via form selection.
  • Related: G-149 (achieved 2026-08-05 - goals/archive/G-149-punkargs-formhint-labels.md) - form-hint labels. Landed as a per-form template for the LEFT label column of the Synopsis header cell (%formindex%/%formname% substitution, suppressible) - it carries no form-line annotation styling, so this goal's annotated form lines (right column) compose with it without collision; an availability-aware hint template remains expressible by consumers.
  • Related: G-170 (achieved 2026-08-06 - goals/archive/G-170-launcher-help-depth.md) - back-pointer added at G-170's activation 2026-08-06 (activation-freshness survey), achieved the same day: the launcher's form-narrowing arm ('help <formname|ordinal>' via usage -form) consumes the same render path this goal's availability filter and annotated form lines flow through - launcher help inherits availability annotation automatically if this goal lands; no sequencing constraint.
  • Related: G-044 (completion/hinting) - downstream consumer of the formstatus field and option availability; G-055 - the tclcore workflow guidance gains the era-form/option pattern once proven here, as it gains the G-073 forward-class pattern.
  • Overlap survey 2026-08-05: goals_xref paths src/modules/punk/args-999999.0a1.0.tm src/modules/punk/ns-999999.0a1.0.tm - the punkargs family surfaced (G-044 G-050 G-053 G-056 G-069 G-072 G-075 G-083 G-084 G-088 G-149 G-151; ns-side G-052 G-085): besides those named above, the family entries are parser/spec/display mechanisms with no availability interaction - deliberate non-overlaps (G-050's validity marking is the nearest sibling surface; reuse its status-aware return conventions if it lands first). G-151 since achieved 2026-08-05 (goals/archive/G-151-punkargs-annotated-success-render.md) - its parse_report landing table is another argument-row surface this goal's unavailable marking would eventually render over.