Browse Source

G-176 drafted (proposed): commandstack doc integration - stack-tied overrider argdocs, override hints, libunknown package-override migration

Four-increment arc from the 2026-08-08 feasibility investigation:
(1) characterise the untested arms of the current punk::libunknown
::package override (epoch single-arg/indexed forms + error arms, the
entire forget arm, abbreviation acceptance, delegation, re-init guard,
packagepreference interop in both install orders; install-shape pins
marked to flip), (2) migrate that override onto
commandstack::rename_command (one managed stack for both live ::package
overrides - cures the restore_original/wrong-command latent hazard of
the current unmanaged mix), (3) rename_command -punkargs stack-tied doc
blocks (attach at the single rename site, detach at the remove_rename
choke point every removal path funnels through; stackdocs registered
namespace covers renames performed before punk::args loads), (4)
cmdhelp/cmdinfo override-in-place hint (G-166-style second axis, live
get_stack query, no hard dependency) + the flagship {::package epoch}
doc attachment and the commandstack::help how-to.

Investigation evidence embedded in the goal Context: probe-verified
space-form doc define/resolve/undefine/fallback cycle ('i package
epoch' resolves despite the parent's restricted choices - G-051
space-form jump), record-key append contract, undefine_deflist
primitive, no external :📦: callers, the dead
has_package_files declaration, both real-world install orders.

goals_lint clean (80 active-index goals / 96 archived).

Claude-Session: https://claude.ai/code/session_01QgaxV27VZkmEec7oNbEVFc
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 3 days ago
parent
commit
b10abcbae0
  1. 4
      GOALS.md
  2. 135
      goals/G-176-commandstack-doc-integration.md

4
GOALS.md

@ -404,3 +404,7 @@ 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 [proposed] 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.2.4.tm (package-override migration to commandstack - fixed-version file, renamed on bump); 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

135
goals/G-176-commandstack-doc-integration.md

