Browse Source
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
2 changed files with 139 additions and 0 deletions
@ -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…
Reference in new issue