Browse Source

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 <string>
docids <list>} 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: '<cmd>' is currently
overridden/extended via commandstack by: <renamers> (override-attached
docs: '<ids>')" 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
master
Julian Noble 2 days ago
parent
commit
8fa716b62b
  1. 15
      CHANGELOG.md
  2. 4
      GOALS-archive.md
  3. 4
      GOALS.md
  4. 29
      goals/archive/G-176-commandstack-doc-integration.md
  5. 2
      punkproject.toml
  6. 67
      src/modules/punk/libunknown-0.3.1.tm
  7. 95
      src/modules/punk/ns-999999.0a1.0.tm
  8. 3
      src/modules/punk/ns-buildversion.txt
  9. 4
      src/tests/modules/AGENTS.md
  10. 30
      src/tests/modules/punk/libunknown/testsuites/discovery/packageoverride.test
  11. 9
      src/tests/modules/punk/libunknown/testsuites/shadowing/shadowing.test
  12. 72
      src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test

15
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: '<cmd>' 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

4
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.

4
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

29
goals/G-176-commandstack-doc-integration.md → 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 <which> <index> ?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: '<cmd>' is currently
overridden/extended via commandstack by: <renamers> (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

2
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 -

67
src/modules/punk/libunknown-0.3.0.tm → 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 <int> pkg <int>} - the current
epoch counters
package epoch tm|pkg - one-entry dict keyed by the current
epoch: {<epoch> <epochinfo>}
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 <idx> - the epochinfo record for epoch <idx>
(error for an unknown <idx>)
package epoch tm|pkg <idx> <key>...
- 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

95
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 <string> docids
<list>} 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 <string> docids <list>} 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 <code> <origin> <resolvedargs> <remainingargs> <docid> <unavailable>]
@ -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
}
}

3
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 <string> docids <list>} 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: '<cmd>' is currently overridden/extended via commandstack by: <renamers> (override-attached docs: '<ids>')" 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).

4
src/tests/modules/AGENTS.md

File diff suppressed because one or more lines are too long

30
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 {

9
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]}
}

72
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.

Loading…
Cancel
Save