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.
 
 
 
 
 
 

15 KiB

G-166 cmdinfo/cmdhelp surface recognised-but-unavailable landings distinctly

Status: achieved 2026-08-06 Scope: src/modules/punk/ns-999999.0a1.0.tm (cmdinfo result key, cmd_traverse landing attribution, cmdhelp render marking + advisory-parse presentation); src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm (virtual ids lead with the unavailability note on affected runtimes); src/tests/modules/punk/ns/testsuites/ns/ (cmdinfo/cmdhelp pins incl the deliberate key-list flip); src/tests/modules/punk/args/testsuites/args/tclcoreparity.test (8.6-arm pins) Goal: cmdinfo/cmdhelp surface recognised-but-unavailable landings: cmdinfo gains an availability key (empty, or the canonical unavailable word) populated wherever resolution addresses a -choiceunavailable word (exact space-form docid landings and the choice traverse), cmdhelp marks such subjects visibly in all return forms and its advisory parse no longer presents them as cleanly usable, the tclcore virtual ids lead with the unavailability note on affected runtimes, and the doc walk's treatment of a unique prefix landing on an unavailable name (currently: resolves no documentation) is decided and pinned within this goal - with the enacted G-073 follow-on items dispositioned accordingly. Acceptance: on a runtime where the tclcore model declares dict unavailable (Tcl 8.6), cmdinfo for 'string is dict' (direct and decomposed invocation forms) reports the new availability key carrying 'dict' while 'string is true' reports it empty, with cmdtype remaining 'doconly' for both (the command-kind axis is not overloaded); the key is present on every cmdinfo result and the cmdhelp.test cmdinfo key-list pin is flipped deliberately; cmdhelp output for an unavailable subject is visibly distinguished in table, text and dict return forms (the dict form carries the key; table/text carry a marking naming the unavailability), and an argument tail such as 'string is dict 5' no longer renders as a cleanly usable command line; the walk's unique-prefix landing on an unavailable name ('i string is dic' on 8.6) has a decided, pinned behaviour consistent with the marking (either resolving the virtual docid WITH the marking, or documented-conservative non-resolution); tclcore virtual ids for unavailable classes lead their rendered help with the unavailability statement on affected runtimes (first description line, not buried mid-prose) while modern runtimes render those ids unchanged; definitions without -choiceunavailable and existing cmdinfo/cmdhelp consumers behave unchanged (full punk/ns and punk/args suites green apart from deliberately flipped pins); the enacted G-073 Follow-on lines carry => goal G-166 dispositions.

Context

Found 2026-08-05 immediately after G-073 achieved (user probes): on Tcl 8.6, 'i ::tcl::string::is dict' (unavailable class) and 'i ::tcl::string::is true' (real class) produce indistinguishable machine shapes - cmdinfo reports cmdtype 'doconly' with identical key sets for both, and cmdhelp's advisory parse of an argument tail ('string is dict 5') succeeds against the virtual id so the render presents the unavailable class exactly like a usable one. The only difference is the "(class not present in Tcl 8.6)" sentence mid-way through the description prose.

Half of this is G-073's intent: documentation REACHABILITY for unavailable words (via exact space-form virtual docids) is an acceptance requirement, and doc addressing has always been deliberately broader than parse acceptance (per-class ids like 'string is true' document argument words that were never subcommands). The INDISTINGUISHABILITY is emergent, not specified: nothing structural tells a consumer - human or machine - that the documented word is rejected by this runtime's parse.

Axis decision (assessed 2026-08-05, to be confirmed in the work): a NEW cmdinfo key, not a cmdtype refinement such as 'doconly_unavailable'. cmdtype answers "what kind of executable thing did resolution land on"; availability is a property of the resolved word at its level. Today they co-occur with doconly only incidentally (unavailable entries never have real commands behind them), and overloading the value breaks consumers switching on cmdtype eq "doconly". The two-axes distinction is recorded in the cmd_traverse choice-traverse comment (ns 0.9.3).