@ -0,0 +1,135 @@
# G-176 commandstack doc integration - stack-tied overrider argdocs, override hints, and the libunknown package-override migration
Status: proposed
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.2.4.tm (package-override migration to commandstack - fixed-version file, renamed on bump); 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.
## Context
Feasibility investigated 2026-08-08 (user-directed; probe evidence below from tclsh90s
with src modules + tclcore moduledoc). Motivating observation: punk::libunknown extends
::package with an 'epoch' subcommand that has no punk::args documentation, and an
overrider currently has no way to attach docs whose lifetime matches the override.
Probe-verified doc mechanics (the punk::args side needs NO changes):
- A space-form id `{::package epoch}` defines cleanly and punk::args::define RETURNS
the id. `i package epoch` resolves the new doc as a focused render EVEN THOUGH
'epoch' is absent from the parent ::package definition's restricted subcommand
choices - the G-051 space-form docid jump (achieved, see
goals/archive/G-051-cmdinfo-pseudo-and-prefix.md) bypasses the choice screen.
`i package` is unaffected. undefine (quiet flag available) removes cleanly and
`i package epoch` falls back to the parent render; re-define cycles are clean.
- punk::args::undefine_deflist is deflist-keyed - commandstack never parses ids.
- Recorded limitation: the parent def's choice TABLE never lists 'epoch' and parsing
'epoch' against ::package fails its choice restriction - mitigated by the hint
mechanism enumerating record-attached doc ids on the parent render.
commandstack architecture facts (as at 2026-08-08, commandstack 0.7.1):
- Record keys are APPEND-only extensible by documented contract (token/renamer at
lsearch -index 1/-index 3; 'additive keys must be APPENDED').
- EVERY removal path funnels through remove_rename (pop_rename :884,
remove_renamer :936, restore_original :996 all delegate) - one detach choke point
at the doomed_record site; one attach point in rename_command's success path.
- Early boot: commandstack renames happen BEFORE punk::args loads. The inert
registration pattern (namespace eval ::punk::args::register {lappend NAMESPACES ...}
- used by libunknown itself at :2175) covers this: a ::commandstack::stackdocs
namespace PUNKARGS variable mirrors live records' deflists; punk::args consumes it
lazily on first doc query. When punk::args is ALREADY loaded the attach must also
define immediately (a namespace already consumed into loaded_packages never
lazy-loads later appends; redefinition is idempotent).
- The reload contract (0.7.1) preserves module state across re-source via info-exists
guards - new stackdocs state needs the same guard.
libunknown override facts (libunknown-0.2.4.tm, line anchors point-in-time):
- Current install (:1692-1822): `proc package` in ::punk::libunknown +
`rename ::package ::package::` + NAMESPACE IMPORT into :: - the import is
load-bearing (an imported proc executes in its origin namespace, resolving the
body's bare epoch_incr_pkg/epoch_incr_tm calls and `variable` statement). A
commandstack::rename_command migration was started and commented out (:1689).
- Migration deltas are enumerable: qualify 4 bare epoch_incr_pkg/tm calls (a
commandstack-installed proc runs in ::), swap the 2 `::package::` delegation sites
(:1734 forget, :1816 default) for COMMANDSTACKNEXT, drop the DEAD
`variable has_package_files` declaration (:1695 - its only use :1709 is commented
out; the :143-147 module-load probe stays), replace rename+import with
rename_command + a stack-query install guard (punk::packagepreference::install
:110-137 is the exact in-tree precedent incl the G-160 (achieved, see
goals/archive/G-160-commandstack-hygiene.md) silent re-install return), keep the
:1574 info-commands re-init guard semantics.
- NO external ::package:: callers exist anywhere in the tree (grepped src/modules +
tests) - the parked-name change is libunknown-internal.
- Latent hazard the migration cures: in a punkshell boot packagepreference installs
its ::package wrapper via commandstack FIRST (app entrypoints, e.g punkshell.tcl:9)
and libunknown's plain rename lands ON TOP (repl-triggered init) - commandstack's
::package stack then believes the wrapper is live at ::package while libunknown's
import actually is; restore_original or a third-party rename_command would operate
on the wrong command and strand ::package::. make.tcl (:1748) runs libunknown with
NO packagepreference - both orders occur, and one managed stack handles either
(multi-renamer any-order removal is commandstack.test-pinned).
- Hot-path note: rename_command's injected header resolves COMMANDSTACKNEXT via
get_next_command on every invocation - packagepreference already pays exactly this
on the same hot command (every package require); precedent accepted.
Coverage audit (2026-08-08): discovery.test pins six epoch arms (0-arg dict shape,
tm-paths/auto_path trace increments, `epoch incr`, cache-blocks-until-incr,
register_all_tm per-epoch no-op) plus libsearch.test indirect use. UNTESTED: the
`epoch tm`/`epoch pkg` single-arg forms, indexed queries + error arms, the entire
forget arm, abbreviation acceptance (the override accepts prefixes like 'ep' that
the builtin would reject - an uncharacterised behaviour delta), delegation as a
contract, the install shape, the re-init guard, and any packagepreference interop.
## Approach
Increments land as separate commits, each leaving all suites green:
1. Characterisation: pin every untested arm of the CURRENT override (list in
Acceptance) in punk/libunknown testsuites (discovery.test extensions or a sibling
packageoverride.test - child-interp pattern, children source libunknown AND
commandstack by path). Install-shape pins (::package import link, ::package::
parked name) carry explicit marked-to-flip comments.
2. Migration: libunknown installs via commandstack::rename_command (deltas per
Context). Only the marked install-shape pins flip; every behaviour pin stays
green unchanged. Decision recorded in this file: hard `package require
commandstack` (lean, dependency-free, present in bootsupport + kits) - no
plain-rename fallback path (two install behaviours would double the test
surface). Fixed-version file rename on bump: git mv + fossil mv.
3. commandstack -punkargs mechanism: leading option on rename_command (beside
-renamer) taking a list of definitionlists; record key `punkargs` appended; dual
activation (stackdocs PUNKARGS variable + immediate define when punk::args
present); detach in remove_rename via undefine_deflist (quiet) + variable
removal; reload guard; help/argdoc how-to; commandstack.test pins incl the
pre-punk::args pending path (bare child renames with -punkargs, then loads
punk::args and queries).
4. Override hint + flagship docs: cmdinfo gains a second-axis override key sourced
from a guarded live commandstack::get_stack query (no hard dependency);
cmdhelp renders the notice naming renamers + record-attached doc ids; libunknown
attaches the `{::package epoch}` doc block via -punkargs (retiring the doc gap
that motivated the arc); cmdhelp.test pins; `i package epoch` verified in a punk
shell.
## Notes
- Same-id shadowing: one live record per doc id is the documented constraint
(natural usage - each overrider documents its OWN added subcommands); no
re-instatement machinery unless a real consumer needs it.
- Rename_stack parking: default decision is detach-on-park (docs describe a command
that no longer answers); revisit if an unpark consumer appears.
- The abbreviation-acceptance delta (override accepts ep/fo prefixes the builtin
rejects) is characterised as CURRENT behaviour in increment 1 - whether to keep it
is a separate question, deliberately out of scope here (the migration must not
silently change it).
- Mechanism B's optional heuristic for UNMANAGED overrides (doc @cmd -name says
'Built-in:' while the live command is a proc/import) is out of scope - after the
increment-2 migration both live ::package overrides are managed.
- The tclcore parent ::package definition is untouched: 'epoch' stays outside its
restricted subcommand choices; the hint line plus the space-form doc are the
contract. Extending parent choice tables from override records is a possible
follow-on, not part of this goal.
- G-058 static-package interplay (achieved, see
goals/archive/G-058-static-runtime-packages.md): the packagepreference wrapper
body consulted in Context is the same one the interop child exercises - its
COMMANDSTACKNEXT_ORIGINAL fast-path is behaviour the interop pins must not
disturb.
Loading…
Cancel
Save