From 8fa716b62b8420264411c23d236c215719f152a2 Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Sat, 8 Aug 2026 03:50:40 +1000 Subject: [PATCH] G-176 achieved: override hints + 'package epoch' documented via stack-tied doc block (punk::ns 0.11.0, punk::libunknown 0.3.1; project 0.65.0) Increment 4 (the final increment) + the achieved flip. punk::ns 0.11.0: cmdinfo gains an 'overridden' result key - a second axis beside cmdtype/unavailable (the G-166 pattern) reporting the LIVE commandstack override state of the base command: one {renamer docids } dict per stack record (bottom-up), docids being the punk::args ids of doc blocks the record attached via 'rename_command -punkargs' (derived with punk::args::rawdef_id). Guarded live query - no hard commandstack dependency, empty when commandstack is not loaded, never cached so it is correct as stacks change. cmdhelp surfaces it: the table/string renders lead with a plain "note: '' is currently overridden/extended via commandstack by: (override-attached docs: '')" line, -return text leads with an OVERRIDDEN: line (below UNAVAILABLE when both apply), -return dict carries the key on all return shapes incl the undocumented fallback. punk::libunknown 0.3.1 (renamed from 0.3.0): the 'package epoch' subcommand is now DOCUMENTED - a substitution-free doc block with the space-form id {::package epoch} rides the override's commandstack record via -punkargs: mirrored for lazy pickup when punk::args loads after init (normal early boot), defined immediately when punk::args is present, and removed with the record by any removal path. 'i package epoch' renders real usage (all six grammar forms) - the doc gap that motivated the whole arc, retired. init's require tightened to 'commandstack 0.8-': a pre-mechanism stable copy fails pointedly at init instead of mid-call with a usage error (found via shadowing.test, whose require-based children needed 'package prefer latest' - the default stable preference picks a stale stable bootsupport commandstack over the alpha-versioned dev copy). End-to-end verified: 'i package epoch' renders the epoch doc; 'i package' leads with the note naming punk::libunknown and '::package epoch'; -return text/-return dict carry OVERRIDDEN:/the structured key; restore_original ::package removes doc and note. Tests: cmdhelp.test gains 2 hint pins (documented-command note incl docs clause + dict axis; doc-less-proc autodef render leading with the note, OVERRIDDEN: text lead, note clearing on unwind) and its two key-list pins (cmdhelp_cmdinfo_result_shape, cmdhelp_return_dict_valid) flip deliberately with the new key - exactly as they did for G-166's 'unavailable'. packageoverride.test gains the flagship pending-path pin (epoch doc mirrored pre-punk::args in path-cleared children, lazily defined on punk::args arrival, removed on unwind) and its pko_probe injects ::PKO_SRCMODULES. shadowing.test children set 'package prefer latest'. src/tests/modules/AGENTS.md punk/ns + punk/libunknown bullets updated. G-176 flipped ACHIEVED 2026-08-08: every acceptance clause met across the four increments (characterise -> migrate -> -punkargs mechanism -> hint + flagship docs). Detail file archived to goals/archive/G-176-commandstack-doc-integration.md with its two boot-site Follow-ons kept open (commandstack pre-sourcing at the libunknown-style boot sites; make.tcl skip-guard modernization - due by the 0.3.x/0.8.0 bootsupport promotion). GOALS.md entry removed; GOALS-archive.md record added; the one tree reference (packageoverride.test header) swept to the archive path. Project 0.64.0 -> 0.65.0 + CHANGELOG. Suites: libunknown+ns+commandstack+loadedlib 216/216; full modules tree 1354 total / 1343 pass / 11 constraint-skipped / 0 fail (zig-built tclsh90s 9.0.5); testbody_lint 1707 clean; goals_lint clean (79 active-index / 97 archived); make.tcl projectversion consistency OK. Claude-Session: https://claude.ai/code/session_01QgaxV27VZkmEec7oNbEVFc Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com --- CHANGELOG.md | 15 +++ GOALS-archive.md | 4 + GOALS.md | 4 - .../G-176-commandstack-doc-integration.md | 29 +++++- punkproject.toml | 2 +- ...ibunknown-0.3.0.tm => libunknown-0.3.1.tm} | 67 ++++++++++++- src/modules/punk/ns-999999.0a1.0.tm | 95 +++++++++++++++++-- src/modules/punk/ns-buildversion.txt | 3 +- src/tests/modules/AGENTS.md | 4 +- .../testsuites/discovery/packageoverride.test | 30 +++++- .../testsuites/shadowing/shadowing.test | 9 +- .../punk/ns/testsuites/ns/cmdhelp.test | 72 +++++++++++++- 12 files changed, 309 insertions(+), 25 deletions(-) rename goals/{ => archive}/G-176-commandstack-doc-integration.md (87%) rename src/modules/punk/{libunknown-0.3.0.tm => libunknown-0.3.1.tm} (96%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fcc7c8f..d3a0f767 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ The latest `## [X.Y.Z]` header must match the `version` field in `punkproject.to Entries are newest-first; one bullet per notable change. See the root `AGENTS.md` "Project Versioning" section for the bump policy. +## [0.65.0] - 2026-08-08 + +- `package epoch` is now documented, and help output flags live command + overrides (G-176 increment 4). `i package epoch` renders real usage: the + doc block travels WITH punk::libunknown's ::package override (attached + to its commandstack record via `rename_command -punkargs`, removed with + it if the override is unwound; punk::libunknown 0.3.1 - init now + requires commandstack 0.8+). `punk::ns::cmdinfo` gains an `overridden` + result key (a second axis in the G-166 style: live commandstack override + state of the base command with renamers and any attached doc ids) and + `cmdhelp`/`i` leads its renders with a "note: '' is currently + overridden/extended via commandstack by: ..." line - `-return text` + leads with `OVERRIDDEN:`, `-return dict` carries the structured key. + (punk::ns 0.11.0) + ## [0.64.0] - 2026-08-08 - `commandstack` 0.8.0 (G-176 increment 3): `rename_command` accepts a new diff --git a/GOALS-archive.md b/GOALS-archive.md index 75e7cbfb..443f22ee 100644 --- a/GOALS-archive.md +++ b/GOALS-archive.md @@ -20,6 +20,10 @@ Do not edit archived records here except to fix a broken path. Archived detail f ## Archived goals +### G-176 [achieved 2026-08-08] commandstack doc integration - stack-tied overrider argdocs, override hints, and the libunknown package-override migration → detail: goals/archive/G-176-commandstack-doc-integration.md +Scope: src/modules/commandstack-999999.0a1.0.tm (rename_command -punkargs option, stackdocs pending-docs namespace, remove_rename detach hook, help/argdoc how-to); src/modules/punk/libunknown-0.3.1.tm (package-override migration to commandstack + flagship epoch doc - fixed-version file, renamed 0.2.4 -> 0.3.0 -> 0.3.1 across increments 2 and 4); src/modules/punk/ns-999999.0a1.0.tm (cmdhelp/cmdinfo override-in-place hint); src/tests/modules/punk/libunknown/testsuites/discovery/ (override characterisation arms - discovery.test extensions or a sibling packageoverride.test); src/tests/modules/commandstack/testsuites/commandstack/commandstack.test (-punkargs lifecycle pins); src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test (override-hint pins) +Acceptance: characterisation tests of the CURRENT libunknown override landed before any behaviour change and stayed green byte-identically through the migration (epoch single-arg/indexed forms + error arms, the forget arm, abbreviations, delegation, re-init guard, packagepreference interop in both install orders) with only marked install-shape pins flipping at the migration; libunknown installs its ::package override via commandstack::rename_command with a stack-query guard and no ::package:: residue; rename_command -punkargs docs are queryable while the record lives (incl renames performed BEFORE punk::args loads - pinned in a bare child) and are removed by remove_rename/pop_rename/remove_renamer/restore_original alike; cmdhelp shows an override-in-place notice (cmdinfo 'overridden' second-axis key, no hard commandstack dependency) enumerating record-attached doc ids; 'i package epoch' resolves the libunknown-attached doc and the how-to is described in commandstack::help + the rename_command argdoc; punk/libunknown, commandstack, punk/ns and punk/packagepreference suites pass under the canonical runtests interpreter. + ### G-084 [achieved 2026-08-07] punk::args -parsekey completeness: cross-member -multiple collection, leaders/values support, defined default precedence → detail: goals/archive/G-084-punkargs-parsekey-completeness.md 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) 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. diff --git a/GOALS.md b/GOALS.md index 52ec5acf..554d02b0 100644 --- a/GOALS.md +++ b/GOALS.md @@ -404,7 +404,3 @@ Detail: goals/G-174-cmdtraverse-word-accounting.md Scope: src/modules/punk/args-999999.0a1.0.tm (resolve @dynamic cache-skip, by-id entry points get_spec/parse_status/arg_error/synopsis); src/modules/punk/ns-999999.0a1.0.tm (cmdhelp render pipeline - the four independent by-id fetches); src/tests/modules/punk/args/testsuites/args/dynamic.test + src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test (once-per-render counter pins + cross-render freshness pins, if the landing arm is taken) Detail: goals/G-175-punkargs-dynamic-resolve-multiplicity.md -### G-176 [active] commandstack doc integration - stack-tied overrider argdocs, override hints, and the libunknown package-override migration -Scope: src/modules/commandstack-999999.0a1.0.tm (rename_command -punkargs option, stackdocs pending-docs namespace, remove_rename detach hook, help/argdoc how-to); src/modules/punk/libunknown-0.3.0.tm (package-override migration to commandstack - fixed-version file, renamed from libunknown-0.2.4.tm at increment 2); src/modules/punk/ns-999999.0a1.0.tm (cmdhelp/cmdinfo override-in-place hint); src/tests/modules/punk/libunknown/testsuites/discovery/ (override characterisation arms - discovery.test extensions or a sibling packageoverride.test); src/tests/modules/commandstack/testsuites/commandstack/commandstack.test (-punkargs lifecycle pins); src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test (override-hint pins) -Detail: goals/G-176-commandstack-doc-integration.md - diff --git a/goals/G-176-commandstack-doc-integration.md b/goals/archive/G-176-commandstack-doc-integration.md similarity index 87% rename from goals/G-176-commandstack-doc-integration.md rename to goals/archive/G-176-commandstack-doc-integration.md index fa3558cb..eefdae6c 100644 --- a/goals/G-176-commandstack-doc-integration.md +++ b/goals/archive/G-176-commandstack-doc-integration.md @@ -1,7 +1,7 @@ # G-176 commandstack doc integration - stack-tied overrider argdocs, override hints, and the libunknown package-override migration -Status: active -Scope: src/modules/commandstack-999999.0a1.0.tm (rename_command -punkargs option, stackdocs pending-docs namespace, remove_rename detach hook, help/argdoc how-to); src/modules/punk/libunknown-0.3.0.tm (package-override migration to commandstack - fixed-version file, renamed from libunknown-0.2.4.tm at increment 2); src/modules/punk/ns-999999.0a1.0.tm (cmdhelp/cmdinfo override-in-place hint); src/tests/modules/punk/libunknown/testsuites/discovery/ (override characterisation arms - discovery.test extensions or a sibling packageoverride.test); src/tests/modules/commandstack/testsuites/commandstack/commandstack.test (-punkargs lifecycle pins); src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test (override-hint pins) +Status: achieved 2026-08-08 +Scope: src/modules/commandstack-999999.0a1.0.tm (rename_command -punkargs option, stackdocs pending-docs namespace, remove_rename detach hook, help/argdoc how-to); src/modules/punk/libunknown-0.3.1.tm (package-override migration to commandstack + flagship epoch doc - fixed-version file, renamed 0.2.4 -> 0.3.0 -> 0.3.1 across increments 2 and 4); src/modules/punk/ns-999999.0a1.0.tm (cmdhelp/cmdinfo override-in-place hint); src/tests/modules/punk/libunknown/testsuites/discovery/ (override characterisation arms - discovery.test extensions or a sibling packageoverride.test); src/tests/modules/commandstack/testsuites/commandstack/commandstack.test (-punkargs lifecycle pins); src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test (override-hint pins) Goal: a command overrider using commandstack can attach punk::args doc blocks that live and die with its stack entry (supplied at rename_command time, active whether or not punk::args is loaded yet, removed by every removal path), cmdhelp renders an override-in-place hint on any commandstack-managed command's existing documentation (naming the renamers and any doc ids their records added), and the punk::libunknown ::package override - the flagship consumer, whose 'package epoch' subcommand gains real documentation this way - is migrated onto commandstack so both live ::package overrides share one managed stack. Acceptance: characterisation tests of the CURRENT libunknown override land before any behaviour change and stay green byte-identically through the migration (the epoch tm/pkg single-arg forms, indexed ?keys...? queries and their error arms, the forget arm incl the tcl/Tcl/tcl::oo/tk denial and epoch-scripts pruning, abbreviation acceptance (ep/epo/epoc, fo/for/forge), a delegation pass-through pin, the re-init guard, and a packagepreference interop child covering both install orders) with only explicitly marked install-shape pins (::package import link, ::package:: parked name) flipping when the migration lands; libunknown installs its ::package override via commandstack::rename_command with a stack-query install guard mirroring punk::packagepreference and no ::package:: residue; commandstack::rename_command accepts a -punkargs list of definitionlists whose docs are queryable while the record lives - including renames performed BEFORE punk::args loads (pinned in a bare child that loads punk::args afterwards) - and are removed by remove_rename, pop_rename, remove_renamer and restore_original alike (record key appended per the key-order contract, reload-contract guard on new state); punk::ns::cmdhelp shows an override-in-place notice for a commandstack-managed command (cmdinfo carrying it as a second-axis key in the G-166 (achieved, see goals/archive/G-166-cmdinfo-unavailable-surfacing.md) style) without a hard commandstack dependency, enumerating record-attached doc ids; 'i package epoch' resolves the libunknown-attached doc in a punk shell and the mechanism how-to is described in commandstack::help and the rename_command argdoc; punk/libunknown, commandstack, punk/ns and punk/packagepreference suites pass under the canonical runtests interpreter. @@ -170,6 +170,31 @@ Increments land as separate commits, each leaving all suites green: updated to the generalised usage/misplacement wording. Suite 46/46. Project 0.64.0. +- Increment 4 (override hint + flagship docs) landed 2026-08-08: punk::ns 0.11.0 + + punk::libunknown 0.3.1 (file renamed from 0.3.0). cmdinfo gains the + 'overridden' second-axis key (G-166 style): live guarded + commandstack::get_stack query on the base command - one {renamer docids} + dict per record, docids derived with punk::args::rawdef_id from the record's + -punkargs deflists; empty when commandstack absent; never cached. cmdhelp + leads table/string renders with the plain "note: '' is currently + overridden/extended via commandstack by: (override-attached docs: + ...)" line, -return text leads with OVERRIDDEN: (below UNAVAILABLE when both + apply), -return dict carries the key on all return shapes, and the + undocumented fallback carries the note. libunknown attaches the + {::package epoch} doc block via -punkargs (substitution-free deflist; init's + require tightened to 'commandstack 0.8-' so a pre-mechanism stable copy + fails pointedly at init rather than mid-call - found via shadowing.test, + whose require-based children needed 'package prefer latest': stable + preference picks a stale stable bootsupport commandstack over the alpha dev + copy). Verified end-to-end: 'i package epoch' renders the real epoch usage + (the arc's motivating gap, retired), 'i package' leads with the note naming + punk::libunknown and '::package epoch', restore_original removes doc and + note. cmdhelp.test: 2 new hint pins + the two key-list pins flipped again + (as with G-166); packageoverride.test: flagship pending-path pin (doc + mirrored pre-punk::args in path-cleared children, lazily defined, removed on + unwind). Suites: libunknown+ns+commandstack+loadedlib 216/216. Project + 0.65.0. + ## Follow-ons - Boot-site commandstack pre-sourcing (out of the current Scope - a Scope diff --git a/punkproject.toml b/punkproject.toml index 22d82247..b0d85c2c 100644 --- a/punkproject.toml +++ b/punkproject.toml @@ -1,6 +1,6 @@ [project] name = "punkshell" -version = "0.64.0" +version = "0.65.0" license = "BSD-2-Clause" url = "https://www.gitea1.intx.com.au/jn/punkshell" #packager: declared identity for published artifacts (declarative, not proof - diff --git a/src/modules/punk/libunknown-0.3.0.tm b/src/modules/punk/libunknown-0.3.1.tm similarity index 96% rename from src/modules/punk/libunknown-0.3.0.tm rename to src/modules/punk/libunknown-0.3.1.tm index e554d5ad..bb2d4a7b 100644 --- a/src/modules/punk/libunknown-0.3.0.tm +++ b/src/modules/punk/libunknown-0.3.1.tm @@ -7,7 +7,7 @@ # (C) 2025 # # @@ Meta Begin -# Application punk::libunknown 0.3.0 +# Application punk::libunknown 0.3.1 # Meta platform tcl # Meta license MIT # @@ Meta End @@ -18,6 +18,16 @@ # from src/modules/AGENTS.md "Versioning And Releases" - bumping means # renaming the file AND updating the Meta line above, the manpage_begin line # below and the provide-block version, then appending a line here): +#0.3.1 - G-176 increment 4: the 'package epoch' subcommand is now DOCUMENTED - +# a punk::args doc block with the space-form id {::package epoch} is +# attached to the override's commandstack record via the new +# 'rename_command -punkargs' mechanism (commandstack 0.8.0). The doc +# lives and dies with the override: mirrored for lazy pickup when +# punk::args loads after init (normal early boot), defined immediately +# when punk::args is already present, and removed by any commandstack +# removal path (e.g restore_original ::package). 'i package epoch' in a +# punk shell now renders real usage instead of falling back to the +# parent ::package render. #0.3.0 - G-176 increment 2: the ::package override installs via # commandstack::rename_command (renamer punk::libunknown) instead of the # former 'rename ::package ::package::' + namespace-import mechanism, so @@ -88,7 +98,7 @@ # doctools header # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ #*** !doctools -#[manpage_begin punkshell_module_punk::libunknown 0 0.3.0] +#[manpage_begin punkshell_module_punk::libunknown 0 0.3.1] #[copyright "2025"] #[titledesc {Module API}] [comment {-- Name section and table of contents description --}] #[moddesc {-}] [comment {-- Description at end of page heading --}] @@ -1594,7 +1604,11 @@ tcl::namespace::eval ::punk::libunknown { #A no-op when already provided (e.g whenever punk::packagepreference::install #ran first, or a boot context pre-sourced it); otherwise resolves via the #standard package machinery - commandstack is lean and dependency-free. - package require commandstack + #0.8- floor: rename_command -punkargs (the attached 'package epoch' doc) + #arrived at commandstack 0.8.0 - an older stable copy must fail HERE with a + #version message, not mid-call with a usage error (with the default stable + #preference an old stable copy would otherwise beat an alpha dev copy). + package require commandstack 0.8- #re-entry guard: our override record on the ::package commandstack foreach stackrecord [commandstack::get_stack ::package] { if {[dict get $stackrecord renamer] eq "punk::libunknown"} { @@ -1713,7 +1727,50 @@ tcl::namespace::eval ::punk::libunknown { #::package overrides (this + punk::packagepreference's) share one managed #stack whatever the install order. The body runs at :: - namespace-relative #references must be fully qualified. - set stackrecord [commandstack::rename_command -renamer punk::libunknown package {args} { + #The added 'epoch' subcommand's documentation travels WITH the override: + #attached to the stack record via -punkargs, live while the record is on + #the stack, removed with it by any commandstack removal path. The deflist + #stays free of dollar-brace tstr substitutions - when punk::args loads + #after us (normal early boot) it is lazily evaluated in the registered + #::commandstack::stackdocs namespace, not in ours. + set epochdoc {@id -id {::package epoch} + @cmd -name "punk::libunknown override: package epoch"\ + -summary\ + "package/module discovery epoch introspection."\ + -help\ + "Introspect (or manually advance) the punk::libunknown discovery epoch + counters that key the package/module scan caches. Added by the + ::package override that punk::libunknown::init installs - this + subcommand (and this documentation) is present only while that + override is live. + + Forms: + package epoch - dict {tm pkg } - the current + epoch counters + package epoch tm|pkg - one-entry dict keyed by the current + epoch: { } + package epoch incr - increment BOTH the tm and pkg epochs, + invalidating the scan caches (e.g after + adding a .tm file to an already-scanned + directory) + package epoch tm|pkg incr - increment one epoch (also accepted as: + package epoch incr tm|pkg) + package epoch tm|pkg - the epochinfo record for epoch + (error for an unknown ) + package epoch tm|pkg ... + - walk keys into that epochinfo record + (an unknown key errors naming the + available toplevel keys) + + The epochs also advance automatically via traces on ::auto_path and + ::tcl::tm::paths." + @values -min 0 -max -1 + which -type string -optional 1 -choices {tm pkg incr} -choicerestricted 0 -help\ + "epoch selector (tm or pkg), or incr to advance both epochs." + arg -type any -optional 1 -multiple 1 -help\ + "index (or incr) and optional key path - see the forms above." + } + set stackrecord [commandstack::rename_command -renamer punk::libunknown -punkargs [list [list $epochdoc]] package {args} { #::package override installed by punk::libunknown::init (epoch/forget arms; all else delegates) switch -- [lindex $args 0] { fo - for - forge - forget { @@ -2204,7 +2261,7 @@ namespace eval ::punk::args::register { package provide punk::libunknown [tcl::namespace::eval ::punk::libunknown { variable pkg punk::libunknown variable version - set version 0.3.0 + set version 0.3.1 }] return diff --git a/src/modules/punk/ns-999999.0a1.0.tm b/src/modules/punk/ns-999999.0a1.0.tm index 26818649..f6b35e3f 100644 --- a/src/modules/punk/ns-999999.0a1.0.tm +++ b/src/modules/punk/ns-999999.0a1.0.tm @@ -4667,6 +4667,16 @@ y" {return quirkykeyscript} Non-empty means the landing is documentation the current runtime cannot actually run - e.g 'string is dict' on Tcl 8.6. + overridden - (G-176) empty list, or one entry per LIVE + commandstack rename record on the BASE command + (bottom-up): a dict {renamer docids + } where docids are the punk::args ids of + any doc blocks the record attached via + 'rename_command -punkargs'. A second axis like + 'unavailable': it describes the live override + state of the command, not the kind of thing + resolution landed on. Always empty when the + commandstack package is not loaded. args_resolved - the command words consumed by resolution args_remaining- the trailing words resolution did not consume docid - the punk::args definition id documenting the landing @@ -4740,7 +4750,38 @@ y" {return quirkykeyscript} #Overloading cmdtype (e.g a 'doconly_unavailable' value) would break every #consumer switching on cmdtype eq "doconly", and the two only co-occur #incidentally (an unavailable name has no real command behind it today). - return [list origin $origin cmdtype $cmdtype unavailable $unavailable args_resolved [list [lindex $commands 0] {*}$consumed_args] args_remaining $remainingargs docid $docid stack $stack] + #G-176: 'overridden' is a further second-axis key - the live commandstack + #override state of the BASE command word, queried at call time (never + #cached) so it is correct by construction as stacks change. + return [list origin $origin cmdtype $cmdtype unavailable $unavailable overridden [_cmdinfo_overridden [lindex $commands 0]] args_resolved [list [lindex $commands 0] {*}$consumed_args] args_remaining $remainingargs docid $docid stack $stack] + } + #G-176: live commandstack override records for a command - one dict + #{renamer docids } per record, bottom-up. docids are the + #punk::args ids of doc blocks the record attached via 'rename_command + #-punkargs' (derived with punk::args::rawdef_id - deflists whose id cannot + #be derived are simply not listed). Guarded: empty list when the + #commandstack package is not loaded - no hard dependency. + proc _cmdinfo_overridden {command} { + if {![llength [info commands ::commandstack::get_stack]]} { + return [list] + } + if {[catch {commandstack::get_stack $command} stackrecords]} { + return [list] + } + set overridden [list] + foreach crec $stackrecords { + if {![dict exists $crec renamer]} {continue} + set docids [list] + if {[dict exists $crec punkargs] && [llength [info commands ::punk::args::rawdef_id]]} { + foreach deflist [dict get $crec punkargs] { + if {![catch {punk::args::rawdef_id $deflist} rawid] && $rawid ne ""} { + lappend docids $rawid + } + } + } + lappend overridden [dict create renamer [dict get $crec renamer] docids $docids] + } + return $overridden } #Each record yielded/returned by cmd_traverse is: # [list ] @@ -5627,6 +5668,24 @@ y" {return quirkykeyscript} #below the usage, the text form leads with it) return "'$name' is a recognised name here, but is not available in this runtime/context - this command line is not usable here and the usage shown is reference documentation only." } + #G-176: one-line override-in-place notice from cmdinfo's 'overridden' axis. + #basecmd is the command the records belong to (the cmdhelp subject); + #overridden is the list of {renamer .. docids ..} dicts (bottom-up). Returns + #the bare notice - the table render prefixes 'note: ', -return text prefixes + #'OVERRIDDEN: ' (its machine-facing leading-line convention). + proc _cmdhelp_override_notice {basecmd overridden} { + set renamers [list] + set docids [list] + foreach rec $overridden { + lappend renamers [dict get $rec renamer] + lappend docids {*}[dict get $rec docids] + } + set notice "'$basecmd' is currently overridden/extended via commandstack by: [join $renamers {, }]" + if {[llength $docids]} { + append notice " (override-attached docs: '[join $docids {', '}]')" + } + return $notice + } proc cmdhelp {args} { set nscaller [uplevel 1 [list ::tcl::namespace::current]] lassign [dict values [punk::args::parse $args -cache 1 withid ::punk::ns::cmdhelp]] leaders opts values received @@ -5674,8 +5733,13 @@ y" {return quirkykeyscript} #string renderer and the sections are joined below the common header. set dinfo [uplevel 1 [list ::punk::ns::cmdhelp -return dict -form $opt_form -- $querycommand {*}$queryargs]] set docid [dict get $dinfo docid] + set text_overridden [punk::args::system::Dict_getdef $dinfo overridden {}] ;#G-176 if {$docid eq ""} { - return "Undocumented command [dict get $dinfo origin]. Type: [dict get $dinfo cmdtype]" + set undoc "Undocumented command [dict get $dinfo origin]. Type: [dict get $dinfo cmdtype]" + if {[llength $text_overridden]} { + set undoc "OVERRIDDEN: [_cmdhelp_override_notice $querycommand $text_overridden]\n$undoc" + } + return $undoc } set unavail [dict get $dinfo unavailable] ;#G-166 (the dict form always carries it) set spec [punk::args::get_spec $docid] @@ -5718,6 +5782,11 @@ y" {return quirkykeyscript} } set result [string trimright $result \n] } + if {[llength $text_overridden]} { + #G-176: override-in-place leading line for the machine/LLM-facing + #surface (sits below UNAVAILABLE when both apply) + set result "OVERRIDDEN: [_cmdhelp_override_notice $querycommand $text_overridden]\n$result" + } if {$unavail ne ""} { #G-166: mark the plain-text form too - it is the machine/LLM-facing #surface, so the marking leads rather than trailing the usage block. @@ -5773,11 +5842,12 @@ y" {return quirkykeyscript} } else { dict set nextopts -form [dict get $pstatus form] } + set alias_overridden [punk::args::system::Dict_getdef $testinfo overridden {}] ;#G-176 if {$opt_return eq "dict"} { if {$scheme_received} { dict set pstatus scheme [dict get $opts -scheme] } - return [dict create origin $rootorigin docid $rootdoc cmdtype $rootorigintype unavailable [dict get $testinfo unavailable] args_remaining $queryargs parsestatus $pstatus] + return [dict create origin $rootorigin docid $rootdoc cmdtype $rootorigintype unavailable [dict get $testinfo unavailable] overridden $alias_overridden args_remaining $queryargs parsestatus $pstatus] } #G-166: an unavailable subject never renders as a cleanly usable #command line - see the matching site in the main cmdhelp body. @@ -5793,6 +5863,10 @@ y" {return quirkykeyscript} } else { set result [punk::args::arg_error [dict get $pstatus message] [punk::args::get_spec $rootdoc] {*}$nextopts -aserror 0 -parsestatus $pstatus] } + if {[llength $alias_overridden]} { + #G-176: override-in-place notice leads the render + set result "note: [_cmdhelp_override_notice $querycommand $alias_overridden]\n$result" + } if {$opt_grepstr ne ""} { if {[llength $opt_grepstr] == 1} { set result [punk::ansi::grepstr --ignore-case -return all [lindex $opt_grepstr 0] $result] @@ -5850,6 +5924,7 @@ y" {return quirkykeyscript} set args_remaining [dict get $cinfo args_remaining] set origintype [dict get $cinfo cmdtype] set unavail [dict get $cinfo unavailable] ;#G-166 + set overridden [punk::args::system::Dict_getdef $cinfo overridden {}] ;#G-176 switch -- $origintype { script { @@ -5897,7 +5972,7 @@ y" {return quirkykeyscript} if {$scheme_received} { dict set pstatus scheme [dict get $opts -scheme] } - return [dict create origin $origin docid $origindoc cmdtype $origintype unavailable $unavail args_remaining $args_remaining parsestatus $pstatus] + return [dict create origin $origin docid $origindoc cmdtype $origintype unavailable $unavail overridden $overridden args_remaining $args_remaining parsestatus $pstatus] } #G-166: a recognised-but-unavailable subject is never presented as cleanly #usable. The advisory parse can succeed against the subject's virtual id @@ -5920,6 +5995,10 @@ y" {return quirkykeyscript} } else { set result [punk::args::arg_error [dict get $pstatus message] [punk::args::get_spec $origindoc] {*}$nextopts -aserror 0 -parsestatus $pstatus] } + if {[llength $overridden]} { + #G-176: override-in-place notice leads the render + set result "note: [_cmdhelp_override_notice $querycommand $overridden]\n$result" + } if {$opt_grepstr ne ""} { if {[llength $opt_grepstr] == 1} { set result [punk::ansi::grepstr --ignore-case -return all [lindex $opt_grepstr 0] $result] @@ -5930,9 +6009,13 @@ y" {return quirkykeyscript} return $result } else { if {$opt_return eq "dict"} { - return [dict create origin $origin docid "" cmdtype $origintype unavailable $unavail args_remaining $args_remaining parsestatus {}] + return [dict create origin $origin docid "" cmdtype $origintype unavailable $unavail overridden $overridden args_remaining $args_remaining parsestatus {}] } - return "Undocumented command $origin. Type: $origintype" + set result "Undocumented command $origin. Type: $origintype" + if {[llength $overridden]} { + set result "note: [_cmdhelp_override_notice $querycommand $overridden]\n$result" + } + return $result } } diff --git a/src/modules/punk/ns-buildversion.txt b/src/modules/punk/ns-buildversion.txt index 53329246..c79abd3d 100644 --- a/src/modules/punk/ns-buildversion.txt +++ b/src/modules/punk/ns-buildversion.txt @@ -1,6 +1,7 @@ -0.10.0 +0.11.0 #First line must be a semantic version number #all other lines are ignored. +#0.11.0 - G-176 increment 4: cmdinfo gains an 'overridden' result key - a second axis beside cmdtype/unavailable (G-166 style) reporting the LIVE commandstack override state of the base command: one {renamer docids } dict per stack record (bottom-up), docids being the punk::args ids of doc blocks the record attached via 'rename_command -punkargs' (derived with punk::args::rawdef_id). Guarded live query (info commands on commandstack::get_stack) - empty list when commandstack is not loaded, never cached so it is correct as stacks change. cmdhelp surfaces it: the table/string renders lead with a plain "note: '' is currently overridden/extended via commandstack by: (override-attached docs: '')" line, -return text leads with an OVERRIDDEN: line (below UNAVAILABLE when both apply - the G-166 leading-line convention), -return dict carries the 'overridden' key on all its return shapes, and the undocumented-command fallback carries the note too. The cmdhelp.test cmdinfo/dict key-list pins flipped deliberately with this key (as they did for G-166's 'unavailable'); new pins cover the documented-command note incl the docs clause + dict axis, and the doc-less-proc autodef render leading with the note, the -return text OVERRIDDEN: line and the note clearing when the override unwinds. #0.10.0 - G-166 recognised-but-unavailable landings are surfaced distinctly. (a) cmdinfo gains an 'unavailable' result key on EVERY result - empty, or the canonical -choiceunavailable name (punk::args 0.16.0) the resolution addressed. It is a SECOND axis beside cmdtype, never a cmdtype value: cmdtype still answers what kind of executable thing was found ('string is dict' and 'string is true' on Tcl 8.6 both stay 'doconly'), availability answers whether the resolved word is selectable in this runtime/context. cmd_traverse's yielded/returned records carry a sixth element for it; cmdinfo keeps the final landing's value. (b) DECIDED (enacting the G-073 doc-walk follow-on): a unique PREFIX landing on an unavailable name now resolves that name's virtual docid, attributed - previously it conservatively resolved nothing, which made addressing inconsistent ('i string is tr' resolved but 'i string is dic' did not, while exact 'dict' and 'true' both did). The choice traverse's parse-parity claim is untouched: an unavailable word still identifies no SUBCOMMAND there, it is only attributed (the path taken when the name has no space-form virtual docid). (c) cmdhelp surfaces it in every return form: -return dict carries the key, table/string render the marking below the usage, -return text leads with an 'UNAVAILABLE:' line - and an unavailable subject is never presented as cleanly usable, so 'i string is dict 5' no longer renders info-scheme-clean just because the advisory parse of '5' succeeds against the virtual id. Wording (punk::ns::_cmdhelp_unavailable_marking) mirrors punk::args' tailored parse rejection; the runtime-specific why stays in the definition. Definitions without -choiceunavailable behave unchanged. Tests: cmdflow.test gains the flowunavail/flowunavail_nodoc fixtures + 5 pins, cmdhelp.test gains the helpstrua fixture + 5 pins (3 local, 2 real-world tclcore-gated) and the two deliberate key-list flips (cmdhelp_cmdinfo_result_shape, cmdhelp_return_dict_valid). #0.9.3 - G-073 doc-walk parity: both cmd_traverse choiceword_match call sites (the G-051 space-form prefix-parity branch and the choice-traverse subcommand resolution) now pass the argument's -choiceunavailable list (punk::args 0.16.0 8th resolver argument), so the doc walk honours recognised-but-unavailable names identically to parsing: a prefix shadowed into ambiguity by an unavailable name resolves no documentation, and an unavailable word is not accepted as a choice (its documentation remains reachable via the exact space-form virtual docid, checked before the choice traverse - e.g 'i string is dict' on Tcl 8.6 via the tclcore moduledoc 0.4.0 per-class ids). No behaviour change for definitions without the key. #0.9.2 - documentation-only PUNKARGS update: cmdhelp's 'subcommand' argument help now states the multi-form narrowing contract explicitly (argument words resolving to exactly one form narrow the usage display to that form's argument table, marked in the synopsis; no words, an ambiguous match, or words no form accepts keep the whole-command render). No behaviour change - the G-041 advisory-parse candidacy already implements it; G-150 pins the contract in cmdhelp.test against the now selection-sound punk::auto_exec::hash declaration (auto_exec 0.1.1). diff --git a/src/tests/modules/AGENTS.md b/src/tests/modules/AGENTS.md index 47d244cf..f1abb192 100644 --- a/src/tests/modules/AGENTS.md +++ b/src/tests/modules/AGENTS.md @@ -46,10 +46,10 @@ Unit tests for editable source modules under `src/modules/`, `src/modules_tcl8/` - `punk/args/` — punk::args tests (`testsuites/args/`): parsing (incl the 2026-08-08 validation.test dash-word pins: the starved-values dash-led seating rule - no -- marker needed when word supply equals required-values demand - and dash-led -type regexp values, whose validator's 'regexp -about' needed its -- guard), choices/choicegroups, forms (incl the 2026-08-05 candidacy fencing/fall-through primitive pins ahead of G-168: -regexprefail on optional value slots is form-fatal with no re-landing, unknown-option/dangling-option/option-value-fence failures fall through to sibling forms as successful parses, and the documented per-word limit - a complete option+value+file line double-matches a fenced scriptfile form and a dash-tolerant stdin form), the ensemble_subcommands_definition generator (`ensembledef.test`: lazy-argdoc ordering - the generator loads registered-but-unloaded subcommand argdocs before its id checks; plus the 2026-08-08 unqualified-ensemble-name normalization pin - a relative multi-component name is qualified in the caller's context, zero update_definitions stderr warnings and snippet parity with the qualified call), registered-namespace lazy definition loading (`docpackages.test`, G-169 pre-work: inert registration/scan-vs-load split, id_exists never triggers loading, real_id/usage lazy resolution incl tag-prefixed script-level id families, duplicate-definer last-loaded-wins characterization), the G-168 launch-definition model parity (`punkexemodel.test`, punkexe moduledoc 0.7.0, id loading updated for the G-169 handover - the script id resolves via app-punkscript-docs from src/lib (auto_path derived from the test file location) while the moduledoc carries the core-owned ids: script/tclsh selection matrices against the real (script)::punkexe ids with the real-side dispatch/app oracle recorded in goals/archive/G-168, the bare-'-e' viable-incomplete verdict, the ./-e fence message, -encoding fall-through statuses, and the sanctioned complete-'-encoding' multipleformmatches LIMIT pins; the formcheck.test punkexe GAPs flipped to discriminated/sanctioned/selection-sound pins in the same arc), the G-151 landing report (`parsereport.test`, punk::args 0.18.0 parse_report: the canonical flag-like-word-consumed-as-VALUE attribution row, parsed-result vs words+withid entry parity, machine dict shape with declaration-section row order and absent-optional row omission, received xN multiplicity for solos/-multiple opts, type-aware always-marked elision at the default width plus the caller > @cmd -reportvaluewidth > built-in width cascade and never-elided dict returns, VIEW-style single-line-ization of control-bearing values, aliased-optionset storage-key row bridging plus the G-084 storage-key attribution pin (value-parsekey and renamed-option rows attribute received; a shared-parsekey group member row keeps the bridged value with Source default - the recorded remaining gap), bordered-table/tableobject renders, words-form failure errorcode parity with parse, and the registered two-form definition's own render), rendering/indentation characterization, synopsis display characterization (`synopsis.test`: basic italic argname/`` styling, longopt `--x=` alias forms, literal/literalprefix/stringstartswith/stringendswith type-alternates rendering unitalicised, option alternate parenthesization, multi-element clause display incl `?type?` members and argname tail-word hints, `-typesynopsis` value-element lists and option passthrough incl documenter ANSI, and the small-restricted-choice-set literal rule: 1-3 restricted choices render as unitalicised `|`-joined literals in leader/option/value positions with choicegroups counted, >3 or `-choicerestricted 0` falling back to italics, `-typesynopsis` taking precedence), usage-marking characterization (`usagemarking.test`: -parsedargs/-badarg/-parsestatus/-scheme marking primitives plus goodchoice highlighting of selected/default-in-effect choice words, asserted by SGR-parameter subset against the live colour arrays; the G-049 nocolour/colour-leak GAP pins flipped 2026-07-10 to scheme-statelessness assertions), the G-049 parse-status structure (`parsestatus.test`: punk::args::parse_status overall/per-argument statuses, badarg for type/allocation failures, -caller attribution, errorcode -argspecs stripping, and the G-084 unique-storage-key attribution pin - argstatus reports received/value through a value's -parsekey or a renamed option's declared parsekey), -parsekey characterization (`parsekey.test`: result/received/solos/multis keying, shared-key required satisfaction and defaults, mash-path and prefix-abbreviation keying, plus the G-084 settled pins (2026-08-07): value -parsekey rename support, @values-line -parsekey rejection, leader -parsekey define-time rejection, last-defined-member defaults precedence, cross-member -multiple define-time rejection (allowed only when ALL members share one @opts -parsekeymode error group; a {0 1} range replace-shape stays allowed) and value-parsekey integrity (duplicate/dash-led value parsekeys rejected at define time); `testsuites/dev/parsekey-knownbugs.test` holds no disabled pins (retained as the future punkargsKnownBug home); the parsekey/optname collision GAP is flipped (G-083, 2026-08-07: -parsekey colliding with a distinct defined arg's name is now a resolve error unless that arg shares the parsekey), and the G-083 argument-relations define-time vocabulary is pinned in `relations.test` (per-arg -conflicts target validation, @opts -parsekeymode override|error storage and the requires-group/bad-value/requires-parsekey resolve errors), plus its increment-2 parse-time enforcement (optionconflict raise for -conflicts violations and -parsekeymode error co-occurrence, defaults-never-conflict, cross-group conflicts, parse_status invalid classification), and its increment-3 usage/synopsis rendering and lsearch moduledoc adoption (conflicts-with hints appended to per-arg help rows, -parsekeymode error groups annotated 'mutually exclusive' in group headers with override groups unannotated, synopsis one-line form carrying no conflict detail; and the lsearch tclcore moduledoc modelling -sorted/-glob and -bisect/-all incompatibilities via per-arg -conflicts while -glob/-regexp stay last-wins and the 'punk::args fixes required' caveat is dropped))), the G-053 range-valued -multiple occurrence arity (`multipleranges.test`, punk::args 0.22.0: {min max} range canonicalisation into a per-form MULTIPLE_RANGES companion dict while the stored -multiple boolean keeps its hot-path list-collect meaning so legacy 0/1 stay byte-unchanged, the -optional/range-min reconciliation resolve error, the {0 1}/{2 4}/{1 -1} scalar-vs-list value shapes, parse-time occurrencecount enforcement with min-under-supply suppressed in the G-152 viability probe and classified incomplete (pure exhaustion) while over-max is invalid, the usage-table Multi column showing 0-1/2-4/1+ with the synopsis ?arg? at-most-once ellipsis distinction, and -multipleunique composition; plus the allocation-participation pins (directed work 2026-08-08, punk::args 0.25.0): bounded ranges cap greedy leader/value collection at max occurrences (incl the cap-beats-type-screen case), min-occurrence-aware reservations keep a later required ranged argument fed (single and pair clauses, the leaders-side scan cap and split floor), genuine over-supply reports the pointed occurrence limit at the overflow site, legacy boolean greed unchanged), longopt style-distinction and mash-edge characterisation (`longopts.test`, 2026-08-07 gap-fill: the gnu (`--flag=` inline-only; spaced/solo usage = badoptionformat) vs plain (`--flag` spaced-only; inline `=` = invalidoption) vs mixed (`-f|--file|--file=` both forms incl longopt prefix abbreviation) definition-grammar distinctions, first-`=`-only value splitting and empty inline values, the two `=`-member resolve-time definition errors, single-dash `-flag=value` never split at the `=`, and `@opts -any 1` adhoc passthrough where `--flag=value` splits but `-flag=value` stays a whole adhoc flagname expecting a value; the same gap-fill added to `mashopts.test`: unknown-letter-in-mash invalidoption rejection and the `-any` interplay - defined flags still mash while undefined mash-lookalike tokens are adhoc flags, never mash attempts; error-shape pins use the first three -errorcode elements), and tclcore doc/interpreter behavioural parity (`tclcoreparity.test`, G-054, gated on have_tclcoredocs: 'string is' class choices equal the live-harvested set, per-class docids exist, error-vs-ok agreement across the probe matrix; version-note labels appear when the class is live OR is a declared forward unavailable class - dict labels on every runtime since G-073, unicode keeps the live-only rule; the G-073 forward-class adoption invariants and the USER-SANCTIONED 'di' prefix-strictness exemption (the model is deliberately stricter than real 8.6, full words parity-true); and the G-166 pin that an unavailable class's per-class virtual id LEADS its help with the unavailability statement on runtimes lacking the class while modern runtimes generate it unchanged. All expectations are derived from the running interpreter, green on 8.6/8.7/9.0 through runtests.tcl on each - native Tcl 8.6 has been a supported runner interpreter since 2026-07-21) - `punk/nav/ns/` — punk::nav::ns tests (`testsuites/nav/navns.test`): the n/ n// n/// navigation state machine (ns/ transitions absolute/relative/glob-no-nav, failed-nav state preservation, quad-colon normalization, v-form content selection, ensemble annotation) and the ::punk::nav::ns::ns_current variable contract the repl/codethread/subshell seeding all consume; display content is covered in punk/ns nslist.test - `punk/repl/` — punk::repl tests (`testsuites/repl/`): opunk console backend integration (`consolebackends.test`) and repl current-namespace retention (`nscurrent.test`: real codethread via repl::init driven by synchronous runscript sends - inscope evaluation of ns_current, retention across submissions, n/-navigation retained, auto-create-with-notice for missing namespaces, the 2026-07-14 stray-namespace seeding fix pinned behaviourally plus a source-text guard on repl::start's inline template; the end-to-end piped subshell session is covered at shell level by shell/testsuites/punkexe/shellnavns.test - which found the first-subshell shared-code-interp asymmetry and the piped-inscope gap recorded there) -- `punk/ns/` — punk::ns tests (`testsuites/ns/`): cmdwhich/cmdinfo/cmd_traverse doc-lookup flow (`cmdflow.test`, G-040 parity; plus the G-166 availability axis on the flowunavail/flowunavail_nodoc fixtures - the `unavailable` cmdinfo key present on every result, exact and unique-prefix landings on a `-choiceunavailable` name resolving that name's virtual docid ATTRIBUTED rather than resolving nothing, the choice traverse attributing without addressing when no virtual docid exists, and cmdtype staying unchanged throughout since availability is a second axis, never a cmdtype value), n/ display machinery characterization (`nslist.test`: tier A get_ns_dicts classification buckets as the machine contract for display reworks - incl package tail/prefix derivation, alias edge cases, usageinfo scan-dependence; tier B per-element layout-agnostic marking - underline/underdouble/underdotted namespace package styles, command type tag colours, exported/imported markers, the punkargs doc icon; tier C REWORK-flagged pins of the current hardcoded 2-col/4-col layout and nspath subtables, to flip deliberately with the planned punk-tables/width-responsive rework; plus the flipped nslist_types_default pin - bare nslist without -types displays all member types since punk::ns 0.7.1 fixed the braced-literal -types default), corp proc-retrieval and syntax/untabify interplay (`corp.test`: name edge cases, -ranges/-n line handling, basic-highlight ansistrip equivalence, -untabify spaces/unicode tab-free output, the KNOWN-DEFICIENCY pin for default -untabify none on tabbed bodies - grepstr warns per pass and brace overlays mangle tabbed lines, deterministic under mocked console tabstops - and a ::tcl::CopyDirectory -untabify spaces smoke test; precursor coverage for the planned punk::ns hygiene pass), cmdtrace characterization (`cmdtrace.test`: -pause 0 non-interactive runs, linedict line-mark keys for flat and 2-word-form nested switches as correct-mark guards, and GAP pins for the upstream nested-switch mismark - core.tcl-lang.org tktview 5d5b1052280c976ea3d4, arm bodies whose split-list index lands on a literal switch-command word report container-relative lines; mark tests gated on have_tclcoredocs because cmdtrace's arm-offset correction parses against the ::switch argdoc; plus the fixed-canary asserting punk::lib::check::has_tclbug_nestedswitch_tracelines still reports the bug - a live behavioural probe, so a fixed Tcl release fails the canary first and triggers the documented flip workflow), cmdhelp usage-rendering integration (`cmdhelp.test`: scheme selection, goodarg/badarg marking incl type/allocation failures, goodchoice highlighting of supplied/default choice words, alias path, cmdinfo result shape, queried-command failure attribution, and `-return dict` parse-status returns (G-049 - its GAP pins flipped 2026-07-10); the flipped G-051 pins for pseudo-command cmdtype (`doconly`) + space-form docid prefixes (real `string is` pins behind the have_tclcoredocs constraint); the G-166 unavailability marking on the helpstrua fixture and on the real `string is dict` subject - the `-return dict` key, the table/string marking with the info scheme suppressed so a valid argument tail no longer renders as a cleanly usable command line, and the `-return text` leading `UNAVAILABLE:` line (the two deliberate key-list flips - `cmdhelp_cmdinfo_result_shape`, `cmdhelp_return_dict_valid` - landed with it); remaining GAP pins for TclOO undocumented-method fallback (G-052) and synopsis marking absence (G-050); plus the G-150 flag-led form-narrowing + selection-soundness pins against punk::auto_exec::hash - bare-parse selection contract (incl the dash-led-name noformmatch cost), no-word/unknown-flag/ambiguity whole-render fallbacks, and hash runtime-behaviour-unchanged), and name/path primitive characterization (`nsprimitives.test`: string pins for nsparts/nsprefix/nstail/nsjoin/nsjoinall incl weird colon-run (`:::`) splitting, the trailing-colon parse ambiguity (`::x:` + `y` joins to the same string as `::x` + `:y` and reparses leading-colon-greedy), and prefix/tail/join round-trip and its absolutizing exceptions (the original twin-divergence pins for nsparts1/nsprefix1/nsprefix_orig/nstail1/nstail_orig served as safe-deletion evidence and were removed with the twins in the punk::ns 0.7.0 hygiene pass - divergence record in this file's git history, commit 0c7168a1); plus nseval fq-requirement/create-on-eval/evaluator-proc caching, the native-vs-punk `p:::x` resolution divergence (native namespace eval reaches child `x`, nseval creates/reaches literal `:x`), nseval_ifexists no-create + error propagation on plain and genuinely weird namespaces, nsexists/nschildren/nstree_raw weird-ns and relative-resolution pins, globmatchns `*`/`**`/`?` semantics (incl `*` matching a single inner colon - a formerly stale 'should be fixed' comment above nsglob_as_re was corrected in the 0.7.0 hygiene pass), and nspath_to_absolute/nspath_here_absolute caller-resolution pins; the nsjoinall error-message wart pin ('nsjoin:' prefix) flipped when punk::ns 0.7.1 fixed it) +- `punk/ns/` — punk::ns tests (`testsuites/ns/`): cmdwhich/cmdinfo/cmd_traverse doc-lookup flow (`cmdflow.test`, G-040 parity; plus the G-166 availability axis on the flowunavail/flowunavail_nodoc fixtures - the `unavailable` cmdinfo key present on every result, exact and unique-prefix landings on a `-choiceunavailable` name resolving that name's virtual docid ATTRIBUTED rather than resolving nothing, the choice traverse attributing without addressing when no virtual docid exists, and cmdtype staying unchanged throughout since availability is a second axis, never a cmdtype value), n/ display machinery characterization (`nslist.test`: tier A get_ns_dicts classification buckets as the machine contract for display reworks - incl package tail/prefix derivation, alias edge cases, usageinfo scan-dependence; tier B per-element layout-agnostic marking - underline/underdouble/underdotted namespace package styles, command type tag colours, exported/imported markers, the punkargs doc icon; tier C REWORK-flagged pins of the current hardcoded 2-col/4-col layout and nspath subtables, to flip deliberately with the planned punk-tables/width-responsive rework; plus the flipped nslist_types_default pin - bare nslist without -types displays all member types since punk::ns 0.7.1 fixed the braced-literal -types default), corp proc-retrieval and syntax/untabify interplay (`corp.test`: name edge cases, -ranges/-n line handling, basic-highlight ansistrip equivalence, -untabify spaces/unicode tab-free output, the KNOWN-DEFICIENCY pin for default -untabify none on tabbed bodies - grepstr warns per pass and brace overlays mangle tabbed lines, deterministic under mocked console tabstops - and a ::tcl::CopyDirectory -untabify spaces smoke test; precursor coverage for the planned punk::ns hygiene pass), cmdtrace characterization (`cmdtrace.test`: -pause 0 non-interactive runs, linedict line-mark keys for flat and 2-word-form nested switches as correct-mark guards, and GAP pins for the upstream nested-switch mismark - core.tcl-lang.org tktview 5d5b1052280c976ea3d4, arm bodies whose split-list index lands on a literal switch-command word report container-relative lines; mark tests gated on have_tclcoredocs because cmdtrace's arm-offset correction parses against the ::switch argdoc; plus the fixed-canary asserting punk::lib::check::has_tclbug_nestedswitch_tracelines still reports the bug - a live behavioural probe, so a fixed Tcl release fails the canary first and triggers the documented flip workflow), cmdhelp usage-rendering integration (`cmdhelp.test`: scheme selection, goodarg/badarg marking incl type/allocation failures, goodchoice highlighting of supplied/default choice words, alias path, cmdinfo result shape, queried-command failure attribution, and `-return dict` parse-status returns (G-049 - its GAP pins flipped 2026-07-10); the flipped G-051 pins for pseudo-command cmdtype (`doconly`) + space-form docid prefixes (real `string is` pins behind the have_tclcoredocs constraint); the G-166 unavailability marking on the helpstrua fixture and on the real `string is dict` subject - the `-return dict` key, the table/string marking with the info scheme suppressed so a valid argument tail no longer renders as a cleanly usable command line, and the `-return text` leading `UNAVAILABLE:` line (the two deliberate key-list flips - `cmdhelp_cmdinfo_result_shape`, `cmdhelp_return_dict_valid` - landed with it); the G-176 override-in-place hint (2026-08-08: cmdinfo's live `overridden` second axis - commandstack rename records for the base command with renamers + `-punkargs`-attached doc ids - and cmdhelp's leading "note: '' is currently overridden/extended via commandstack by: ..." line incl the docs clause, the `-return text` OVERRIDDEN: leading line, the dict key on all return shapes, the doc-less-proc autodef render leading with the note, and the note clearing when the override unwinds; the same two key-list pins flipped again with the new key, and fixtures unwind via restore_original in -cleanup); remaining GAP pins for TclOO undocumented-method fallback (G-052) and synopsis marking absence (G-050); plus the G-150 flag-led form-narrowing + selection-soundness pins against punk::auto_exec::hash - bare-parse selection contract (incl the dash-led-name noformmatch cost), no-word/unknown-flag/ambiguity whole-render fallbacks, and hash runtime-behaviour-unchanged), and name/path primitive characterization (`nsprimitives.test`: string pins for nsparts/nsprefix/nstail/nsjoin/nsjoinall incl weird colon-run (`:::`) splitting, the trailing-colon parse ambiguity (`::x:` + `y` joins to the same string as `::x` + `:y` and reparses leading-colon-greedy), and prefix/tail/join round-trip and its absolutizing exceptions (the original twin-divergence pins for nsparts1/nsprefix1/nsprefix_orig/nstail1/nstail_orig served as safe-deletion evidence and were removed with the twins in the punk::ns 0.7.0 hygiene pass - divergence record in this file's git history, commit 0c7168a1); plus nseval fq-requirement/create-on-eval/evaluator-proc caching, the native-vs-punk `p:::x` resolution divergence (native namespace eval reaches child `x`, nseval creates/reaches literal `:x`), nseval_ifexists no-create + error propagation on plain and genuinely weird namespaces, nsexists/nschildren/nstree_raw weird-ns and relative-resolution pins, globmatchns `*`/`**`/`?` semantics (incl `*` matching a single inner colon - a formerly stale 'should be fixed' comment above nsglob_as_re was corrected in the 0.7.0 hygiene pass), and nspath_to_absolute/nspath_here_absolute caller-resolution pins; the nsjoinall error-message wart pin ('nsjoin:' prefix) flipped when punk::ns 0.7.1 fixed it) - `punk/mix/` — punk::mix::cli tests (prune helpers, punkcheck virtual sources), punk::mix::commandset::repo fossil move/rename characterization tests (`testsuites/repo/`, FOSSIL_HOME-isolated; GAP-marked tests pin behaviour G-022 will change), punk::mix::commandset::loadedlib tests (`testsuites/loadedlib/libsearch.test`: 'dev lib.search' match semantics via -return list — wrap-glob default, =exact prefix, case rules, explicit globs, version aggregation — plus the loadedlib 0.2.0 contract: deep discovery by default (deep .tm modules found without -refresh, registration persists), -refresh = genuine re-scan (epoch incr + rediscovery picks up .tm files added to already-scanned dirs), and highlight working without the shell-global a+ alias; shared provisioned child interp sourcing the source-tree libunknown directly — see the file's ORDERING NOTE), and the MULTISHELL polyglot build machinery (`testsuites/scriptwrap/`, split 2026-07-19 per G-092 so no single file dominates the -jobs parallel floor - tests moved verbatim: `multishell.test` = scriptset wrap via the punk.multishell.cmd template with structure/LF-only pins plus platform-gated execution smoke (cmd.exe→powershell payload on windows, sh payload on unix or via the `wsllinux` capability constraint from `src/tests/testsupport/wslprobe.tcl` - staged to the WSL distro's native filesystem, G-059); `multishell_wrapverify.test` = checkfile 512-byte label validation of a fresh wrap; `multishell_wrapdeterminism.test` = byte-identical re-wrap pin; `runtimecmd_checkfile.test` = checkfile + LF contract of the committed bin/runtime.cmd; `runtimecmd_roundtrip.test` = the runtime scriptset round-trip byte-identity pin) - `punk/lib/` — punk::lib tests (`testsuites/lib/`): range/index/parse/compat/interp_sync utilities, G-058 static-baseline seeding (`staticseed.test`: interp_sync_package_paths/snapshot_package_paths propagate a simulated ::punkboot static baseline and seed `load {} ` ifneeded mappings; no-op without a baseline), and the repl command-completeness engine (`commandcomplete.test`: punk::lib::system::incomplete pending-opener stacks - the info-complete quoting quirk progression (`set x "{*}{"` standalone vs in-proc-body), single openers, tabs, escapes, incomplete<->info-complete parity property; pre-repl-refactor characterization, see goals/G-044 detail preserve-list) - `punk/packagepreference/` — punk::packagepreference tests (`testsuites/packagepreference/`): G-058 static-vs-bundled policy (`staticpolicy.test`: require of a baseline package triggers the index scan before resolution so a newer bundled copy wins, static beats older bundled, exact requires of bundled versions stay reachable, missing static mappings get seeded), and the install re-install guard (`installguard.test`, G-160: second install returns 0 silently via the record `renamer` key - the historical `rename` read threw; uninstall/re-install cycle gets the next unique tokenid; fresh child interps source the SOURCE-TREE commandstack + packagepreference by path so no bootsupport/kit snapshot can answer) - `punk/zip/` — punk::zip tests (`testsuites/zip/zipreader.test`, G-124 - the module's first tests): the dependency-free reader over the three archive shapes (bare zip, executable-prefixed with archive-relative offsets, executable-prefixed with file-relative offsets) - archive_info's offsetstyle/dataoffset derivation incl. the nozip verdict for a plain binary carrying a stray PK\5\6, members' per-entry introspection (classification, sizes, method, crc, mtime, stored attributes) and glob/exclude selection, unzip's byte-identical CRC-verified extraction incl. the >2MB streaming path and partial extraction; the named refusals (encrypted, unknown compression method, zip64, crc mismatch, path escape) each asserting that no partial output is left behind; and the mkzip->read round trip - the first coverage that what punkshell WRITES is readable. Runs entirely on stock Tcl (verified on msys2's tclsh8.6 with no zipfs, no vfs::zip and no tcllib); two zipfs-gated tests cross-check against a real zipfs mount and record the answer to the standing directory-classification question (zipfs keys on the trailing slash, not the stored permission bits - so punk::zip::mkzip directories mount as directories). The real-runtime pin self-gates on `bin/runtime/win32-x86_64/tclsh90b4_piperepl.exe`, which is untracked -- `punk/libunknown/` — .tm same-version shadowing pin-tests (`testsuites/shadowing/`): tcl::tm::add prepend rule, head-of-tm-list wins exact-version ties, version beats order, punk::libunknown parity — shipped behaviour depends on these (runtests tm ordering, punk_main package-mode precedence, G-033); mixed .tm/pkgIndex.tcl characterization is goal G-035; discovery/epoch-cache characterization (`testsuites/discovery/discovery.test`): sibling .tm registration happens only at the requested namespace depth (deeper modules invisible to 'package names' until requested), register_all_tm deep discovery (all-depths registration, per-epoch cached no-op, head-of-tm-list precedence parity), 'package epoch' command shape, trace-driven epoch increments on tm/auto_path changes, the epoch-index short-circuit (a .tm added to an already-scanned dir needs 'package epoch incr'), and the pkgIndex.tcl sourcing-scope contract (source_pkgindex, fixed 2026-07-11 - formerly a GAP pin of the global-'dir' clobber): user global 'dir' survives pkg-unknown fallthrough, index scripts see $dir and reach the real ::auto_path (tcllib extension pattern), and their stray unqualified sets no longer leak to ::; plus ::package-override characterisation (`testsuites/discovery/packageoverride.test`, G-176 increment 1, 2026-08-08 - the pre-migration safety net for the commandstack migration: epoch single-arg/indexed query forms and their error arms, the filtered forget arm incl the tcl/Tcl/tcl::oo/tk denial and the no-ifneeded filter, abbreviation acceptance (ep/fo prefixes the parked builtin rejects - a deliberate override delta), delegation pass-through, the re-init no-op guard, and MARKED-TO-FLIP install-shape pins (::package namespace-import origin, ::package:: parked implementation, commandstack::get_stack seeing only the packagepreference record in the two-override interop children covering BOTH real-world install orders - punkshell's pkgpref-first and make.tcl's libunknown-first) - FLIPPED 2026-08-08 with the landed increment-2 migration as marked: they now pin the commandstack-installed shape, real proc at ::package, no ::package:: residue, both overrides as managed stack records (count 2 in both interop orders)). Suite conventions learned the hard way: libunknown 0.3.0 installs its ::package override via commandstack, so cleared-tm-path child probes must pre-source the SOURCE-TREE commandstack by path before libunknown init (children inheriting parent paths resolve it via require); child probes source the SOURCE-TREE libunknown directly by path — 'package require punk::libunknown' tie-breaks the same-version copies (src/modules vs bootsupport) by tm path order, which favours bootsupport in the testinterp and machine env paths in children; and probe scripts must avoid global variable names the handlers use (notably 'dir') — that clobbering misdirected a fixture write into the real Tcl install during test development +- `punk/libunknown/` — .tm same-version shadowing pin-tests (`testsuites/shadowing/`): tcl::tm::add prepend rule, head-of-tm-list wins exact-version ties, version beats order, punk::libunknown parity — shipped behaviour depends on these (runtests tm ordering, punk_main package-mode precedence, G-033); mixed .tm/pkgIndex.tcl characterization is goal G-035; discovery/epoch-cache characterization (`testsuites/discovery/discovery.test`): sibling .tm registration happens only at the requested namespace depth (deeper modules invisible to 'package names' until requested), register_all_tm deep discovery (all-depths registration, per-epoch cached no-op, head-of-tm-list precedence parity), 'package epoch' command shape, trace-driven epoch increments on tm/auto_path changes, the epoch-index short-circuit (a .tm added to an already-scanned dir needs 'package epoch incr'), and the pkgIndex.tcl sourcing-scope contract (source_pkgindex, fixed 2026-07-11 - formerly a GAP pin of the global-'dir' clobber): user global 'dir' survives pkg-unknown fallthrough, index scripts see $dir and reach the real ::auto_path (tcllib extension pattern), and their stray unqualified sets no longer leak to ::; plus ::package-override characterisation (`testsuites/discovery/packageoverride.test`, G-176 increment 1, 2026-08-08 - the pre-migration safety net for the commandstack migration: epoch single-arg/indexed query forms and their error arms, the filtered forget arm incl the tcl/Tcl/tcl::oo/tk denial and the no-ifneeded filter, abbreviation acceptance (ep/fo prefixes the parked builtin rejects - a deliberate override delta), delegation pass-through, the re-init no-op guard, and MARKED-TO-FLIP install-shape pins (::package namespace-import origin, ::package:: parked implementation, commandstack::get_stack seeing only the packagepreference record in the two-override interop children covering BOTH real-world install orders - punkshell's pkgpref-first and make.tcl's libunknown-first) - FLIPPED 2026-08-08 with the landed increment-2 migration as marked: they now pin the commandstack-installed shape, real proc at ::package, no ::package:: residue, both overrides as managed stack records (count 2 in both interop orders); plus the flagship -punkargs consumer pin (G-176 increment 4: the {::package epoch} doc block rides the override record - mirrored in the registered stackdocs namespace pre-punk::args in these path-cleared children, lazily defined when punk::args arrives, removed with the record by restore_original)). Suite conventions learned the hard way: libunknown 0.3.x installs its ::package override via commandstack (init requires commandstack 0.8-), so cleared-tm-path child probes must pre-source the SOURCE-TREE commandstack by path before libunknown init, and children that resolve it via package require instead need 'package prefer latest' (with the default stable preference a stale stable bootsupport commandstack beats the alpha-versioned dev copy - the shadowing.test children hit exactly this); child probes source the SOURCE-TREE libunknown directly by path — 'package require punk::libunknown' tie-breaks the same-version copies (src/modules vs bootsupport) by tm path order, which favours bootsupport in the testinterp and machine env paths in children; and probe scripts must avoid global variable names the handlers use (notably 'dir') — that clobbering misdirected a fixture write into the real Tcl install during test development diff --git a/src/tests/modules/punk/libunknown/testsuites/discovery/packageoverride.test b/src/tests/modules/punk/libunknown/testsuites/discovery/packageoverride.test index b38879eb..e71755f2 100644 --- a/src/tests/modules/punk/libunknown/testsuites/discovery/packageoverride.test +++ b/src/tests/modules/punk/libunknown/testsuites/discovery/packageoverride.test @@ -2,7 +2,8 @@ # Characterization tests for the punk::libunknown ::package override itself - # the install shape, the epoch/forget/abbreviation arms and delegation - as a # pre-migration safety net for G-176 increment 2 (migration of the override -# onto commandstack::rename_command). See goals/G-176-commandstack-doc-integration.md. +# onto commandstack::rename_command). See goals/archive/G-176-commandstack-doc-integration.md +# (achieved 2026-08-08). # # Pin classes: # - BEHAVIOUR pins: stayed green byte-identically through the migration. @@ -62,6 +63,7 @@ namespace eval ::testspace { proc pko_probe {script} { variable libunknown_src variable commandstack_src + variable srcmodules set i [interp create] try { interp eval $i {package prefer latest} @@ -69,6 +71,8 @@ namespace eval ::testspace { interp eval $i [list source $commandstack_src] interp eval $i [list source $libunknown_src] interp eval $i {punk::libunknown::init} + #for tests that later load punk::args in the child (epoch-doc lazy path) + interp eval $i [list set ::PKO_SRCMODULES $srcmodules] interp eval $i $script } finally { interp delete $i @@ -282,6 +286,30 @@ namespace eval ::testspace { } } -result {1 1.0 2 ::package} + #added 2026-08-08 (agent, G-176 increment 4) - the flagship -punkargs consumer: + #libunknown 0.3.1 attaches the {::package epoch} doc block to its override + #record. In these path-cleared children punk::args is ABSENT at init, so this + #exercises the real early-boot pending path: the deflist sits in the + #registered ::commandstack::stackdocs mirror, a later punk::args load + #consumes it lazily, and unwinding the override removes the doc with the + #record (the increment-3 detach contract, here through the real consumer). + test override_epoch_doc_attached {the override record carries the {::package epoch} doc - mirrored pre-punk::args, lazily defined when punk::args arrives, removed when the override unwinds}\ + -constraints pko_sources -body { + pko_probe { + set r [list] + lappend r [llength $::commandstack::stackdocs::PUNKARGS] + lappend r [dict exists [lindex [commandstack::get_stack ::package] 0] punkargs] + tcl::tm::add $::PKO_SRCMODULES + package prefer latest + package require punk::args + punk::args::update_definitions [list ::commandstack::stackdocs] + lappend r [punk::args::id_exists {::package epoch}] + commandstack::restore_original ::package + lappend r [punk::args::id_exists {::package epoch}] [llength $::commandstack::stackdocs::PUNKARGS] + set r + } + } -result {1 1 1 0 0} + test override_interop_libunknown_first {make.tcl order then packagepreference on top: epoch reaches through the wrapper's delegation and require works; both records on the managed stack}\ -constraints pko_interopsources -body { pko_interop libunknown_first { diff --git a/src/tests/modules/punk/libunknown/testsuites/shadowing/shadowing.test b/src/tests/modules/punk/libunknown/testsuites/shadowing/shadowing.test index 1ef79f04..1770876c 100644 --- a/src/tests/modules/punk/libunknown/testsuites/shadowing/shadowing.test +++ b/src/tests/modules/punk/libunknown/testsuites/shadowing/shadowing.test @@ -86,8 +86,15 @@ namespace eval ::testspace { try { interp eval $i {tcl::tm::remove {*}[tcl::tm::list]} if {$libunknown} { - #make punk::libunknown loadable, then activate it + #make punk::libunknown loadable, then activate it. + #prefer latest: libunknown 0.3.x init requires commandstack (G-176) - + #with the default stable preference the alpha-versioned source-tree + #commandstack (999999.0a1.0) would lose to an older stable bootsupport + #copy that predates the mechanism. Same-version .tm shadowing (this + #suite's subject) is unaffected - ties are broken by tm path order + #either way. interp eval $i [list tcl::tm::add {*}[tcl::tm::list]] + interp eval $i {package prefer latest} interp eval $i {package require punk::libunknown; punk::libunknown::init} interp eval $i {tcl::tm::remove {*}[tcl::tm::list]} } diff --git a/src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test b/src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test index b555fa59..fdb004c4 100644 --- a/src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test +++ b/src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test @@ -259,15 +259,19 @@ namespace eval ::testspace { #--- cmdinfo result shape ---------------------------------------------------------------- + #key list extended deliberately with G-166 (unavailable) and again with G-176 + #(overridden, 2026-08-08 - the commandstack override-state second axis) test cmdhelp_cmdinfo_result_shape {cmdinfo returns the documented key set - synopsis and cmdhelp consume this shape}\ -setup $common -body { set cinfo [punk::ns::cmdinfo ::testspace::helpfix] lappend result [dict keys $cinfo] lappend result [dict get $cinfo cmdtype] [dict get $cinfo docid] + #an un-overridden fixture reports the empty override state + lappend result [dict get $cinfo overridden] }\ -cleanup { }\ - -result [list {origin cmdtype unavailable args_resolved args_remaining docid stack} proc ::testspace::helpfix] + -result [list {origin cmdtype unavailable overridden args_resolved args_remaining docid stack} proc ::testspace::helpfix {}] #--- scheme selection -------------------------------------------------------------------- @@ -423,6 +427,8 @@ namespace eval ::testspace { #--- -return dict (G-049 machine-parsable returns) ----------------------------------------- + #key list extended deliberately with G-166 (unavailable) and again with G-176 + #(overridden, 2026-08-08) test cmdhelp_return_dict_valid {a fully-valid argument set returns ok/valid/info with received arguments status ok}\ -setup $common -body { set d [punk::ns::cmdhelp -return dict ::testspace::helpfix v1 0 1] @@ -437,7 +443,7 @@ namespace eval ::testspace { }\ -cleanup { }\ - -result [list {origin docid cmdtype unavailable args_remaining parsestatus} ::testspace::helpfix proc 1 valid info ok ok 0 unparsed] + -result [list {origin docid cmdtype unavailable overridden args_remaining parsestatus} ::testspace::helpfix proc 1 valid info ok ok 0 unparsed] test cmdhelp_return_dict_invalid {an invalid argument set (choice violation) returns ok 0/invalid/error with the offending argument status bad}\ -setup $common -body { @@ -1143,5 +1149,67 @@ bar /bin/bar} 0 1 0 1] array set ::auto_execs $saved_auto_execs }\ -result [list {foo /bin/foo} 1] + + #--- G-176 override-in-place hint (2026-08-08) --------------------------------------------- + #cmdinfo's 'overridden' axis surfaces live commandstack rename records for the + #base command; cmdhelp leads its renders with a notice naming the renamers and + #any doc ids their records attached via 'rename_command -punkargs'. Fixtures + #override throwaway procs in this shared testinterp and unwind in -cleanup via + #restore_original (which also detaches the attached doc - the -punkargs detach + #contract is pinned module-side in commandstack.test; here we pin the cmdhelp + #surfacing). + testConstraint havecommandstack [expr {![catch {package require commandstack}]}] + + #added 2026-08-08 (agent, G-176 increment 4) + test cmdhelp_override_hint_documented_command {a documented overridden command renders the leading note naming renamer and attached doc id; dict form carries the overridden axis}\ + -constraints havecommandstack -setup $common -body { + proc ::testspace::ovfix {args} {return base} + punk::args::define { + @id -id ::testspace::ovfix + @cmd -name testspace::ovfix -summary "override hint fixture." -help "override hint fixture." + @values -min 0 -max 0 + } + commandstack::rename_command -renamer ::testspace::ovrenamer -punkargs {{{@id -id {::testspace::ovfix zap} + @cmd -name "override: ovfix zap" -summary "zap subcommand." -help "zap subcommand help." + @values -min 0 -max 0}}} ::testspace::ovfix {args} { + uplevel 1 [list $COMMANDSTACKNEXT {*}$args] + } + set out [punk::ansi::ansistrip [punk::ns::cmdhelp ::testspace::ovfix]] + lappend result [string match "note: '::testspace::ovfix' is currently overridden/extended via commandstack by: ::testspace::ovrenamer*" [lindex [split $out \n] 0]] + lappend result [string match "*override-attached docs: '::testspace::ovfix zap'*" $out] + set d [punk::ns::cmdhelp -return dict ::testspace::ovfix] + lappend result [dict get $d overridden] + }\ + -cleanup { + commandstack::restore_original ::testspace::ovfix + punk::args::undefine ::testspace::ovfix 1 + rename ::testspace::ovfix "" + }\ + -result [list 1 1 [list [dict create renamer ::testspace::ovrenamer docids [list {::testspace::ovfix zap}]]]] + + #added 2026-08-08 (agent, G-176 increment 4) + #A doc-less overridden proc renders via the generate_autodef path (plain procs + #never take the 'Undocumented command' fallback) - the note still leads it. + test cmdhelp_override_hint_docless_and_text {a doc-less overridden proc leads its autodef render with the note (no docs clause); -return text leads with OVERRIDDEN:; the hint clears when the override unwinds}\ + -constraints havecommandstack -setup $common -body { + proc ::testspace::ovbare {args} {return base} + commandstack::rename_command -renamer ::testspace::ovrenamer ::testspace::ovbare {args} { + uplevel 1 [list $COMMANDSTACKNEXT {*}$args] + } + set out [punk::ansi::ansistrip [punk::ns::cmdhelp ::testspace::ovbare]] + #no -punkargs docs on this record - the notice line ends without a docs clause + lappend result [string match "note: '::testspace::ovbare' is currently overridden/extended via commandstack by: ::testspace::ovrenamer" [lindex [split $out \n] 0]] + lappend result [string match "*override-attached docs*" $out] + set t [punk::ns::cmdhelp -return text ::testspace::ovbare] + lappend result [string match "OVERRIDDEN: '::testspace::ovbare' is currently*" $t] + commandstack::restore_original ::testspace::ovbare + lappend result [string match "*overridden/extended*" [punk::ansi::ansistrip [punk::ns::cmdhelp ::testspace::ovbare]]] + set result + }\ + -cleanup { + catch {commandstack::restore_original ::testspace::ovbare} + rename ::testspace::ovbare "" + }\ + -result [list 1 0 1 0] } tcltest::cleanupTests ;#needed to produce test summary line.