Approach

  • New cmdinfo result key (spelling decided in the work; candidate 'unavailable' - empty string normally, the canonical unavailable word when the resolution addressed one). Population is nearly free: the choice traverse already holds the resolver's matchinfo (its 'unavailable' key, punk::args 0.16.0), and the exact space-form id landing branches can consult the level's choices-bearing arginfo the same way the space-form prefix-parity branch (G-051, achieved 2026-07-13 - see goals/archive/G-051-cmdinfo-pseudo-and-prefix.md) already does (Dict_getdef -choiceunavailable + membership check).
  • cmdhelp derives the render marking from the same data: a visible unavailability statement in table/text forms (warn styling; placement decided in the work - title line marker and/or a leading line), the key in -return dict, and the advisory-parse presentation adjusted so an accepted parse against an unavailable subject's virtual id is not shown as a cleanly usable command line.
  • tclcore generator: on runtimes where a forward class is unavailable, the per-class virtual id's help LEADS with the unavailability statement (the static description follows); modern runtimes generate the id unchanged.
  • Prefix-landing decision: either the walk resolves a unique prefix landing to the virtual docid and relies on the marking to carry the rejection story (parse gives the tailored "resolves to 'dict'" report for the same word), or the current conservative non-resolution is kept and pinned as deliberate. Decided in the work; the G-073 follow-on line flips accordingly.

