Browse Source

G-160: closeout evidence + DOX + punkshell 0.49.3

Detail-file Progress section records the settled decisions (tokenid
mechanism + seeding removal, token-map O(1) dispatch with source-level
verification note and parked-dispatch side effect, Delete_stack error
semantics, Rename_stack 1/0 returns, channel-discipline scope incl the
gated remove_rename anomaly warning, known_renamers reconciliation
rationale, did_rename shape, commandstack::next design, the
pins-updated-minimally interpretation) and the verification evidence
(33/33 + 6/6 on tclsh90/punk86, live punk91 src smoke, mint).

src/tests/modules/AGENTS.md: commandstack entry rewritten for the 0.6.0
fixed-behaviour contract (GAP language retired); packagepreference entry
gains installguard.test.

punkshell 0.49.3 + CHANGELOG (commandstack 0.6.0, packagepreference 0.2.1).

Claude-Session: https://claude.ai/code/session_01TNn3C58Cpekt3CsZNLCqvR
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 1 week ago
parent
commit
40283ca082
  1. 20
      CHANGELOG.md
  2. 86
      goals/G-160-commandstack-hygiene.md
  3. 2
      punkproject.toml
  4. 4
      src/tests/modules/AGENTS.md

20
CHANGELOG.md

@ -5,6 +5,26 @@ 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.49.3] - 2026-08-03
- commandstack 0.6.0 (G-160 hygiene pass): tokenids are unique and monotonic
per (renamer, command) - same-renamer re-renames now dispatch through the
full override chain and are individually removable by exact token (the
counter was stuck at 1 on an apply-local variable, silently bypassing
intermediate overrides and erroring on a third rename); get_next_command
dispatch is a single dict lookup (token->implementation map, no stack scan);
get_IMPLEMENTOR classifies builtins where tcl::info::cmdtype exists;
informational warnings are debug-gated (a stray write of the literal word
"stderr" to stdout is gone); rename records carry a trailing did_rename 0|1;
misplaced -renamer flags error instead of silently misparsing; new
commandstack::next delegation helper; Rename_stack-parked stacks are
retrievable and keep dispatching; Delete_stack refuses to strand live
overrides; known_renamers defaults match the vendored packagetrace/
packagesuppress registrations.
- punk::packagepreference 0.2.1: a second install returns 0 silently as
documented instead of throwing (the already-installed guard read a
nonexistent record key; latent in kits, which install once per interp).
## [0.49.2] - 2026-08-03
- commandstack 0.5.0: `commandstack::help` now returns a real API overview

86
goals/G-160-commandstack-hygiene.md

