User-approved contract amendment replacing the day-1 file-relpath filter: one
directory-oriented pathglob semantics at every layer, with the ergonomics gap
closed in the syntax itself.
punk::path 0.4.0:
- *** as a whole segment matches ZERO or more segments (join-aware regex in
pathglob_as_re: an adjacent separator is absorbed into an optional group),
so X/*** = X and everything below - the subtree spelling; ***/f.txt matches
at any depth including the root.
- include separability fix: an exact or single-segment-glob full match no
longer sets allbelow (the deep walk previously dragged the whole subtree in
for X and X/* patterns; the zipfs walk was already separable).
- exclude separability fix (new exclude_state classifier, both walks): only
**|***-tail patterns prune the matched subtree; other matches exclude just
that directory's files - the **/_aside vs **/_aside/** argdoc distinction is
now real. Dead _path_matches_any removed.
- legacy bare-* include collapse removed (a * in -include-paths is the
one-below lattice form, not a match-everything alias; no caller used it).
- globmatchpath default-nocase driveletter exception rewritten as a direct
regex-head rewrite (the regex-text file-split broke on c:/***'s glued group
and accepted non-alpha drives).
- path.test +5 lattice/*** pins (40 total).
runtests.tcl:
- -include-paths/-exclude-paths pass through to treefilenames unchanged;
argdocs teach the separable X | X/* | X/** | X/*** lattice; directory and
file-name axes independent (tails); single-file targeting = exact dir
pattern + file tail.
- -serial-paths reconciled to the same directory-of-file reading (default now
modules/punk/console/*** modules/opunk/console/*** via
runtests_discovery::dir_matches_any) - the pre-existing file-path serial
matching was the other same-option-different-referent divergence.
- per-pattern zero-match stderr advisory (the X/**-for-subtree foot-gun points
at X/***).
- json report emitter: whitespace-padded entier-looking values now take the
quoted-escaped path ('string is entier -strict' accepts surrounding
whitespace - a failed test's "0\n" result_was embedded a raw newline and
truncated the parseable report line).
- testsupport/discovery.tcl now a thin passthrough (requires punk::path
0.4.0-); pathdiscovery.test rewritten to the directory-semantics contract
(22 tests incl. the X/** zero-match advisory characterization); AGENTS.md
targeting guidance swept to /*** across src/tests and src/modules/opunk.
Verification (native tclsh 9.0.3, piped, serialized): 45-probe matrix, path
suite 40/40, runner suite 22/22; vs the pre-G-093 baseline the default
discovery FILE SET differs by exactly the added runner suite and result
parity only by the five new path tests (+ that suite); mode parity -jobs 16
vs singleproc: PARITY ok (94/1037/failed=1 exec-14.3). Goal contract amended
in the detail file; full record there.
Claude-Session: https://claude.ai/code/session_01BNUVVkYq9vHa6G3S9a3XTZ
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
scriptlib_resolve now lets an extensionless (or unknown-extension) lib:<name>
call match a file named exactly <name> when its first lines identify it as
tcl: a leading '# tcl' comment (prefix, case-insensitive), a shebang naming
tclsh/tclkit/wish, or the portable sh-trampoline ('#!/bin/sh' with a
commented 'exec tclsh' continuation - detected within the first 4 lines).
New internal punk::path::system::scriptfile_is_tcl does the bounded sniff
(512 bytes, UTF-8 BOM and CRLF tolerated, directories/unreadable files
rejected). When both <name> and <name>.tcl exist, the spelling matching the
call wins, checked per scriptlib location so kit-internal directory
precedence is never crossed by a spelling preference.
.kit joins the known extensions: lib:<name>.kit previously had .tcl appended
(searched <name>.kit.tcl), which made the shell subcommand's do_tclkit
dispatch arms unreachable - lib: kit dispatch is now restored. Result dict
reworked: scripttype (tcl/kit/py/pl/ps1/sh or empty) + notes keys added,
scriptname is now the matched relative name, and matches require file isfile.
app-punkshell and app_shellrun lib: handling refactored onto the shared
resolver (previously independent inline copies of the policy), fixing two
silent-failure bugs in that copy: no message at all when a scriptlib dir
existed but lacked the script, and the error listing showing
<kit>/scriptlib rather than the <kit>/app/scriptlib actually checked.
app-punkscript's post-resolve gate now uses scripttype and its not-found
report includes the identification skip notes. The unused has_globchars
vestige is dropped.
Fixtures scriptlib/_punktest/{extless,dual,dual.tcl,shebang_sh,notatcl} and
5 new scriptexec.test cases (extensionless resolve, both precedence
directions, trampoline shebang + argv, non-tcl skip note on not-found);
suite passes 17/17 against a freshly built punk902z kit. Sniff helper unit
checks pass under tclsh 9.0.3 and 8.6. punkshell project 0.13.0 -> 0.14.0.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
app-punkscript accepts lib:<name> (with or without .tcl - extensionless
appends it) as the shell subcommand does: `punkexe script lib:hello` or
bare `punkexe lib:hello` via reclassification. The prefix always wins; a
literal path beginning lib: (pathological - colon is illegal in Windows
filenames) is reachable via ./lib:... Not-found errors list every
searched location; only .tcl runs via the script subcommand.
Resolution policy is factored into punk::path::scriptlib_resolve
(PUNKARGS-documented) rather than copied inline: kit-internal
app/scriptlib first and deliberately not externally overridable, then
scriptlib dirs relative to the executable - the same policy
app-punkshell encodes inline (todo noted: refactor the shell path onto
the shared proc). Share definitions via modules, not launcher control
flow.
Verified on both generations (punk902z, punksys): lib:hello
extensionless and explicit, bare-arg reclassification, not-found
candidate listing (bin/scriptlib then <root>/scriptlib for a bin/ exe).
Project version 0.4.0 (backward-compatible behaviour addition).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com