Notes

  • Related: G-073 (achieved 2026-08-05, archived - goals/archive/G-073-punkargs-unavailable-choices.md) - this goal enacts its open follow-on on doc-walk prefix landings and resolves the indistinguishability its acceptance did not specify; the -choiceunavailable key, resolver indication and tailored parse rejection this goal consumes all landed there (punk::args 0.16.0, tclcore moduledoc 0.4.0, ns 0.9.3).
  • Related: G-050 (punk::ns::synopsis argument-validity marking and status-aware returns) - sibling display-marking surface; whichever lands second should reuse the first's marking vocabulary/styling decisions.
  • Related: G-044 (completion/hinting) - a future consumer: completion over choices should be able to exclude or annotate unavailable words from the same data rather than re-deriving.
  • Related: G-055 (tclcore moduledoc regeneration workflow) - the tclcore virtual-id leading-note change lands in the moduledoc G-055's workflow governs; its guidance gains the forward-class pattern per the G-073 follow-on already dispositioned => goal G-055.
  • Overlap survey 2026-08-05: goals_xref paths src/modules/punk/ns-999999.0a1.0.tm
    • G-044/G-050/G-052/G-075/G-085 surfaced; G-052 (TclOO autodef) and G-085 (cmdtrace) are same-file unrelated concerns; G-075 ((package) ids) is sibling docid territory with no word-availability interaction - deliberate non-overlap.
  • Related: G-167 (proposed) - back-pointer added at activation 2026-08-06 (activation-freshness survey, the top-ranked pair at 2.21; G-167 already points here): its @form/option-name availability layers are the shape-delta sibling of this goal's word-level availability. Marking-vocabulary ownership is settled by this goal landing first - G-167's form/option annotations reuse the wording established here ("is a recognised name here, but is not available in this runtime/context", shared with punk::args' private::unavailable_choice_msg) rather than minting a second phrasing.
  • Activation-freshness survey 2026-08-06 (goals_xref score G-166): no other material relationship found. The remaining unlinked pairs are lexical - G-072 / G-083 / G-084 share the tclcore moduledoc and tclcoreparity.test paths as punk::args definition-authoring goals with no word-availability interaction (deliberate non-overlap, as recorded for G-075 above); G-047 / G-066 / G-063 / G-163 / G-056 / G-016 / G-048 / G-158 / G-110 / G-148 / G-061 / G-069 score on shared vocabulary only, with zero path intersection.

Progress

  • 2026-08-06 (activated and achieved, one session): punk::ns 0.10.0 + punk::args::moduledoc::tclcore 0.4.1 (source modules); punkshell 0.57.0. Key spelling as proposed: 'unavailable' - matching punk::args' choiceword_match result-key name so the two layers share one word. AXIS DECISION CONFIRMED as drafted: a new cmdinfo key, not a cmdtype refinement. cmdtype still answers what kind of executable thing resolution landed on ('string is dict' and 'string is true' both stay 'doconly' on 8.6); 'unavailable' answers whether the resolved word is selectable here. The key is present on EVERY cmdinfo result (empty when not applicable), so consumers never have to test for its existence. Mechanism: cmd_traverse's yielded/returned records gained a sixth element carrying the level's availability attribution; cmdinfo keeps the FINAL record's value (the availability of the landing it reports). Population is as cheap as predicted - the level's choices-bearing first leader is resolved once per level with punk::args::choiceword_match and BOTH the exact space-form landing and the prefix retry consult that one result (the G-051 branch was restructured rather than duplicated).
  • PREFIX-LANDING DECISION (enacting the G-073 follow-on): a unique prefix landing on an unavailable name RESOLVES that name's virtual docid, attributed
    • the conservative non-resolution was not kept. Rationale recorded at the code site: documentation ADDRESSING and word AVAILABILITY are separate axes, which is this goal's whole thesis; encoding availability as resolve-vs-don't-resolve conflated them and made addressing inconsistent ('i string is tr' resolved but 'i string is dic' did not, while exact 'string is true' and 'string is dict' both did). Now every form of address that names a documented word resolves it, and the availability key plus cmdhelp's marking carry the rejection story parse reports for the same word. The choice traverse's G-040 parse-parity claim is deliberately untouched: an unavailable word still identifies no SUBCOMMAND there - it is only attributed (the path taken when the unavailable name has no space-form virtual docid).
  • cmdhelp marking: one wording, one home (punk::ns::_cmdhelp_unavailable_marking), used by every return form - the -return dict form carries the key, table/string render the message below the usage under the non-info scheme, -return text leads with an 'UNAVAILABLE:' line (it is the machine/LLM-facing surface). The marking takes precedence over BOTH the ok-parse info render and any parse failure message: the subject not existing here is the more fundamental report, and it is the one a parse against a virtual id cannot make - which is exactly why 'i string is dict 5' previously rendered info-scheme-clean (the advisory parse of '5' SUCCEEDS against the virtual id). The parse status is still passed through, so argument positions keep their marking under the non-info scheme. Wording mirrors punk::args' private::unavailable_choice_msg; the runtime-specific WHY is deliberately not repeated in punk::ns - it belongs to the definition, and the subject's own help now leads with it.
  • tclcore: the per-class virtual id of a forward class this runtime lacks leads its help with the unavailability statement (naming the runtime patchlevel and the rejected call shape), a blank line, then the unchanged static description. Runtimes where the class is live generate the id unchanged - the unavailable set is empty there, so the arm is unreachable rather than merely inactive.
  • Verification (runtests.tcl, three runtimes): punk/ns cmdflow.test 25/25 and cmdhelp.test 50/50 on native Tcl 8.6.10 (bin/runtime/win32-ix86/tclsh8.6.10-luck-zip.exe - THE AFFECTED ARM, unavailable={dict}), 8.7a6 (c:/tcl87) and 9.0.5; full punk/ns subtree 125 tests green on 9.0.5, and on 8.6/8.7 green apart from the two PRE-EXISTING nsprimitives failures (nseval_ifexists_weird, nstree_raw_pins - the weird-namespace ':::' resolution divergence that 9.x does not share), confirmed identical with the module changes stashed on BOTH runtimes. Full punk/args subtree 341 total / 338 passed / 3 intended skips / 0 failed on 8.6.10, 8.7a6 and 9.0.5. Broad regression sweep: the whole src/tests/modules/*** tree on 9.0.5 - 1257 tests, 108 files, 0 failed. New pins: cmdflow.test flowunavail (per-choice virtual docids) + flowunavail_nodoc (attribution without addressing) fixtures with 5 tests (key always present and empty by default; exact landing attributed with cmdtype unchanged; the prefix-landing decision pinned against parse's choiceunavailable rejection; choice-traverse attribution; attribution surviving an argument tail); cmdhelp.test helpstrua fixture with 3 render tests (dict key, argument-tail-not-cleanly-usable incl the info-scheme suppression, string+text marking) plus 2 tclcore-gated real-world tests ('string is dict' vs 'string is true' direct AND decomposed forms, and the 'i string is dict 5' arm) - all live-derived so the modern arm asserts the same shapes with an empty key; tclcoreparity.test gains the virtual-id leading-note pin. The two deliberate key-list flips landed as drafted (cmdhelp_cmdinfo_result_shape, cmdhelp_return_dict_valid).
  • Consumer audit: every in-tree cmdinfo consumer reads named keys via 'dict get' (punk::ns synopsis/eg/forms/corp/cmdtrace/cmdhelp, punk::args ensemble_subcommands_definition and its usage resolution, scriptlib/developer/whatis.tcl and nslist.tcl) - none positional, so the added key is inert for all of them.

Follow-ons

Follow-on: punk::ns::synopsis does not surface the availability axis - 's string is dict' on 8.6 renders the synopsis of a subject the runtime cannot run, unmarked (deliberately out of scope: the synopsis marking surface is G-050's, and this goal established the vocabulary G-050 reuses) => goal G-050 Follow-on: completion/hinting should consume the cmdinfo availability key (and the -choiceunavailable pool behind it) rather than re-deriving, so unavailable words display-but-do-not-complete => goal G-044 Follow-on: the tclcore leading-note pattern (conditional per-runtime help prefix on a forward class's virtual id) belongs in the moduledoc authoring workflow guidance alongside the G-073 forward-class pattern already dispositioned there => goal G-055 Follow-on: G-167's @form/option-name availability surfacing reuses the marking vocabulary this goal established rather than minting a second phrasing => goal G-167