@ -91,3 +91,89 @@ vendored packages actually register (packagetrace / packagesuppress, plain words
- Version: minor bump (0.6.0) expected - additive keys and fixes; the Delete_stack guard
changes an unexported maintenance proc's behaviour (changelog-noted). Revisit as major
only if the settled semantics break an exported surface.
## Progress
2026-08-03 - full pass landed in one arc (activation bac3802c, source increment git
23077dc1 / fossil 52a1db73): commandstack 0.6.0 + punk::packagepreference 0.2.1,
suite flips + new pins, minted, punkshell 0.49.3.
Decisions settled in the work (per the Approach's "settled in the work" clauses):
- tokenid mechanism: incremented on the real namespace variable in the proc frame
BEFORE the apply and passed in as an apply parameter (the Approach's first option).
Aborted renames (same-body refusals) consume an id - gaps are deliberate; uniqueness
and monotonicity are the contract, not density. The known-renamer seeding
(`dict set ... 0`) was dropped - `dict incr` creates missing keys, so seeding added
nothing and its skip-when-default path was a latent inconsistency.
- O(1) dispatch mechanism (acceptance 3): a `token_implementations` namespace dict
(token {command renamer tokenid} -> implementation) maintained by rename_command
(set on stack push), remove_rename (unset doomed token; re-point the rewritten
record's token at the doomed record's implementation). get_next_command is now a
single `dict exists`/`dict get` pair - source-level verification: the proc contains
no lsearch and no stack-list read on the hit path (the all_stacks lookup remains
only to distinguish the two miss cases: stacked-but-bad-token error vs no-stack
passthrough). Deliberate side effect: dispatch keeps working while a stack is
parked under a Rename_stack key (map is token-keyed, not command-keyed) - pinned.
Map/stack sync is guarded long-term by the record_key_order_and_token_map pin
(every record's token maps to its implementation, map size == total records,
through rename/remove sequences).
- Delete_stack settled semantics: ERROR while the stack holds records (live renames -
the recursion foot-gun); empty-residue and missing entries return 1 (its legitimate
maintenance use - pruning the empty key remove_rename leaves behind).
- Rename_stack returns 1 (moved) / 0 (no stack at oldname); error on existing newname
unchanged.
- Channel discipline: ALL informational/warning output (missing-command, same-body
abort + stack display, new-code notice + code dump, not-immediate-predecessor,
unknown-implementor cooperate notice, remove_rename's next_implementor-mismatch
anomaly warning) is debug-gated, unified on stderr (the code dump moved from stdout).
The mismatch warning was gated rather than kept always-on: it reports a conservative
proceed (parked proc left in place) in externally-interfered stack states, the state
stays inspectable via show_stack, and erroring would break removal in exactly the
states needing repair. Errors remain errors. The stray bare `puts stderr` (which
printed the literal word stderr to stdout) is gone.
- known_renamers reconciliation (acceptance 2 "decision recorded in this file"):
defaults changed to the strings the vendored packages actually register -
`packagetrace packagesuppress` (plain words, per their rename_command -renamer
calls; packagesuppress 0.4 renamed all-lowercase in 2024). The historical
`::packagetrace ::packageSuppress` matched no registration ever made. The defaults
matter for cross-reload recovery: get_IMPLEMENTOR reads the magic comment of an
override installed before a commandstack state reset, and only a default matching
the recorded renamer string routes that into the cooperate branch; the stale
defaults also let remove_rename accept never-registered renamer strings. The
defaults pin (commandstack_known_renamers_defaults) updated.
- did_rename shape: performed-rename records append `did_rename 1` as the LAST key
(token/renamer stay 1st/2nd - lsearch -index 1/-index 3 contract pinned unchanged);
both no-rename paths return `{implementation {} did_rename 0}` so consumers may
test either key (in-tree consumers test implementation eq "" - unchanged).
- commandstack::next: helper resolving the CALLER's COMMANDSTACKNEXT via upvar 1 and
invoking it at the override's caller frame (uplevel 2) - result and caller-context
equivalent to the manual `uplevel 1 [list $COMMANDSTACKNEXT {*}$args]` convention
(pinned by a namespace-context probe); clean error outside an override body. The
COMMANDSTACKNEXT variables remain the primitive interface (consumers unchanged).
- "Pre-existing non-GAP pins unchanged" (acceptance 5) interpretation: pins whose
expected values encode surfaces this goal deliberately changed were updated
minimally to the contracted behaviour (basic_record + missing-command + same-body
pins gained did_rename / debug-gating context, known_renamers defaults pin
reconciled, Rename_stack parking pin now asserts retrievability + 1/0 returns);
every other pre-existing pin passes untouched. The five _GAP_ tests flipped to
fixed-behaviour pins under non-GAP names (samerenamer_new_body_distinct_token_chain,
third_samerenamer_rename_succeeds, rerename_after_other_renamer_chains,
delete_stack_guard, get_implementor_classification).
Verification evidence:
- commandstack suite 33/33 (29 baseline tests: 5 flipped in place, none removed;
plus 4 new tests) green on tclsh90 9.0.3 and the punk86 kit (8.6).
- packagepreference suites 6/6 on both runtimes: new installguard.test (double
install returns 0 silently with one stack record; uninstall/re-install cycle gets
the next unique tokenid {::package punk::packagepreference 2}, all silent) +
staticpolicy.test 4/4 unchanged.
- Live consumer smoke (`bin/punk91 src script`): source commandstack 999999.0a1.0
loaded in a real shell boot - packagepreference installed on ::package (1 record,
renamer punk::packagepreference, did_rename key present), `package require http`
resolves through the override, punk auto_execok and punk::nav::fs cd stacks live.
- Minted via `tclsh90 src/make.tcl modules`: modules/commandstack-0.6.0.tm +
modules/punk/packagepreference-0.2.1.tm; minted copy requires clean and exposes
commandstack::next. Bootsupport/vfscommon snapshots deliberately not promoted
(per Notes - next promotion cycle picks the fixed module up).

2
punkproject.toml

@ -1,6 +1,6 @@
[project]
name = "punkshell"
version = "0.49.2"
version = "0.49.3"
license = "BSD-2-Clause"
url = "https://www.gitea1.intx.com.au/jn/punkshell"
#packager: declared identity for published artifacts (declarative, not proof -

4
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 <script>`)
- `punkboot/utils/` — punkboot::utils tests (`testsuites/utils/`): the make.tcl helper module. `utils.test` (punkproject.toml/CHANGELOG version parsing), `vcsdirty.test` (dirty fossil/git provenance warnings behind the producing-commands gate - git-fixture based), and `bootlibrary.test` (G-125 boot-precondition predicate `vfs_boot_library_report`: both tcl-library conventions - `tcl_library/` for zipfs-attached kits and `lib/tcl<major>.<minor>/` for starkit-style kits - the companion-file requirement that stops the `lib/BWidget1.10.1/init.tcl` every punkshell kit carries from answering for a tcl library, near-miss reporting, missing/empty trees, and a sweep asserting every assembled `src/_bake/*.vfs` tree still passes so the gate cannot fail kits that boot today). All three are pure fixture tests - no mint or bake is run; the make.tcl side of the gate is pinned separately in `shell/testsuites/punkexe/maketclbootgate.test`
- `modpod/` — modpod (vendored zip-based .tm wrapper) tests (`testsuites/modpod/roundtrip.test`, G-111 - the module's first suite): make_zip_modpod wrap emits stub+zip (\x1A separator, PK local header), is_valid_tm_version accept/reject, and child-process load round-trips of per-run generated fixture pods - require from a real-disk module path (stub self-mounts via zipfs, or the vfs::zip fallback on 8.6), the -offsettype file form, the unwrapped #modpod-<pkg>-<ver> redirect form (extracted folder beside the .tm is sourced directly - exact path asserted, no mount signature), a binary payload (dll discovered by a child probe among packages NOT already loaded in a bare child, repo lib_tcl<N> trees offered as auto_path - no committed binaries) loading from the mounted pod in a fresh child, and the tm-residing-on-a-zipfs-path zip-in-zip form (childzipfs-gated: skips on 8.6, the recorded G-034-class limitation). Child spawn probes the kit `script` subcommand form first, then plain script-file dispatch (native tclsh)
- `commandstack/` — commandstack (cooperative command renaming) characterisation tests (`testsuites/commandstack/commandstack.test`, 2026-08-03 - the module's first suite, usage-driven from punk::packagepreference/packagetrace/packagesuppress/punk-auto_execok/punk::nav::fs-cd): record shape as a contract (dict key order for the lsearch -index 1/-index 3 convention, token, `implementation {}` no-rename signal), COMMANDSTACKNEXT/COMMANDSTACKNEXT_ORIGINAL delegation, multi-renamer stacking with removal in any order (bottom-removal re-linking), builtin renames (next_implementor `original`), remove_rename's three argument forms + unknown-renamer errors, show_stack fallback render, Rename_stack parking quirks, util::get_IMPLEMENTOR, lib::split_body round-trip, lib::splitx, the help overview, and lazy punk::args registration of the PUNKARGS docs. Known defects pinned as _GAP_ tests: tokenid stuck at 1 (apply-local counter) making same-renamer re-renames stack duplicate tokens whose dispatch bypasses intermediate layers and a third rename collide on the parked name; the get_IMPLEMENTOR `builtin` branch unreachable (unqualified `info commands tcl::info::cmdtype` pattern inside commandstack::util); Delete_stack under a live rename causing self-delegation recursion. Behavioural tests run in fresh child interps per test (module sourced by path relative to the test file; a ::puts shim captures module stderr warnings for assertion and keeps runner output clean); descriptions are single-line per the tcltestrun banner-parsing contract in src/tests/AGENTS.md. Green on tclsh90 (9.0.3) and punk86 (8.6)
- `commandstack/` — commandstack (cooperative command renaming) tests (`testsuites/commandstack/commandstack.test`, 2026-08-03 - characterisation suite + the G-160 hygiene-pass contract at commandstack 0.6.0; usage-driven from punk::packagepreference/packagetrace/packagesuppress/punk-auto_execok/punk::nav::fs-cd): record shape as a contract (token first/renamer second dict key order for the lsearch -index 1/-index 3 convention, trailing `did_rename` 0|1, `{implementation {} did_rename 0}` no-rename signal), COMMANDSTACKNEXT/COMMANDSTACKNEXT_ORIGINAL delegation + the `commandstack::next` helper (caller-context parity with the manual uplevel convention pinned), unique+monotonic per-(renamer,command) tokenids (same-renamer re-renames chain and are removable by exact token, third rename succeeds), multi-renamer stacking with removal in any order (bottom-removal re-linking), builtin renames (next_implementor `original`), remove_rename's three argument forms + unknown-renamer errors, the token->implementation map get_next_command resolves through (map/stack consistency pinned across rename/remove; parked stacks keep dispatching), channel discipline (silent full cycle with debug off; warnings only under debug), debug argument validation, -renamer misplacement errors, get_stack raw-key-first retrieval of Rename_stack-parked records + Rename_stack 1/0 returns, Delete_stack live-record guard (errors; empty/missing return 1), get_IMPLEMENTOR classification incl builtin-where-cmdtype-exists (dynamic expectation - undetermined on 8.6), lib::split_body round-trip, lib::splitx, show_stack fallback render, the help overview, and lazy punk::args registration of the PUNKARGS docs. Behavioural tests run in fresh child interps per test (module sourced by path relative to the test file; a ::puts shim captures module output for silence/warning assertions and keeps runner output clean); descriptions are single-line per the tcltestrun banner-parsing contract in src/tests/AGENTS.md. Green on tclsh90 (9.0.3) and punk86 (8.6)
- `punkcheck/` — punkcheck module tests (install, summarize_install_resultdict, installtrack)
- `punk/ansi/` — punk::ansi tests (`testsuites/ansi/`): ansistrip/ansimerge, plus characterization of the ANSI-at-position mechanisms (`ansistring.test`: INDEX/INDEXCODE/INDEXCHAR/RANGE/INSERT grapheme indexing with SGR-prefix merging, INDEXCOLUMNS/COLUMNINDEX double-wide column mapping, trim/VIEW), code splitting invariants (`ta.test`: detect/detectcode distinction, split_codes/split_codes_single/split_at_codes shapes and round-trip) and single-code/effective-state semantics (`codetype.test`: is_sgr_reset/has_sgr_leadingreset, has_any/all_effective, sgr_merge, sequence_type classify), grepstr characterization (`grepstr.test`: return modes incl summarydict (linemap pinned as always-present - the -help says -n-only, reconciliation deferred to the planned hygiene pass), exact highlight SGR wrapping, -n line numbering, invert + empty-highlight strip, -C context/breaks, capture groups, and the tab deficiency: warns once per call on stderr, single-pass tab line survives - the multi-pass mangling is pinned at consumer level in punk/ns corp.test), and untabify characterization (`untabify.test`: -stops int/list/terminal, -with spaces/unicode/custom-pair, multiline, errors, plus the EXPERIMENTAL -plastic elastic-tabstop mode deliberately pinned-as-interim and retained for possible repl editbuf use). Console queries (get_tabstops/get_size + punk::console::tabwidth) are mocked per the overtype renderline.test pattern - they emit live terminal queries that block/error headless. ANSI codes in these tests are literal escape strings so results are colour-state independent
- `punk/args/` — punk::args tests (`testsuites/args/`): parsing, choices/choicegroups, forms, rendering/indentation characterization, synopsis display characterization (`synopsis.test`: basic italic argname/`<type>` 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), -parsekey characterization (`parsekey.test`: result/received/solos/multis keying, shared-key required satisfaction and defaults, mash-path and prefix-abbreviation keying, plus GAP pins for last-defined-member default precedence, cross-member -multiple value loss, parsekey/optname collision conflation, and values/leaders parsekey breakage - desired-behaviour pins disabled behind punkargsKnownBug in `testsuites/dev/parsekey-knownbugs.test`), 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 conditional on class presence - expectations derived from the running interpreter, green on 8.6/8.7/9.0; under 8.6 run the file directly via a plain tclkit + tcltest driver since runtests' harness needs newer infrastructure)
@ -49,7 +49,7 @@ Unit tests for editable source modules under `src/modules/`, `src/modules_tcl8/`
- `punk/ns/` — punk::ns tests (`testsuites/ns/`): cmdwhich/cmdinfo/cmd_traverse doc-lookup flow (`cmdflow.test`, G-040 parity), 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); remaining GAP pins for pseudo-command cmdtype + space-form docid prefixes (G-051, real `string is` pins behind the have_tclcoredocs constraint), TclOO undocumented-method fallback (G-052), and synopsis marking absence (G-050)), 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 {} <prefix>` 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)
- `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 ::. Suite conventions learned the hard way: 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

Loading…
Cancel
Save