diff --git a/CHANGELOG.md b/CHANGELOG.md index 28b5659d..ad5bc7be 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.50.1] - 2026-08-04 + +- commandstack 0.7.1 (G-160 follow-on, landed at user direction): the + reload contract - known_renamers and debug are now info-exists guarded + like the rest of the module state (all_stacks, renamer_command_tokens, + token_implementations), so a module re-source refreshes proc definitions + only and no longer resets them while stacks/tokens survive. Previously + the reset stranded live stacks: the removal forms gate on known_renamers + membership, so the surviving records' renamers became unknown and + removal errored. Contract documented in commandstack::help; pinned by + commandstack_reload_preserves_state (suite 41/41 on tclsh90 9.0.3 and + punk86 8.6; packagepreference consumer suites 6/6 on both). Minted as + modules/commandstack-0.7.1.tm; bootsupport/vfscommon promotion left to + the next promotion cycle (as with 0.6.0/0.7.0). + ## [0.50.0] - 2026-08-04 - punk executable -e one-liner support (G-077, achieved): ` -e diff --git a/goals/archive/G-160-commandstack-hygiene.md b/goals/archive/G-160-commandstack-hygiene.md index bbc97ad0..a2e41f0e 100644 --- a/goals/archive/G-160-commandstack-hygiene.md +++ b/goals/archive/G-160-commandstack-hygiene.md @@ -181,4 +181,4 @@ Verification evidence: ## Follow-ons Follow-on: remove_rename convenience forms parked as code todos (pop topmost-for-renamer, remove all entries for a renamer, restore-to-original regardless of stack) => landed 2026-08-04 (commandstack 0.7.0 - pop_rename/remove_renamer/restore_original) -Follow-on: a module re-source resets known_renamers and debug while all_stacks/renamer_command_tokens/token_implementations survive their info-exists guards - guard known_renamers likewise or document the reload contract => open +Follow-on: a module re-source resets known_renamers and debug while all_stacks/renamer_command_tokens/token_implementations survive their info-exists guards - guard known_renamers likewise or document the reload contract => landed 2026-08-04 (commandstack 0.7.1 - both guarded; reload contract documented in commandstack::help, pinned by commandstack_reload_preserves_state) diff --git a/punkproject.toml b/punkproject.toml index 3d1800d1..afafab35 100644 --- a/punkproject.toml +++ b/punkproject.toml @@ -1,6 +1,6 @@ [project] name = "punkshell" -version = "0.50.0" +version = "0.50.1" 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/commandstack-999999.0a1.0.tm b/src/modules/commandstack-999999.0a1.0.tm index 9bb93b14..5d57369d 100644 --- a/src/modules/commandstack-999999.0a1.0.tm +++ b/src/modules/commandstack-999999.0a1.0.tm @@ -11,6 +11,12 @@ # - oo dispatch features may be a better implementation - especially for allowing undoing command renames in the middle of a stack. # - document that replacement command should use 'commandstack::get_next_command ' for delegating to command as it was prior to rename #changes: +#2026-08-04 (G-160 follow-on 2) +# - reload contract: known_renamers and debug are now info-exists guarded +# like the rest of the module state (all_stacks, renamer_command_tokens, +# token_implementations) - previously a module re-source reset both while +# the stacks/tokens survived, stranding live stacks whose renamers were +# no longer known (the removal forms gate on known_renamers membership) #2026-08-04 (G-160 follow-on) # - remove_rename convenience forms (the long-parked code todos): # pop_rename (pop a renamer's topmost entry - per command, or searched @@ -63,12 +69,23 @@ namespace eval commandstack { + #Reload contract: ALL module state survives a re-source (only proc + #definitions refresh) - every state variable here is info-exists guarded. + #known_renamers in particular must survive with all_stacks: stack records + #reference renamer strings and the removal forms gate on known_renamers + #membership, so a reset would strand live stacks. ('variable name ' + #is no guard - with a value it re-assigns on every re-source.) variable all_stacks variable debug - set debug 0 - #the strings the vendored cooperating packages actually pass as -renamer - #(reconciled 2026-08-03 - the historical defaults ::packagetrace ::packageSuppress matched no actual registration) - variable known_renamers [list packagetrace packagesuppress] + if {![info exists debug]} { + set debug 0 + } + variable known_renamers + if {![info exists known_renamers]} { + #the strings the vendored cooperating packages actually pass as -renamer + #(reconciled 2026-08-03 - the historical defaults ::packagetrace ::packageSuppress matched no actual registration) + set known_renamers [list packagetrace packagesuppress] + } if {![info exists all_stacks]} { #don't wipe it set all_stacks [dict create] @@ -239,6 +256,11 @@ namespace eval commandstack { when enabled; errors always raise) Notes + - Reload contract: a module re-source (re-source / package forget+require + during development) refreshes proc definitions only - ALL module state + survives: all_stacks, renamer_command_tokens, token_implementations, + known_renamers and debug are each info-exists guarded at load, so live + stacks never lose the state that references them. - The renamer string defaults to the calling namespace. - Cooperating packages are identified by a magic comment in installed proc bodies: IMPLEMENTOR_! (added automatically by rename_command). @@ -264,7 +286,8 @@ namespace eval commandstack { argument. When enabled, rename_command and remove_rename report progress and informational warnings on stderr - with debug off (the default) they emit nothing (errors are still - raised as errors)." + raised as errors). The setting survives a module re-source + (the reload contract - see commandstack::help)." @values -min 0 -max 1 on_off -type boolean -optional 1 -help -& "New debug state. Omit to query the current state." @@ -936,8 +959,8 @@ namespace eval commandstack { gated by known_renamers (unlike remove_rename) - renamers evidenced by the stack records are registered into known_renamers first, mirroring rename_command, so a - restore still works after state loss such as a module - re-source that reset known_renamers while stacks survived. + restore still works after state loss such as known_renamers + being cleared while stacks survived. Returns the number of records removed: 0 when the command has no live stack (never renamed, or only the empty residue entry - prune that with Delete_stack).} @@ -959,8 +982,8 @@ namespace eval commandstack { if {![llength $stack]} { return 0 } - #a repair operation must not be gated by known_renamers (which a module - #re-source may have reset while stacks survived) - register the renamers + #a repair operation must not be gated by known_renamers (which state + #surgery may have lost while stacks survived) - register the renamers #the stack evidences, mirroring rename_command foreach record $stack { set record_renamer [dict get $record renamer] diff --git a/src/modules/commandstack-buildversion.txt b/src/modules/commandstack-buildversion.txt index 6750059a..f4c218bf 100644 --- a/src/modules/commandstack-buildversion.txt +++ b/src/modules/commandstack-buildversion.txt @@ -1,6 +1,13 @@ -0.7.0 +0.7.1 #First line must be a tm version number #all other lines are ignored. +#0.7.1 - G-160 follow-on: reload contract - known_renamers and debug are now +# info-exists guarded like the rest of the module state (all_stacks, +# renamer_command_tokens, token_implementations): a module re-source no +# longer resets them while stacks/tokens survive (previously the reset +# stranded live stacks - the removal forms gate on known_renamers +# membership). Contract documented in commandstack::help; pinned by +# commandstack_reload_preserves_state #0.7.0 - G-160 follow-on: remove_rename convenience forms (the parked code todos): # - pop_rename renamer ?command? - pop the renamer's topmost stack entry and # return the removed record (searched across live stacks when no command is diff --git a/src/tests/modules/AGENTS.md b/src/tests/modules/AGENTS.md index 79c12195..7632956a 100644 --- a/src/tests/modules/AGENTS.md +++ b/src/tests/modules/AGENTS.md @@ -40,7 +40,7 @@ Unit tests for editable source modules under `src/modules/`, `src/modules_tcl8/` - `opunk/console/` — ::opunk::Console backend subclass tests (`testsuites/console/backends.test`, G-001): virtual dispatch of subclass overrides through base-class calls and punk::console::console_spec_resolve (both unchanged), TestConsole determinism + probe-free at_eof, SshConsole capability/eof + the flagship size-via-ANSI-query-over-socket case (a scripted remote terminal answers CSI 6n), TkConsole widget size/eof (gated behind env PUNK_TEST_TK=1 - Tk in the shared testinterp has side effects; also verifiable standalone under a tk-capable kit e.g `punk91 src