Tree:
269b1af82b
master
v0.1a
${ noResults }
112 Commits (269b1af82b6c37e6df5d3939bdb5acc2a6ef292e)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
269b1af82b |
G-095: punkcheck 0.6.0 concurrent-writer safety - atomic saves, advisory event-scoped locking
Saves are write-temp-then-atomic-rename with bounded retry for Windows
sharing violations; load_records_from_file retries transient open
denials during a writer's replace window (parse errors stay strict -
they mean real corruption). Readers gain torn-read immunity with no
reader-side protocol.
New punkcheck::lock namespace (PUNKARGS-documented): advisory sibling
lockfile <punkcheckfile>.lock via open {WRONLY CREAT EXCL}, contents
naming holder pid/host/installer/timestamp, channel held open for the
duration, in-process reference-counted re-acquisition (sequential
make.tcl installers over one root must not self-deadlock). start_event
acquires; event end / installtrack destroy releases; flushes and
chokepoint saves outside an event take a transient lock. Contention
retries with backoff to -timeout (env PUNKCHECK_LOCK_TIMEOUT, default
15s) then errors naming the holder; stale locks break on provably-dead
holder pid (twapi process_exists / kill -0, capability-gated) or age
(-staleage / PUNKCHECK_LOCK_STALEAGE, default 300s).
Deferred flushes merge own records (INSTALLER by -name, touched
FILEINFO by -targets) into freshly-loaded file state under the lock
instead of wholesale overwrite; an mtime/size tripwire warns when a
non-protocol writer (e.g. older vendored punkcheck) touched the file
between load and save.
Duplicate-INSTALLER recovery: clean actionable error when stdin is
non-interactive (punkcheck::lib::stdin_is_interactive - strict twapi
GetConsoleMode on the real stdin handle on Windows, -inputmode probe /
test -t 0 on unix); the interactive prompt gains the synced-targets
deletion-wedge caveat. default_excludefiletail_core adds .punkcheck.*
so protocol siblings are never installable content.
Consumers verified without edits: cli and five make.tcl sites end their
events (lock released at end); make.tcl's vfs/bin kit flows destroy
their installers on every path (destructor releases).
New concurrency.test (6 tests): two child installer processes with a
polling reader (no parse errors, both installers survive, no duplicate
INSTALLERs, no lock/tmp leftovers), lock timeout naming the holder then
success after release, dead-pid and age stale-breaks against planted
lockfiles, non-interactive duplicate-INSTALLER error via pipe-stdin
child, protocol-sibling exclusion pin.
Matrix: Windows Tcl 9.0.3 84/84 (runtests), Windows Tcl 8.6.17 84/84
(direct tcltest drive - the runtests harness itself needs lpop under
native 8.6), linux WSL tclsh 8.6.14 84/84 (native-FS staged run).
punk/mix subtree unaffected (150 pass / 1 known constraint-skip).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
2 weeks ago |
|
|
b838a53921 |
G-094: punkcheck 0.5.0 single record lifecycle - OO installtrack sole implementation, per-event persistence policy
installtrack/installevent is now the only implementation of the .punkcheck record lifecycle (targetset init/add-source/started/end). Each event takes a persistence policy at start_event (-persistence eager|deferred): eager keeps the current per-op read-modify-write behaviour; deferred accumulates updates in the installtrack's in-memory working recordset until an explicit $installer flush (event-scoped save). QUERY stays never-persisted. punkcheck::install rebuilt as a tree-walking OO consumer in deferred mode - its records now carry the full field set (-metadata_us/-ts_start_transfer/ -transfer_us/-cksum_us and -targets_cksums incl all-targets mode), pinned field-equivalent with OO-installed records by the new lifecycle.test. Legacy zero-caller proc pipeline (start_installer_event, installfile_begin/ started_install/finished_install/skipped_install) retired to error-with- pointer shims; installfile_help rewritten for the OO lifecycle; the live shared engine installfile_add_source_and_fetch_metadata is unchanged. punk::mix::cli's commented-out legacy call sites removed (0.5.1, no behaviour change). Single save chokepoint: every lifecycle write funnels through installtrack save_working_recordset - the G-095 attachment point. Coherence and latent fixes (each pinned in lifecycle.test): - start_event refreshes the working recordset; sequential events on one instance no longer clobber prior targetset writes (end/end_event now clears the active-event slot, so a second start_event is valid) - event reconstruction maps record -ts_begin/-ts_end to constructor opts (flush no longer rewrites prior event history timestamps) - installtrack as_record: stray backslash-space wrote -name with a trailing space, breaking by-name lookup after any flush - get_recordlist misspelled variable; targetset_dict nonexistent helper - extract_or_create_fileset_record stdout print removed (isnew returned; targetset_init reports via debugchannel); dead targetset class removed Pin flip (recorded in installtrack.test): the full-lifecycle test's end + end_event double-end now correctly errors - lifecycle uses one of $event end / $installer end_event, matching all real consumers. Suites: punkcheck install/installtrack/lifecycle 78/78, punk/mix subtree incl cli prune.test 144 pass / 1 constraint-skip on native Tcl 9.0.3. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
8dde10bbdf |
runtests: punk-kit hosts launch children in 'src' package_mode; tally shows Testfiles-failed
Under punk91/punk902z/punk905_beta, '-include-paths modules/punk/console/*** -jobs 16' failed all 7 files with zero tests run: child processes boot via plain kit script dispatch, preloading kit-stamped punk packages (punk::console 0.7.2) before the payload's src paths apply - the suites' pinned 'require punk::console 999999.0a1.0-' then version-conflicts and the child exits 1 (the known shadowing runtests already warned about). Fix: when the host is a PUNK kit (kit container heuristics AND the ::punkboot namespace marker from punk_main.tcl boot) children launch as 'kitexe src child_test_runner.tcl ...' so they boot the project's src dev modules - matching what the payload selects. Non-punk kit containers (e.g tclsh90szip.exe: zipfs app mount, no punk boot) keep the old warning and get no extra arg. runtests_run_child_process gains a required exemodeargs param (tpool info args/body replication unaffected). Tally: file-level failures are not test results, so a FAIL run could sit beside 'Failed 0' unexplained (user report). The tally line now appends a fail-coloured 'Testfiles-failed N' whenever testfiles failed. Verification: console suites 71/71 under punk905_beta, punk91, punk902z (previously 0 run / 7 files failed); native Tcl903 + suite tclsh90s unchanged 71/71 with no modeargs; tclsh90szip warning path passes; tally demo shows 'Total 0 ... Failed 0 Testfiles-failed 1'. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
d3cc914a52 |
punk::libunknown epoch-copy unsoundness fix - tkconsole repl failure root-caused (G-098)
Copying ::punk::libunknown::epoch verbatim into a fresh interp/thread carries per-epoch 'added' maps that drive zipfs_tclPkgUnknown's can_skip_sourcing short-circuit - sound only in the interp that performed the scans. Packages the donor obtained at an earlier epoch (or with no unknown call: Thread is baked into thread::create'd threads) are absent from the donor's current-epoch map, so recipients skip their pkgIndex sourcing and requires fail where stock tclPkgUnknown would succeed. Bit deterministically as repl_console_backend_tkconsole under the suite 9.0.5 runtime: 'package require Tk' bumps the epoch pre-init, the codethread inherits the post-bump sparse map, the code interp then can't find vfs/Thread/registry, its init aborts before the G-001 conredirect junction vars exist, and the first pending-collect error left the repl reader inactive until the driver failsafe. Tcl903 escaped only by an accidental extra epoch bump in its code interp (fresh map, full rescan). Fix: punk::lib::libunknown_epoch_export (PUNKARGS-documented) - epoch record with every 'added' map emptied; counters/untracked/scripts/index globs preserved. Used at all four propagation sites (interp_sync, snapshot, repl %lib_epoch%, repl safe-arm). Hardening: the repl pending-collect now tolerates missing junction vars so a code-interp init failure can't wedge the reader. Also: test socketpairs pinned to -myaddr 127.0.0.1 (all-interfaces listens raised windows firewall consent popups for each newly built test exe - user datapoint). Verification: consolebackends 3/3 both runtimes (suite 42s->14s); full runtests sweeps identical on suite runtime and Tcl903: 1037/1021/15/1 with the sole failure exec-14.3 (documented machine baseline). G-098 acceptance sweep met. Pre-existing PUNK_TEST_TK opt-in quirk noted in the goal (silent early end, both runtimes, out of scope). Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
bc958300b1 |
G-093 rework: punk::path *** pathglob + separable lattice; runtests passthrough targeting
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
|
2 weeks ago |
|
|
e5060160b4 |
G-093: runtests file-relpath path targeting - include fix, -exclude-paths, -discover-only
Root cause (recorded in the goal file): punk::path::treefilenames matches -include-paths against the DIRECTORY containing files, and its documented X/** boundary semantics exclude files directly in X - so suites keeping .test files at the subtree root (scriptwrap, binscripts, punkexe) were silently missed by X/** targeting: the G-092 four-pattern (2/13 files) and repeated-flag (zero files) failures. punk::args -multiple accumulation probed healthy - repeated flags and a single space-separated value reach discovery identically; no punk change was needed or made. runtests.tcl now filters the tailbase-relative FILE paths after an unrestricted walk (new testsupport/discovery.tcl: globmatchpath, any-include-match, exclusion wins): X/** includes files directly in X, an exact relative path targets a single file, a bare directory path matches nothing (append /**). -exclude-paths exposed (same syntax and accumulation, exclusion wins over inclusion). -discover-only prints the discovered list plus a RUNTESTS_FILES tcl-list line and exits before any run machinery - subsecond via a two-stage boot (discovery phase loads only punk::args + punk::path; punk/Thread/shellrun/punk::tcltestrun and the testinterp/child path assembly load after the exit). New regression suite runner/testsuites/discovery/pathdiscovery.test (23 tests: pure filter, fixture-tree walk+filter, end-to-end -discover-only children including both G-092 characterization forms; ~7s wall, parallel-safe). src/tests/AGENTS.md targeting wording reconciled; new src/tests/runner/AGENTS.md. G-093 index status proposed -> active (user-directed). Verification (native tclsh 9.0.3, piped Bash context): pre-change baseline default -jobs 16 (93 files / 1010 tests / failed=1 exec-14.3 only) vs post-change -jobs 16 with -exclude-paths runner/**: PARITY ok; post-change default run differs from baseline only by the added suite (+23 passing); mode parity -jobs 16 vs singleproc sequential: PARITY ok (94/1033/1). Claude-Session: https://claude.ai/code/session_01BNUVVkYq9vHa6G3S9a3XTZ Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
e2fc7332fe |
G-087 stages 4+5: overlay merge primitive, marker/matrix retirement, version seeding
Stage 4 - documented overlay semantics implemented (commandset::layout 0.2.0): layout_materialize resolves a layout to its overlay chain (vendor tier then custom tier per store+vendor, <name>@<base> derived-layout folders expanding their base chain first, cycle-guarded) and composes multi-folder chains into a disposable staging dir applying <item>.anti deletion markers (zero-byte marker files recommended - committable, unlike the originally documented empty marker folders, which are also accepted). Single-folder chains with no markers are used in place, so punk.project (store and zipfs modpod) behaviour is unchanged. project.new (commandset::project 0.4.0) copies from the materialized path and the layout listing/scanning commands show the effective merged view. Fixtures: punk.othersample is now a live derived layout (new custom-deck fauxlink ref + .gitignore.anti demo marker); extra.txt/store README rewritten to the implemented semantics. New tcltest suite src/tests/modules/punk/mix/testsuites/layout/materialize.test (20 tests). Anti markers deliberately stay a plain filename convention rather than tag-bearing fauxlinks: a fauxlink is a reference tooling may follow (fcat auto-follows), a marker is a tombstone with no target. Stage 5 - retirements and generated-project version seeding: - The empty unimplemented child-side src/PROJECT_LAYOUTS_CREATE_FROM_... marker folder is deleted along with its project.new and make.tcl sync exclusions. - The vendor/custom x _project matrix collapses for layouts: custom/<vendor> is the one override level; _project folders join no overlay chain (the pseudo-vendor remains for decktemplates module/utility templates only). - project.new seeds generated projects post-materialization (only-if-missing, never from payload): punkproject.toml ([project] name + 0.1.0), a matching CHANGELOG.md ## [0.1.0] header, and punkorigin.toml - an interim generation provenance baseline (utc, layout name + resolved store target, punk::mix::templates version, punkshell version when derivable, origin path) for the G-027 pull design to adopt (noted in G-027). Also: script-mode/programmatic project.new robustness (explicit shellrun require; punk::mix::util askuser/do_in_path/foreach-file fully qualified - the util:: shorthand exists only after cli commandset import). Includes the concurrently-landed (other session, previously uncommitted) 0.3.1 early module-name validation fix in project.new, shipped within the 0.4.0 bump. G-087 flipped achieved 2026-07-19 (verification in the detail file; archive move follows in the next commit). punkshell 0.16.0 -> 0.17.0. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
4fc1d62ce2 |
agent skills: tcl-nslist namespace discovery; punk::ns 0.9.1 packagetails fix
New scriptlib/developer/nslist.tcl backing the new cross-framework tcl-nslist agent skill (.agents/skills/ canonical, .claude/skills/ synced copy): the discovery counterpart of whatis.tcl - lists what a namespace/package actually exposes at runtime via punk::ns::get_ns_dicts (the n// machinery): child namespaces with loadable-package markers, commands classified by kind, punk::args-documented commands, -synopsis whole-namespace usage lines, -pathcommands namespace-path resolution. Auto-package-requires unloaded packages and follows ensemble commands to their implementation namespace. The tcl-whatis skill/script cross-reference it (whatis redirects with a hint when the queried name is a namespace, not a command). punk::ns 0.9.1: get_ns_dicts packagetails/packageprefixes initialization moved inside the per-namespace loop - with multiple matched namespaces (path globs, trailing **) every dict after the first carried the union of all earlier namespaces' entries, mis-marking non-package children in nslist/n// underline styling and in the returned data; a child with several deeper packages below it was appended to packageprefixes once per matching package (now once). Pinned in nslist.test (nslist_classification_multins_package_buckets_reset). Documentation-only PUNKARGS added for get_ns_dicts (returned dict keys documented) and nslist_dict; parsing stays manual. Root AGENTS.md: introspection note + scriptlib/developer inventory updated. Project version 0.15.1 + CHANGELOG entry. punk::ns suite 102/102 pass. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
7e9eced51e |
lean test children: explicit suite deps, shellrun preload removed (-jobs ~50s)
The multiproc child bootstrap no longer preloads shellrun + the no-op runx warmup: 17 test files gained their missing explicit package require lines (punk::ansi for the bare ansi suites, punk::args for the bare args suites incl dev/dynamic-cache, punk::lib for the lib suites and for grepstr/untabify/examples whose punk::ansi/punk::args commands reach punk::lib internally, plus textblock for examples.test - caught by the empirical lean run: punk::args only soft-requires textblock and punk::args::helpers::example calls textblock::join). Children now load only tcltest plus each file's declared deps; the singleproc testinterp keeps shellrun as the runner's own capture mechanism. Module-web finding recorded in src/tests/AGENTS.md and the test-file comments rather than fixed: punk::ansi and punk::args call punk::lib without requiring it, and a hard back-require is blocked by punk::lib's own hard require of punk::args (cycle) - deps declared at test level; a considered module-level resolution remains open. UDP watch-mode note folded into child_test_runner.tcl per user direction: no interaction today (the parent relays child output at file granularity; verified post-lean - events + relay flow); any future live per-child tee must be conditional on PUNK_TEST_UDPTEE so unwatched children stay lean. Verified (native tclsh 9.0.3): full-suite PARITY ok for lean -jobs 16 vs the pre-lean baseline, between repeated lean -jobs 16 runs, and lean -jobs 1 vs -jobs 16 (989/973/15/1, exec-14.3 sole failure). Timings: -jobs 16 70.7s -> 49-53s; sequential multiproc ~5m30 -> 4m32; singleproc unchanged. AGENTS scaling guidance refreshed. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
276eff850d |
runtests: ANSI red/green/yellow status indicators for human output
User request after console-context failures went unnoticed: compact per-file status words, failure/warning list entries, the per-file had-failures/passed/child-failed notices, the markdown failures/warnings file lists, the tally Passed/Failed segments and a coloured overall STATUS on the DONE line are now SGR-coloured (green pass, bold red fail/error, bold yellow warning). Gating: -colour auto|on|off (default auto) colours only when stdout is a real windows console, detected via twapi GetConsoleMode on the STD_OUTPUT handle - the isatty-equivalent; get_console_handle proved unsuitable (it succeeds for piped children of console shells, verified both ways). NO_COLOR honoured in auto. Machine output (RUNTESTS_RESULT, json) is never coloured; piped output stays plain for agents (verified zero escape bytes piped, codes present with -colour on). Raw literal SGR is used rather than a+/a so the runner's indicators are independent of punk::console's process-global colour state (the same 2026-07-19 console runs showed that state shifting under mixed tty-ness). The previously UNCONDITIONAL raw-red errorInfo block in the file-error branch now goes through the same gate, so piped error output is cleaner than before. Also sharpens the -jobs guidance wording: subtree runs (e.g 28-file modules/punk/args/**: ~50s sequential vs ~11s at -jobs 16) benefit from -jobs - only single-file/few-file runs do not. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
913ea749a1 |
tests: decode console utf-16le stderr in capture_stderr helpers
dynamic_bad_tag_warns_once failed (count 0) ONLY in console-attached singleproc runs (user report; reproduced deterministically with stderr on a real console and stdout redirected): when stderr is backed by a windows console channel, a pushed chan transform receives the console driver's utf-16le wide-char byte stream - every ascii char arrives NUL-interleaved, so content regexps never match. The punk::args warning itself emits correctly, exactly once, inside the capture window (proven with marker writes: markers and warning all captured, all wide). Piped/file stderr and -jobs child processes deliver plain bytes, which is why every piped run passed. Fix in all three capture_stderr helpers (punk/args dynamic.test, punk/ansi grepstr.test, punk/ns corp.test - identical latent defect): if the captured data is NUL-interleaved, decode it as utf-16le (fallback 'unicode' for tcl 8.6) before returning. Verified: the console-attached args subtree run is green (246/243/3/0); piped runs unchanged. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
a590ff4aec |
src/tests/AGENTS.md: -jobs guidance updated with measured scaling curve
User-measured reference-machine numbers 2026-07-19: -jobs 8 ~79-86s, -jobs 16 ~61s (~5.6x vs ~5m40s sequential), plateau by -jobs 24 (~60s). Guidance now recommends -jobs 16 and records the plateau anatomy (slowest single child ~31s runtimecmd pair, serial console tail ~16s piped / larger under a real console, ~10s runner overhead). Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
57b3b86e0a |
runtests: report total elapsed seconds in all report styles
The '### runtests DONE at <ts>' human line gains '(elapsed <N>s)', the RUNTESTS_RESULT summary line gains a trailing elapsed_seconds=<N> key=value, and the json report gains a top-level "elapsed_seconds" field - matching the name already used by the watch-mode run-end event, which now shares the same computed value. Additive only; the parity tool reads named keys and is unaffected (verified on all three report styles). Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
5002371864 |
Split long-running test files to lower the -jobs parallel floor (G-092 achieved)
multishell.test (10 tests, ~105s solo child - the -jobs floor) split five ways along shared-fixture boundaries, every test moved verbatim with its provenance lines: multishell.test keeps wrap + structure/LF-only + exec smoke (incl WSL); multishell_wrapverify.test (fresh-wrap checkfile) and multishell_wrapdeterminism.test (byte-identical re-wrap) each re-pay the wrap fixture; runtimecmd_checkfile.test and runtimecmd_roundtrip.test guard the committed bin/runtime.cmd and its source round-trip with no wrap fixture at all. argparsingtest.test (17 tests, ~32s) split into timeit/discover/contract/first_call (11) + argparsingtest_compare.test (compare_*, 6). Assessed and left unsplit: dtplite.test (24.6s solo), scriptexec.test (12s); exec.test excluded as imported core material. File headers point at the src/tests/modules/AGENTS.md punk/mix bullet for the sibling map; the runtests longest-first weight table carries measured post-split weights. runtests_parity.tcl gains a -names mode: multiset comparison of '- testname:' lines from '-report markdown -show-passes 1' captures, file attribution ignored - verbatim moves compare identical, lost/ duplicated/renamed tests are reported. Verified (native tclsh 9.0.3): repeated -jobs 8 full-suite runs 1m26.3s / 1m26.8s (was 2m16s at G-091, ~5m40s sequential - 4.07x vs the pre-parallel baseline, 36.6% vs the G-091 reference); slowest child 30.7s / 31.3s (bound 45s); NAMES identical (989 occurrences) vs the pre-split sequential capture; tallies identical in every run (989/973/ 15/1, exec-14.3 sole failure, files 87 -> 92); PARITY ok -jobs 8 vs -jobs 1 and between repeats; repo clean after runs. Notable finding recorded in the goal file: child-wall contention inflation (~45% with 50s+ dominant children present) collapsed to ~15% once the work distribution was flattened - splitting reduced both the critical path and the contention itself. G-092 flipped to achieved 2026-07-19 and archived (GOALS-archive.md record, detail file with full verification evidence to goals/archive/). goals_lint clean. Also noted in the goal file, out of scope: runtests -include-paths multi-pattern/repeated-flag matching misbehaved during measurement (single value with four deep patterns matched one; repeated flags matched zero) - contradicts documented semantics, needs its own investigation. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
1a1847c2e7 |
runtests -jobs N parallel test execution (G-091 achieved)
-jobs N (implies -singleproc 0; explicit -singleproc 1 conflicts) runs test files through a tpool of N concurrent child processes with per-child capture files and tcltest -tmpdir subdirs, longest-first static-weight submission, and a -serial-paths serial tail (default: the console-state suites modules/punk/console/** + modules/opunk/console/**; piped-child-driven suites proved parallel-safe and each serial file costs its full child boot strictly after the parallel phase). Cached results feed the unchanged processing loop in discovery order, so reports are identical in shape and order to sequential runs. Watch mode emits file-collected events (completion order, output relayed there); file-end (tallies) stays discovery-order. The runner now reports jobs phase times and the ten slowest child WALL times (child wall includes boot + file-level fixture cost that per-test usec misses). Two Tcl-core-level behaviours found and worked around in the child spawn (see the verification record in the archived goal file): - concurrent BLOCKING execs from worker threads convoy on Windows (all return at the longest concurrent child's exit; plain sleepers 2-12s from 8 workers all walled at 12.0s) -> spawn via 'exec ... &' and poll per-pid tcl::process status; blocking fallback retained for runtimes without tcl::process (tcl 8.6). - Tcl_ReapDetachedProcs runs on every exec and purges finished background children process-wide, racing the poll (nondeterministic 'key <pid> not known in dictionary') -> tcl::process autopurge false + explicit per-pid purge after the status read. Verified on native tclsh 9.0.3: repeated -jobs 8 full-suite runs 2m16.2s / 2m15.6s with PARITY ok vs -jobs 1, between repeats, and vs the pre-parallel baseline (987-test identity, exec-14.3 sole expected failure); 2.58x vs the ~350s sequential baseline (2.41x vs one cooler-machine 5m28.8s sequential run - recorded in the goal file); repo clean after every run. G-091 flipped to achieved 2026-07-19 and archived (entry to GOALS-archive.md, detail file to goals/archive/ with the verification record; reference sweep updated runtests.tcl comments and the src/tests/AGENTS.md marker). goals_lint clean. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
a65f9e5b67 |
shellrun 0.2.0 runx -teelog + runtests UDP watch mode (PUNK_TEST_UDPTEE)
runx -teelog {-tag/-syslog/-file/-raw settings}: live tee of the
captured stdout/stderr to shellfilter::log workers (log sources
<tag>stdout/<tag>stderr) while captured/returned data is unchanged.
Implemented as write traces on the capture variables rather than extra
channel transforms: probing showed a tee_to_log float combined with the
float-locked capture junction is starved or loses its worker settings
through add/remove churn (float-placement logic is unaudited - README
'very unripe parts'), and shellthread's parked-worker adoption does not
re-apply settings (writes silently misroute to a previous target). Both
findings deliberately not addressed here - recorded for a proposed
shellfilter/shellthread audit goal. Tag workers stay open for reuse;
conflicting reconfiguration errors explicitly.
runtests.tcl watch mode: env PUNK_TEST_UDPTEE=<port>|<host>:<port>
streams runner lifecycle events (tag 'runtests', tcl-list
RUNTESTS-EVENT messages: run-start/file-start/file-end/run-end with
tallies) and test output (tags teststdout/teststderr) to a local UDP
listener via the same mechanism - live per chunk in singleproc mode
(runx -teelog inside the testinterp), relayed per completed file by the
parent in multiproc mode. Watch mode terminates the per-testinterp log
worker threads after each file; unwatched runs are unchanged (including
the pre-existing teehandle-worker leak, also noted for the audit). The
parent extends auto_path with <projectroot>/lib_tcl<N>/<arch> so
workers load tcludp 1.0.13+ (1.0.12 UDP_ExitProc = G-036 exit-hang
class).
Verified on native tclsh 9.0.3: full-suite result parity (87 files, 989
tests, exec-14.3 sole failure) for watch-off and watch-on singleproc
runs vs the pre-change baseline; focused watch runs in both modes
captured over UDP (events + live/relayed output). Viewer-side caveat
documented: tcludp's receive fileevent under Tcl 9.0.3/Windows
delivered only the first datagram (send side unaffected; .NET UdpClient
received all).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
2 weeks ago |
|
|
218fbb1c46 |
runtests.tcl: complete -singleproc 0 multi-process mode + parity harness
Multi-process mode previously execd bare test files with no environment (children died on their first package require) and misreported the crashes as missing-cleanupTests warnings with the stderr discarded. - testsupport/child_test_runner.tcl (new): per-file child bootstrap. Applies a runtests-generated environment payload (prefer latest, test tm paths, auto_path, modpod ifneeded defs, tcltest options; per-file -testdir computed child-side), warms 'clock format' before the module-path wipe (first script-level clock use loads msgcat from the runtime default paths, which the test paths do not supply), and mirrors the testinterp preload: package require shellrun plus one no-op runx -tcl call (runx execution pulls punk::lib; several suites depend on preloaded punk::* commands). - runtests.tcl: generate the payload per run; spawn children via plain exec with file-captured stdout/stderr and immediate-EOF stdin (mechanism reusable for future parallel -jobs scheduling); classify nonzero child exits as file-level failures with the stderr tail surfaced in all report styles (exit-0-no-summary remains the missing-cleanupTests warning); warn under kit executables (children boot with kit-stamped punk packages preloaded, shadowing src dev modules - prefer a native tclsh). - scriptlib/developer/runtests_parity.tcl (new): compares two '-report json' captures on result identity (per-file counts, failure/skip/warning identities; timings ignored), tolerating preamble noise and the ANSI SGR reset emitted on the JSON line. Verified on native tclsh 9.0.3: full suite singleproc vs multiproc PARITY ok (87 files, 989 tests, 973/15/1 with the documented exec-14.3 baseline as the sole failure); crash and warning classification exercised. Wall time ~5m50s in both modes. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
c05af65543 |
argparsingtest 1.0.0: per-style parser sets opts/tkstyle/tclstyle with N/A capability rows
Restructure of the parser-timing module around three calling styles:
- parser procs move into per-style child namespaces argparsingtest::opts /
::tkstyle (2 leading positionals) / ::tclstyle (2 trailing positionals),
with identical short proc names across styles; the test1_ prefix is gone
- hand-rolled parsers share a manual_ prefix (manual_ni, manual_switch,
manual_prefix, ...) so they group visually in the comparison tables;
test1_prefix2 removed (not meaningfully distinct from test1_prefix)
- tkstyle/tclstyle carry a representative roster (manual_switch baseline +
punkargs/punkargs_by_id/punkargs_parsecache + opt + cmdline + tepam);
style parsers return a {p1 p2 opts} list
- new 'unsupported' discovery status for library/style combos the backing
library cannot express: cmdline with leading positionals (getoptions stops
at the first non-option word - probe verified), argp with any positionals
(parseArgs walks the whole list as option pairs - source verified).
compare renders these as N/A rows below the timed rows so every library
still appears in every style's table
- harness procs (discover_parsers/timeit/first_call/compare) gain
-style all|opts|tkstyle|tclstyle and return results keyed by style;
-args requires a single -style (each style has its own default vector);
external probe keys drop the test1_ prefix (getopt/parse_args/argparse/cmdr)
- punkargs_by_id variants keep the eager punk::args::define as sole doc
source (the former duplicate argdoc lappend made the lazy namespace scan
undefine/re-register the id on first introspection); unused struct::set
require dropped; opt/cmdline/tepam requires hoisted to module top;
first_call library warm-ups extended with positional coverage
- test suite rewritten: 17 tests including per-parser {p1 p2 opts} contract
checks across both positional styles, N/A table rendering, roster counts
and the -style/-args error paths
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
2 weeks ago |
|
|
1eb9dc690b |
punk::path 0.3.0: extensionless tcl scripts via lib: (first-line identification)
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
|
2 weeks ago |
|
|
75cffe21f3 |
punk::args 0.12.6 + punk::ns 0.9.0: LLM-oriented usage output; tcl-whatis agent skill
punk::ns 0.9.0: cmdhelp (i) gains -return text - plain-text argument
documentation for machine/LLM consumption: no ANSI, no table layout, the
argument section of every command form rendered in one output under a common
header ('i -return text after' shows all six forms), G-041 form selection
still honoured when argument words are supplied, no advisory-parse error
preamble (-return dict remains the parse-status surface). Implementation
delegates resolution to the -return dict recursion and renders per-form via
the string renderer.
punk::args 0.12.6 (user direction; string-form layout explicitly not frozen -
no external consumers yet):
- arg_error renders the error message + per-form match detail exactly once,
BELOW the usage display (was above and below); bottom append suppressed for
empty messages.
- string renderer argument rows are single-line
'name TYPE:type(constraints) ?DEFAULT:'val'? ?MULTI:yes?' - type
constraints parenthesize onto the base type instead of line-breaking
mid-row; empty DEFAULT/MULTI labels and whitespace-only help blocks omitted.
- choices render as markdown-subset bullets '- `choice` - label' with label
continuations at a fixed deeper indent - choice names are now
machine-distinguishable from label text without ANSI. Structural contract:
column-0 lines bearing TYPE: are argument rows, indented lines are
documentation, backticked bullets are choices. Table cells unchanged.
New scriptlib/developer/whatis.tcl (runtime command introspection for
agents): resolved name, subcommand-chain resolution via punk::ns::cmdinfo
('whatis string is'), kind, providing package + loaded version, origin file,
proc definition file:line, punk::args synopsis; -body appends the runtime
body with file-relative line numbers, -doc the full plain-text argdoc via
cmdhelp -return text (with fallback for older punk::ns). Backing the
cross-framework tcl-whatis agent skill: canonical .agents/skills/tcl-whatis/
(Agent Skills standard - pi/OpenCode/Codex) with byte-identical copy in
.claude/skills/ for Claude Code; .gitignore gains !.claude/skills/ with the
fossil ignore-glob comment + exception-set docs updated per the dual-VCS
contract (fossil adds staged). Root AGENTS.md: .agents/skills index entry,
whatis pointer in Repo-wide Notes, scriptlib/developer example.
Tests: new pins cmdhelp_return_text_all_forms/_argword_form_selection/
_single_form_plain_marker (cmdhelp.test), rendering_stringmode_singleline_argrows
+ rendering_stringmode_choice_bullets (rendering.test); deliberate-change pin
updates: errorselection.test message matches gained leading * and cmdhelp.test
message pins sample the last line (message placement). Full source-tree suite
963/979 pass, sole failure the pre-existing exec-14.3 baseline; make.tcl
modules clean.
Project version 0.12.42 -> 0.13.0 with CHANGELOG.md entry.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
2 weeks ago |
|
|
c2574a7050 |
punk::args 0.12.5 + punk::ns 0.8.1: parse -cache overhaul, synopsis notation, eg resolution
parse -cache overhaul:
- VALIDATION trap's parse_cache write now explicitly gated on -cache (formerly
unconditional but landing in a discarded proc-local for -cache 0 by scoping
accident - 'variable parse_cache' only ran on the -cache 1 branch)
- cached validation errors stored as per {errorstyle callertext} render
variants under a {arglist definition form} main key (-caller dropped from the
main key - results don't depend on it); a missing variant falls through to a
fresh render. Previously the first caller's errorstyle and %caller%
attribution were baked in and replayed verbatim to later callers.
- @dynamic definitions (and legacy leading '-dynamic 1') are never cached so
re-evaluated substitutions always take effect; dev/dynamic-cache.test
known-bug pin flipped
- new punk::args::parse_cache view/clear proc (sgr_cache style); guarded
variable init; -errorstyle definition default corrected to the operative
'standard'. New parsecache.test (7 tests).
synopsis notation + internal @form -synopsis retirement:
- ::punk::args::parse/::parse_status dropped their stale @form -synopsis
overrides (omitted -cache/-caller) for auto-generated lines shaped with
-typesynopsis {<int|formname>...} on -form; drift pin
synopsis_parse_generated added
- punk::ns::synopsis no longer errors on custom @form -synopsis lines that are
not valid Tcl lists (e.g Tcl manpage style '?-form {int|<formname>...}?' -
's parse' raised 'list element in braces followed by ...'): non-list lines
take a textual command-head replacement fallback
- @form -synopsis directive help rewritten (display-only, any style, prefer
auto-generation, known warranted case: script-level/constructed ids);
::punk::args::synopsis -help gains a notation legend and a new @examples
block comparing Tcl man-page ?...? style with the bracket style (punk::args::eg)
eg usability + examples indication:
- punk::args::eg resolves relative/unqualified command names (punk::ns::cmdinfo
from calling context when loaded, else global qualification) - in namespaces
where it shadows the global 'eg' alias (e.g ::punk::args) 'eg list' returned
empty while 'i list' worked; unknown ids now return a message naming the id;
punk::ns::eg hands the typed name through on unresolved docids
- usage-table 'Example: eg <id>' header row now uses scheme colour CLR(check)
(interim display until G-088 footer/subtitle support)
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
2 weeks ago |
|
|
7a170a6a46 |
argparsingtest 0.2.0: parser timing comparison with cold+warm first-call metrics
New procs timeit/compare/discover_parsers/first_call for rough cross-parser
performance comparison (punk::args variants vs hand-rolled dict/switch/prefix,
tcllib opt/cmdline/tepam, argp), with PUNKARGS argdoc coverage throughout.
first_call times each parser twice in fresh child interps:
- cold: first call after package load (includes byte-compilation of the parser
proc body and any backing-library procs it invokes)
- warm: the backing library is pre-exercised via per-library sacrificial
warm-up scripts (library_warmups dict) so the timed call isolates per-proc
first-use cost. Replaces an earlier punk::args-only
'punk::args::parse {} withdef {}' warm hack that was unfair to the other
libraries under test and only partially warmed punk::args itself.
Child interps pin package requires to the parent's loaded versions
(punk::args, punk::lib when present, argparsingtest) - plain package require
prefers stable versions, so children otherwise timed older stable copies
visible on the module paths instead of the dev module under test; under
Tcl 8.6 the punk::lib pin also supplies the lpop compat shim punk::args::parse
needs, unbreaking punk::args timing in bare child interps there.
compare renders first_cold/first_warm columns (table), nested cold/warm
sub-dicts (dict/json). New test suite under src/tests/modules/argparsingtest.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
2 weeks ago |
|
|
c55225a392 |
punk::args 0.12.4: collision-aware resolve miss path (undefined-id warning retired)
resolve's first-sighting path for a rawdef whose @id is already registered with different content now purges the id's existing cache entries (quiet undefine) before registering, mirroring define's re-creation behaviour. Previously it repointed id_cache_rawdef while stale rawdef_cache_about / rawdef_cache_argdata entries lingered - two rawdefs claimed the same id and a subsequent define with the original text was a silent no-op (stale cache-about hit), leaving withid lookups stuck on the inline definition. The disabled blanket "called with undefined id" stderr warning is removed - it flagged supported inline usage (parse ... withdef, direct resolve calls). Guard checks id_cache_rawdef directly (id_exists also matches aliases, where the rawdef lookup would error). Known residual: the miss path still records no -defspace for @dynamic definitions first seen via resolve. New define.test pin define_resolve_id_shadow (characterized pre-fix: the re-define no-op reproduced with the purge disabled). punk::args suite green under Tcl 9.0.3 (228 passed, 0 failed). punkshell 0.12.41. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
2 weeks ago |
|
|
079caa9ae2 |
runtests.tcl: fix multiple trailing file tails collapsing into one glob
Two independent list-flattening bugs made `runtests.tcl foo.test bar.test`
match zero files, forcing agents to run files individually:
- the trailing glob value is -multiple 1, so its parsed value is a list;
plain lappend nested it as a single space-containing element
- punk::path::treefilenames declares tailglobs as a -multiple 1 positional
(one glob per argument), but the whole file_globs list was passed as one
argument, re-collapsing it (this also broke multiple globs supplied via
-tcltestoptions {-file {...}})
Single names always worked because a one-element Tcl list flattens to
itself, which masked both bugs. Verified: two file tails now discover and
run both suites (files=2, 40/40 pass).
Also note multi-file-tail support in src/tests/AGENTS.md Work Guidance.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
3 weeks ago |
|
|
86883a496c |
punk::ns 0.7.1: hygiene-pass backlog fixes - nslist -types default, nsjoinall error prefix (pins flipped)
Both fixes were pinned as known warts before the change; the pins flip with it:
- get_nslist: the -types default sat inside a braced dict-create literal, so it
was the literal string $known_types - any call without -types (notably bare
user-level `nslist`) errored with the malformed "Unrecognised namespace
member type: $known_types". An unsupplied -types now defaults to all known
member types. Pin flipped: nslist.test nslist_types_default_error_QUIRK ->
nslist_types_default (bare nslist renders children + commands). nslist's own
PUNKARGS -types gained help text, deliberately without a -default so the
passthrough stays absent when unsupplied.
- nsjoinall: the non-empty-prefix-vs-absolute-path error message carried a
copy-paste "nsjoin:" prefix - now "nsjoinall:". Pin flipped in
nsprimitives.test nsjoinall_edges.
- nscommands: commented out a development trace puts (">>> base: ...") that
polluted stdout on the weird-namespace path (same treatment as the 0.1.1
doc-lookup trace-puts cleanup; not pinned).
Suites green: ns/nav/repl 111/111; full source-tree run at the known baseline
(only core exec-14.3, pre-existing). buildversion 0.7.0 -> 0.7.1; project
0.12.34 + CHANGELOG.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
3 weeks ago |
|
|
13e38734b6 |
punk::ns 0.7.0: comment/doc hygiene pass - dead code removed, stale docs corrected, findings flagged
No change to shipped behaviour (ns+nav+repl suites 111/111 green). Minor bump
because unused procs were removed.
Removed (~1200 lines, recoverable via git history):
- the fully commented-out predecessor help command arginfo (~930 lines) -
its own header marked it replaced by cmdhelp
- superseded/deprecated name-primitive twins nsparts1, nsprefix1,
nsprefix_orig, nstail1, nstail_orig (never exported, no callers; NOT
drop-in equivalents - divergence on 5+ colon runs was pinned in
nsprimitives.test before removal; those divergence pins are removed with
the twins and replaced by a direct nsprefix long-colon-run pin - the
divergence record lives in the test file history, commit
|
3 weeks ago |
|
|
0c7168a178 |
ns tests: nsprimitives.test - name/path primitive + nseval-variant characterization (hygiene-pass pin gap closed)
20 pins for the previously near-unpinned punk::ns primitive region: nsparts/nsprefix/nstail/nsjoin/nsjoinall string behaviour incl weird colon-run (:::) splitting, trailing-colon parse ambiguity, round-trip exceptions; divergence pins proving nsparts1/nsprefix1/nsprefix_orig/ nstail1/nstail_orig are not drop-in twins (safe-deletion evidence); nseval create-on-eval + evaluator caching and the native-vs-punk p:::x resolution divergence; nseval_ifexists/nsexists/nschildren/nstree_raw on genuinely weird namespaces; globmatchns */**/? semantics (stale "should be fixed" comment above nsglob_as_re noted - behaviour fixed); nspath_to_absolute/nspath_here_absolute caller resolution. Warts recorded for the pass: nsjoinall error message says "nsjoin:". Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
2b46e2d86a |
shell tests: E3 piped-session proof of n/ namespace continuity and subshell carry-over (shellnavns.test)
New shell/testsuites/punkexe/shellnavns.test - one hang-proof punk_run piped session against the built executable in src launch mode (dev modules, so current punk::repl/nav source is exercised without a rebuild): PROVEN end-to-end: - n/ sets ::punk::nav::ns::ns_current in the running shell - the current namespace continues into `subshell punk` and back out, and the 0.5.2 stray-namespace seeding fix holds live (no phantom ns_current namespace in the subshell context) - navigation inside the subshell takes effect; the session exits cleanly (exitcode 0, no timeout, exit unwinds subshell -> parent -> terminate) FINDINGS from the E3 probes (pinned in the test with markers): - the FIRST subshell evaluates in the SAME code interp as the parent shell - the "first subshell asymmetry" already TODO-documented in repl::init. Continuity therefore manifests via shared state at shell level (SHARED marker: a variable set in the subshell is visible to the parent after exit, and the parent adopts the subshell''s final namespace). The repl::start seeding template - the carry-over mechanism for genuinely separate code interps - is proven at module level in punk/repl nscurrent.test. A G-002-style isolated subshell would flip these pins. - KNOWN GAP: piped-session submissions evaluate at :: even after n/ sets ns_current - the inscope application proven interactively and at module level does not take effect for subsequent piped submissions in this spawn shape. Root cause undetermined (piped-path evaluation vs kit/codethread interplay); flagged for investigation alongside G-038 session-context work. Verified: shell/** suite 42 total / 40 passed / 0 failed (2 gated skips) under Tcl 9.0.3. AGENTS updated (shell contracts bullet; punk/repl module index E3 reference). Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
50e4c60649 |
n/ display+navigation characterization (nslist/navns/nscurrent tests); punk::repl 0.5.2 stray-namespace seeding fix
Groundwork requested for the future rework of n/ n// n/// output to punk tables with terminal-width responsiveness: the underlying display elements and navigation/retention semantics are now pinned so only deliberately REWORK-flagged pins flip when the layout changes. - punk/ns nslist.test (11): tier A pins get_ns_dicts classification buckets (the machine contract: children/packagetails/packageprefixes per the package-names derivation, commands/exported/imported/aliases/procs/ ensembles/oo/coroutines/usageinfo incl alias-target doc resolution and its update_definitions dependence, alias edge cases, native via builtin ns); tier B pins per-element marking layout-agnostically (underline/underdouble/ underdotted package styles, type tag colours, exported green / imported -I under overtype SGR canonicalization, the punkargs doc icon); tier C pins the CURRENT hardcoded 2-col/4-col layout and nspath subtables, explicitly flagged to flip with the rework; KNOWN QUIRK pinned: bare nslist without -types errors with a malformed message (literal dollar-known_types). Findings recorded: the red-strike/masked alias display branches appear unreachable from current bucket derivation. - punk/nav/ns navns.test (6, new suite dir): ns/ navigation state machine (absolute/relative/glob-no-nav/failed-nav preservation/quad-colon normalization), v-form content selection, ensemble annotation, and the ::punk::nav::ns::ns_current variable contract. - punk/repl nscurrent.test (4): repl retention proven against a REAL codethread (repl::init, synchronous runscript sends): inscope evaluation, retention across submissions, n/ navigation retained, auto-create-with- notice for a missing current namespace. - punk::repl 0.5.2 fix: repl::start''s codethread seeding template namespace-eval''d the full ns_current VARIABLE name, creating a stray namespace of that name in every code interp (phantom child in n/ listings of the nav namespace). Now ensures only the parent ::punk::nav::ns. Subshell namespace carry-over semantics unchanged; pinned behaviourally (mirrored template) plus a source-text guard, pending the planned end-to-end piped subshell test (E3) at the shell level. Verified: punk/ns 80/80, punk/nav 6/6, punk/repl 7/7 under Tcl 9.0.3; nslist/navns/nscurrent green under 8.7. Console queries mocked throughout (the render path consults get_size/get_tabstops). Project 0.12.33 + CHANGELOG; tests AGENTS.md index updated. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
e68cc1c223 |
punk::lib 0.5.0: has_tclbug_nestedswitch_tracelines check (behavioural probe of tktview 5d5b1052280c976ea3d4)
New check pair in punk::lib::check, in the established style (G-076
console_deadspin exemplar: pure facts-in/verdict-out classifier
tclbug_nestedswitch_tracelines_signature + has_tclbug_* proc returning the
standard buginfo dict {bug bugref description level}, auto-surfaced through
the help tcl warning report via the info procs enumeration).
Unlike the version-gated checks, this one is a LIVE behavioural probe (safe
and cheap - no console interaction): a dynamically-defined proc with a
nested 4-word switch is enterstep-traced for inner arm 1 (affected split-
list index 1 - reports line 3) and the default arm (index 5, beyond the
command word count - reports line 2 correctly), matched against the
characterized wrong/right signature. Detection therefore flips
automatically on a Tcl runtime containing the upstream fix - no fixed_in
version variable needed. Probe layout note: a 2-arm probe would put the
default body at affected index 3 and hide the signature (both arms
mismark) - the middle arm exists to push default to safe index 5 (this
initially bit the probe itself, confirming the law once more).
Followup-when-fixed documented in the proc: re-verify with
scriptlib/developer/tcl_switch_traceline_repro.tcl, flip the
ns/cmdtrace.test GAP pins and fixed-canary, update the punk::ns::cmdtrace
argdoc caveat, note the fixed-in version. New canary test
cmdtrace_upstream_bug_check_canary asserts the check still reports the bug
- on a fixed Tcl it fails first and points at that workflow.
Verified: punk/ns 69/69 and punk/lib 37/37 under Tcl 9.0.3; cmdtrace.test
6/6 under 8.7; all has_tclbug_*/has_libbug_* procs exercised help-tcl style
without error; probe self-cleans (no temp proc/var residue).
punk::lib buildversion 0.4.3 -> 0.5.0 (new API procs = minor); project
0.12.32 + CHANGELOG; tests AGENTS.md index updated.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
3 weeks ago |
|
|
cabde42e85 |
punk::ns 0.6.0: cmdtrace -pause flag; nested-switch traceline mismark characterized as upstream (tktview 5d5b1052280c976ea3d4)
cmdtrace gains -pause <bool> (default 1, existing interactive behaviour unchanged): -pause 0 bypasses the "paused - hit enter key to continue" askuser in _cmdtrace_leave so cmdtrace runs unattended and the marked-up traced-body report (return value) can be captured by scripts and tests. Line-mismark investigation (all punk-free raw enterstep probes, results byte-identical on Tcl 8.6.17 / 8.7a6 / 9.0.3 - conclusively upstream): - with the ::switch argdoc available (punk::args::moduledoc::tclcore), cmdtrace marks flat single-block switches and 2-word-form nested switches correctly for EVERY arm; the residual mismarks match the raw trace data - empirical law, predictive across 4 command shapes x 6 arms and deeper nestings: an arm body at index j of the split pattern/body list reports container-relative lines (shift = switch command line within its containing script - 1) exactly when j lands on a LITERAL word of the switch command (options, --, or the block); dynamic words and j beyond the command word count fall back to correct arm-relative attribution. Position-based, not call-order based. Explains the ticket observation that the affected-arm count "varies based on switch options". - suspected machinery: Tcl_SwitchObjCmd passes split-list index j as the TclNREvalObjEx word; TclInitCompileEnv adopts ctx line[word] when the index happens to be in range of a per-word array describing the switch command itself (the splitObjs munging looks intended to prevent this) Artifacts: - new tests ns/cmdtrace.test (5): -pause 0 smoke + error-call count, flat-switch and 2-word-nested correct-mark guards, upstream mismark GAP pins (gated on have_tclcoredocs - cmdtrace arm-offset correction parses supplied switch commands against the ::switch argdoc) - scriptlib/developer/tcl_switch_traceline_repro.tcl: standalone pure-Tcl repro + findings write-up, suitable as an attachment/addition to the upstream ticket - cmdtrace argdoc caveat updated: cites the ticket and the characterized pattern (was "possibly an unreported bug") Verified: punk/ns suite 68/68 under Tcl 9.0.3; cmdtrace.test 5/5 under 8.7. punk::ns buildversion 0.5.0 -> 0.6.0 (new flag = minor); project 0.12.31 + CHANGELOG; tests AGENTS.md index updated. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
765d24b302 |
tests: corp/grepstr/untabify characterization - punk::ns hygiene-pass precursor coverage
New punk/ansi suites and extended punk/ns corp.test, characterizing the corp -> grepstr -> untabify tab-handling interaction and the standalone behaviours. All console-query paths are mocked (the overtype renderline.test get_tabstops pattern, extended to get_size + punk::console::tabwidth): the -untabify none / -stops terminal / -stops <int> paths consult punk::console::get_tabstops / get_size which emit live terminal queries that block or error in headless/piped environments - mocking is the answer to probing that behaviour deterministically in the test harness. - ansi/untabify.test (10): -stops 8/int/list/terminal(mocked), -with spaces/unicode(U+21E5 + U+00A0)/custom pair, multiline, usage errors, and the EXPERIMENTAL -plastic elastic-tabstop mode: basic expansion, the cross-line column-alignment property, -with composition - pinned as interim behaviour (hardcoded 8-multiple stops marked temp in source) and deliberately retained for possible future repl editbuf use. - ansi/grepstr.test (9): return modes incl summarydict (linemap pinned always-present; -help claims -n-only - reconciliation deferred to the hygiene pass), exact highlight SGR wrapping, -n numbering with * match counts, invert + empty-highlight strip, -C context with break indicators, capture groups, and tab handling: warns once per call on stderr, a simple single-pass tab line survives with correct highlights. - ns/corp.test (+6): basic-highlight ansistrip equivalence with -syntax none, -n numbering, -untabify spaces exact tab-free expansion + proper 4-element -syntax none list, -untabify unicode markers, the KNOWN DEFICIENCY pin for default -untabify none on a tabbed body (5 grepstr warnings; brace overlays mangle tabbed lines - leaked/shifted close-braces pinned exactly under mocked tabstops; flip deliberately if tab handling is fixed or corp moves off grepstr), and a ::tcl::CopyDirectory -untabify spaces smoke test (tab-free, warning-free, constraint-guarded). src/tests/modules/AGENTS.md punk/ansi + punk/ns index entries updated. Verified: punk/ansi 63/63 and punk/ns 63/63 under Tcl 9.0.3; the three new/extended files green under Tcl 8.7 (10/10, 9/9, 13/13). Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
d50d1dd6c5 |
punk::args 0.12.3: fix stringstartswith tail-clause reservation ($tp -> $rv); flip pin
The stringstartswith(*) arm of get_dict_can_assign_value''s multi-member tail-clause reservation walk compared the prefix against $tp (the type string) instead of $rv (the candidate value). Consequences (pinned pre-fix in the previous commit): - a later optional clause mixing literal(...) and stringstartswith(...) members never had genuinely matching trailing words reserved - a greedy -multiple argument swallowed them and the tail clause was silently lost - a prefix text that happened to prefix the literal type string (e.g str vs stringstartswith(str)) wrongly reserved NON-matching words, raising a spurious toomanyarguments overflow One-token fix; allocation_tailclause_ssw_reservation_GAP flipped to the correct expectations (matching words reserved; non-matching words left to the -multiple argument with no error); literal-only and no-match guards unchanged. Known remaining approximation (pre-existing, noted in the buildversion changelog): the walk still requires a literal* member in the tail clause''s typelist to run at all - a stringstartswith-only tail clause is not reserved. Verified: full punk/args suite 231 total / 227 passed / 0 failed (4 intended skips), punk/ns 57/57 under Tcl 9.0.3; allocation.test 10/10 under Tcl 8.7. punk::args buildversion 0.12.2 -> 0.12.3; project 0.12.30 + CHANGELOG. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
0f649053ee |
punk::args: characterize stringstartswith tail-clause reservation bug (pre-fix pins)
allocation.test gains coverage for the get_dict_can_assign_value multi-member tail-clause reservation walk (a later optional clause mixing literal(...) and stringstartswith(...) members, guarded from a greedy -multiple argument): - guards (must hold pre and post fix): literal-only tail clause reserved correctly; non-matching trailing words correctly left to the -multiple arg - allocation_tailclause_ssw_reservation_GAP pins the current bug: the stringstartswith(*) arm matches against $tp (the type string) instead of $rv (the value), so matching trailing words are swallowed by the -multiple argument (optional tail clause lost), and a prefix text that happens to prefix the type string (str vs stringstartswith(str)) wrongly reserves non-matching words, ending in a spurious toomanyarguments overflow Verified 10/10 against the unfixed module under Tcl 9.0.3. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
d2e96dbe30 |
G-082 achieved: punk::args 0.12.1 single-form error selection - specific rejection preferred over generic overflow
A word rejected by an OPTIONAL argument's allocation screen (G-071 restricted-choice screen, or the basic int/double/bool/number/dict type screen) that subsequently overflows the argument list now reports the specific rejection instead of "Received more values than can be assigned": - choiceviolation naming the word and allowed choices, with -badarg/-badval and the final-validation message template (Leading/Trailing argument attribution), for choice-screen rejections - typemismatch naming the declared (normalized) type, with -badarg/-badval, for basic-type screen rejections Mechanism: private::get_dict_can_assign_value returns a 'rejection' record (single-member clauses only; literal-category mismatches deliberately not recorded); get_dict_form collects first-rejection-per-word from the three allocation call sites (leader/value split trial, leaders loop, values loop) into a per-form store; the two toomanyarguments raise sites prefer a recorded rejection for the unassignable word. Genuinely-surplus words still report toomanyarguments; words consumed by later slots parse unchanged; multiform selection (rank_form_failures) untouched. errorselection.test _GAP pins flipped to the pointed expectations (pre-fix behaviour pinned in the previous commit). punk::args buildversion 0.12.0 -> 0.12.1. Closeout: G-082 flipped achieved + archived (index -> GOALS-archive.md, detail -> goals/archive/ with mechanism/verification/residue recorded); G-073 note updated to point at the new rejection-record seam; src/modules/AGENTS.md authoring-ergonomics bullet re-documented (-optional 0 workaround no longer needed on >= 0.12.1; make.tcl keeps it - it runs against the bootsupport 0.12.0 snapshot). Project version 0.12.28 + CHANGELOG. Verified: full punk/args suite 228/224/0-failed (4 intended skips) and punk/ns 57/57 under Tcl 9.0.3; errorselection.test 7/7 under Tcl 8.7; make.tcl frobnicate still pointed; goals_lint clean. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
0032478e46 |
G-082 increment 1: activate goal; characterize 0.12.x optional-rejection overflow errors
Set G-082 active (user-directed). New errorselection.test pins current
single-form error selection before the fix:
- _GAP pins: an optional choice-restricted leader (make.tcl dispatch shape),
an optional choice-restricted value, and an optional typed (int) value each
reject a word that then overflows - all report generic
{toomanyarguments N index I} with no -badarg/-badval attribution,
discarding the specific rejection (regression vs punk::args 0.5.0)
- reference pins: the -optional 0 equivalents report pointed choiceviolation
with -badarg/-badval and Leading/Trailing argument messages
- guards: genuine surplus stays toomanyarguments; a rejected word consumed by
a later slot parses cleanly; multiform failures still route through
rank_form_failures (noformmatch)
Verified: 7/7 pass against the unfixed module under Tcl 9.0.3.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
3 weeks ago |
|
|
a21315a109 |
punk::args: -parsekey characterization tests; goals G-083/G-084 (argument relations, parsekey completeness)
parsekey coverage review outcome: - tests/args/parsekey.test: pin mash-path last-wins ordering, prefix-abbreviation keying and @opts -any passthrough; GAP pins for last-defined-member default precedence, cross-member -multiple value loss, parsekey/optname collision conflation, and values/leaders parsekey breakage (abort/ignore/reject) - new tests/dev/parsekey-knownbugs.test: desired-behaviour pins disabled behind punkargsKnownBug (value/leader key renaming, cross-member accumulation in received order) - GOALS.md + detail files: G-083 argument relations (per-arg -conflicts checked against received args, @opts strict mode for shared-parsekey groups, define-time parsekey collision validation, lsearch/clock clicks dogfood); G-084 -parsekey completeness (cross-member -multiple collection, leaders/values support or define-time rejection, defaulted-member precedence documented) - src/tests/modules/AGENTS.md: punk/args suite index updated Verified: full punk/args suite under Tcl 9.0.3 = 221 total / 217 passed / 0 failed / 4 skipped (intended disabled pins); parsekey.test 16/16 under 8.7; goals_lint clean. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
7ea1deaae5 |
G-030 achieved: make.tcl dogfoods punk::args - tabled usage, declared subcommands, -confirm prompt policy
All 15 make.tcl subcommands are punk::args-declared ((script)::punkboot + (script)::punkboot::<sub>, built from single-source summary/help/opt dicts with shared option fragments and explicit @form -synopsis). Bare make.tcl / -help, 'help ?subcommand?' and '<subcommand> -help' render tabled usage; invalid flags/subcommands raise punk::args usage errors (exit 1) with unambiguous prefix resolution; 'shell' is a declared passthrough. Prompt policy: new -confirm 0|1 (default 1) on every confirmation point (bootsupport minor-staleness gate, vfscommonupdate REPLACE, kit-type mismatch). Default prompts only on an interactive terminal and aborts fast with guidance on non-interactive stdin (::punkboot::lib::stdin_is_interactive; Tcl 8.6 lacks the -inputmode probe and is assumed interactive). -confirm 0 proceeds (staleness, REPLACE) or skips the mismatched kit. The piped-y agent workflow is retired; the old vfscommonupdate decline half-abort (printed done, exit 0) now exits 1. Degrade rule: punk::args/punk::ansi/textblock boot requires guarded; definition load caught with fallback to a self-contained scan (-k/-dirty-abort/-confirm supported) + plain punkboot_gethelp (availability NOTE factored into punkboot_availability_note, shared by both paths); rendering degrades independently of parsing (errorstyle minimal / plain help when the ANSI stack is unhealthy); PUNKBOOT_PLAIN=1 forces degraded mode. punk::args joins the bootstrap-tracked _runtime_deps staleness set (parsing contract only - the rendering stack degrades instead; contract docs updated in src/bootsupport/AGENTS.md + src/modules/AGENTS.md, workflow docs in src/AGENTS.md + src/tests/shell/AGENTS.md). Verified: usage/help/error paths, vfscommonupdate fail-fast and -confirm 0 runs with closed stdin, staleness flag route live (args 0.5.0->0.12.0 tripped the gate), degraded-mode help/check/info, full 'project -k -confirm 0' kit build. Dogfooding finding recorded in the goal file: punk::args 0.12.0 reports generic overflow where 0.5.0 reported choiceviolation for optional-choice mismatches (worked around with required leaders; candidate error-selection improvement). Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
49ec22a928 |
doc: restore 'dev doc.validate' - wrap tcllib dtplite as bin/dtplite.cmd
'dev doc.validate' invokes a bare dtplite command which the repl unknown-handler resolves via auto_execok on PATH - no dtplite executable existed (only the legacy misnamed bin/dtplite_run.bat), giving "invalid command name dtplite". - src/scriptapps/dtplite.tcl: LF-converted (polyglot payloads are embedded verbatim into the LF-only multishell output); fall back to the project-vendored tcllib (src/vendorlib_tcl9/<arch>/tcllib*) when the invoking tclsh lacks the dtplite package - src/scriptapps/dtplite_wrap.toml: new scriptset config (tclsh nextshell on all platforms) - bin/dtplite.cmd: generated polyglot via punk::mix::commandset::scriptwrap::multishell (checkfile-clean, LF-only) - src/tests/shell/testsuites/binscripts/dtplite.test: artifact pins (LF-only, checkfile, byte-identical round-trip re-wrap) + execution usecases (usage error, validate good/bad file, validate directory tree, html generation) - 8/8 pass under runtests - AGENTS.md (bin, src/scriptapps): record the dtplite scriptset, its test pin and the LF-only payload requirement - punkproject.toml: 0.12.22 -> 0.12.23 Verified: 'dev doc.validate' in punk902z src validates all 64 src/doc .man files clean. The doctools pipeline remains interim - punk::args is the intended doc source of truth. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
6af0fd541e |
punk::args 0.12.0: formcheck on-demand multiform ambiguity analysis + @form -overlapallowed sanction (G-074 achieved)
New punk::args::formcheck <id> ?-return dict|summary?: reports the form pairs of a multiform definition that some argument list could cleanly match simultaneously (the multipleformmatches inputs). Static pairwise pass over the resolved FORMS enumerates each form's positional word-slot chains (leaders then values; -optional and ?-wrapped clause-member branching; -multiple capped; options excluded - order-free), screens aligned equal-length chains per position (discriminator words via choiceword_match, type witnesses from a small table), and CONFIRMS every candidate witness arglist with a real single-form parse against both forms (parse_status - no raise, no user-supplied words, no define/resolve cost). Findings are therefore witnessed - discriminated form pairs cannot false-alarm; misses (exotic types, option-requiring forms, enumeration caps) are the documented conservative direction. Classes: type_weakness (discriminator aligned with a permissive non-validating type - any/none/string/ansistring/globstring/expr/script) vs structural (forms genuinely share an argument shape). New @form key -overlapallowed <formname-list> sanctions a KNOWN overlap on either pair member: the finding reports with sanctioned 1 and leaves the result's unsanctioned list (the actionable/gate subset). Parse behaviour is never affected; unknown form names are rejected at definition resolve (end-of-forms cycle). @form directive doc updated. tclcore moduledoc 0.3.4: the documented after cancelid/cancelscript overlap (runtime-liveness ambiguity, 0.3.0 record) sanctioned on the cancelid form - ::after now reports zero unsanctioned findings while 'after cancel <id-shaped>' still raises multipleformmatches. ::lseq deliberately unsanctioned: formcheck reports range/start_count (witness {1 count 1}) AND range/count (witness {1 by 1}) - both real, both rooted in the expr-typed end slot, kept visible pending an expr syntax-validating type (G-069/G-070). Tests: new args/formcheck.test (7) - no-finding cases (parse withid/withdef pair, afterish/sharedform fixtures), class+sanction fixture, unknown-form rejection, -return summary, ::lseq/::after pins with witnesses re-verified, sanction parse-neutrality. punk::args suite 210/210, punk::ns 57/57. G-074 achieved and archived (acceptance review in the detail file); G-055 verification gate gains the formcheck step (unsanctioned must be empty for regenerated multiform commands). Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
97ca1ceb1e |
punk::lib 0.4.3 + punk::repl 0.5.1 + punk 0.2.6: G-076 dead-console defect in 'help tcl' with mitigated axis, version-gated watchdog (project 0.12.21)
New goal G-076 (active): adopt the upstream tcl9 dead-console fix (ticket f10d91c2d3, root-caused in G-039) via a single version gate shared by the 'help tcl' warning and the repl watchdog arming. - punk::lib 0.4.3: has_tclbug_console_deadspin + pure classifier tclbug_console_deadspin_applies, gate variable check::tclbug_console_deadspin_fixed_in (empty = all Tcl 9 windows runtimes affected). Buginfo dicts gain a mitigated/mitigation axis orthogonal to level; the deadspin check reports mitigated when punk::repl >= 0.5.0 is available to the runtime. - punk::repl 0.5.1: repl::start arms the dead-console watchdog only when the check reports the runtime affected - recording a verified fixed release once flips both consumers. - punk 0.2.6: 'help tcl' renders mitigated warnings subdued (term-grey) with a "(mitigated)" annotation and the mitigation text; severity classification unchanged. - checkbugs.test: classifier truth table, live-check consistency, and mitigated-axis validation in the generic every-check sweep. The fixed_in flip is deliberately deferred until a released Tcl passes the G-039 kill-procedure re-verification (watchdog disabled, clean script-visible eof exit) - recorded as the goal's remaining acceptance item. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
b35ea12896 |
punk::args 0.11.2: bad-@dynamic warn-once + round-1 caching; tclcore 0.3.2: fix malformed tcl_startOfNextWord (project 0.12.19)
User-reported: 'i join' emitted the bad-@dynamic warning 4 times ('i
join test' 6). Root cause was a real inefficiency, not just noisy
logging: a @dynamic definition whose round-1 tstr output has no
round-2 parameters bypassed argdefcache_unresolved entirely, so every
resolve in the 'i' flow (doc walk, advisory parse, get_spec for the
render, synopsis) redid display masking plus the full round-1 tstr and
re-warned. Such definitions now cache as a zero-param unresolved entry
- consistent with the round-1 freezing legitimately dynamic
definitions already get - so later resolves take the cheap cached
branch and the warning emits once per definition per interp.
Warning wording corrected: @dynamic is not a complete no-op for a
parse-inert definition - deferred display fields still re-expand per
render instead of caching - so the message says removal is appropriate
only if that display behaviour is unintended. Sweep of all 462
registered ids: ::split, ::array, ::join carry the parse-inert tag
(left in place pending the display-refresh decision).
Incidental finds from the sweep: the malformed ::tcl_startOfNextWord
tclcore definition (double-quoted -help with unescaped quotes in the
embedded man-page example) failed to resolve at all - now braced per
the define quoting rules, 'i tcl_startOfNextWord' works; and resolve's
malformed-record error path printed dev diagnostics (full records dump
+ ::testrecord global) - commented per the stray-debug convention.
Tests: new args/dynamic.test (warn-once + cached parse, legit-dynamic
round-2 freshness; stderr captured via channel transform). punk::args
203/204 (1 pre-existing skip), punk::ns 57/57. Live-verified: 'i join'
and 'i join test' each emit the warning exactly once (punk902z src).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
3 weeks ago |
|
|
5a553b4ff3 |
tclcore 0.3.0: after cancel-id discrimination via harvested id shape (project 0.12.16)
The cancelid and info forms' id argument is typed
stringstartswith(<prefix>) with the prefix harvested from the running
interpreter at define time (safe create+cancel probe; after# on 8.6.11
and 9.0.3) - substituted via a build-time %AFTERIDPREFIX% string map
because tstr placeholders in non-display fields are not expanded for
plain PUNKARGS definitions (G-046 defers display fields only; noted in
G-055 for the regeneration workflow). -typesynopsis id keeps the
synopsis as the man page's 'id'; both ids gain man-page-derived help.
Effect under G-041 form candidacy: 'i after cancel someid' resolves
cleanly to the cancelscript form, matching real Tcl's silent
script-match no-op; 'after info <non-id>' is model-rejected where real
errors at runtime (parity-true). An id-SHAPED word after cancel stays
truthfully ambiguous (cancelid+cancelscript) - real Tcl resolves that
junction by id liveness at runtime, which no static type expresses.
Dead-id over-acceptance on 'after info' recorded as the accepted
runtime-liveness boundary.
Tests: three parity pins added in tclcoreparity.test (id-shape harvest
agreement with live ids, cancel discrimination incl the liveness
ambiguity witness, info error-vs-ok parity + accepted dead-id
divergence). punk::args 201/202 (1 pre-existing skip), punk::ns 57/57.
Live-verified on punk902z src ('i after cancel someid' renders info
scheme).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
3 weeks ago |
|
|
4707af6fc2 |
G-041 increment 2: doc surface presents the matching form (punk::ns 0.5.0, punk::args 0.11.0, project 0.12.15)
cmdhelp ('i'): the -form option defaults to * (was 0) with parse's
list semantics, and both render sites present the form the advisory
parse selected - 'i after cancel <id>' presents the cancel form's
argument table with its synopsis line underlined; 'i lseq 0 10 2'
presents the range form info-scheme. When no form matches, the ranked
candidates are passed to arg_error (best candidate's table, all
candidates marked, message naming each form's failure); when several
forms match, all matching forms are marked under the ambiguity message.
punk::ns::synopsis ('s'): trailing argument words after a multiform
command path underline the form(s) they match - matching forms from the
advisory parse's formstatus, or the best candidate when none fully
matches ('s after cancel someid' marks both cancel forms; 's lseq
0 10 2' marks the range form). Ordinal line position maps lines to
declaration-order forms in both full and summary renders; marking is
skipped under alias-currying excess or an explicit -form.
punk::args 0.11.0: the documented @form -synopsis override now renders
in punk::args::synopsis full and summary output (arg_error honoured it
already) - the adjacent forms.test GAP flipped
(forms_form_synopsis_override_rendered). Candidate ranking extended:
form_literal_affinity treats required RESTRICTED-choice arguments as
discriminators via choiceword_match (the tclcore models express
subcommand words as -choices), so 'after cancel' ranks the cancel
forms first instead of falling back to declaration order.
Real-model findings recorded in the goal detail: 'after cancel someid'
is genuinely ambiguous in the doc-faithful model (cancelid vs
cancelscript - real Tcl disambiguates semantically); 'lseq 1 count 5'
ambiguity traces to the expr-typed operands (noted in G-055 as a
model-tightening candidate alongside TIP 746).
Tests: cmdhelp.test gains the multiform doc-surface pins (autoselected
form presented, noformmatch best-candidate table + candidate naming,
synopsis marking present/absent). punk::ns 57/57, punk::args 198/199
(1 pre-existing skip); full source-tree suite in the detail record.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
3 weeks ago |
|
|
d85608d685 |
G-041 increment 1: multi-form candidacy engine (punk::args 0.10.0, project 0.12.14)
punk::args::parse/get_dict with the default -form * (or any multi-form selection) now attempts every permitted form instead of effectively parsing form 0 only. Exactly one clean match auto-selects (result gains a 'form' key; 'formstatus' reports every candidate when candidacy ran). No match raises a 'noformmatch' validation error naming each candidate form's first-line failure, ranked best-candidate first (leading-literal affinity with the supplied words, then incomplete before invalid, then declaration order). Several clean matches raise 'multipleformmatches' naming the forms - deliberately no silent preference (recorded in the goal detail); callers pass -form to disambiguate. -form now accepts the documented list of form names/indices across get_dict, parse, parse_status and arg_error via a shared resolver (private::form_selection). arg_error renders the argument table for the first listed form and marks all listed forms' synopsis entries; parse's error render passes the ranked candidate list so the closest form's argument table shows under the no-match message. parse_status: 'form' is now the matched (or best-candidate) form - the per-argument statuses and badarg marking are built for it - and the new documented 'formstatus' key carries per-form status/failureclass/badarg/ message (caller-attributed), the per-form compatibility surface the G-044 completion/hinting consumer needs on partial argument lists. Engine restructure: the single-form parse body of get_dict extracted verbatim to private::get_dict_form (argspecs resolved in the caller's context before selection; no caller-frame use inside - verified). Single-form definitions take the direct path unchanged. Tests: forms.test GAP pins flipped (forms_parse_autoselect, forms_parse_formlist_restriction) plus new coverage: shared-prologue arity discrimination, noformmatch ranking + errorcode payload, multipleformmatches + explicit -form disambiguation, formstatus in results and parse_status. punk::args 198 pass / 1 pre-existing skip, punk::ns 53/53, punk::lib 35/35. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |
|
|
deb8f17d72 |
G-051 achieved: doc-walk choice-prefix parity + truthful doconly cmdtype (punk::ns 0.4.0, punk::lib 0.4.1, project 0.12.13)
Space-form docid prefix parity: cmd_traverse's space-delimited child
docid jump, on an exact-word miss, now resolves the word against the
current level's choices-bearing first leader via
punk::args::choiceword_match (the shared G-040 resolver - -choiceprefix,
-nocase, -choicealiases, denylist, reservelist honoured) and retries
with the canonical word. 'i string is tr' resolves to the
"::tcl::string::is true" documentation exactly when 'string is tr 1'
executes; 'string is bool' -> boolean; ambiguous ('d'), unknown ('zz')
and denied words stay at the parent exactly when parse rejects them.
resolvedargs records the canonical, mirroring parse normalization. No
second matching rule exists.
Truthful cmdtype: cmdinfo classifies cmdwhich-notfound + non-empty docid
as 'doconly' (was 'notfound') - documentation-only levels below real
commands (per-class ids like "::tcl::string::is true", documented TclOO
method docids; the method case adopts doconly per the recorded design
decision, refinable by G-052). Consumers audited: cmdhelp/synopsis/eg
are docid-driven, cmdtrace tests only for 'proc', punk::help topic
fallback uses cmdwhich; punk::lib script analysis updated in step
(doconly accepted alongside notfound, bucketing unchanged).
Tests: the four G-051 GAP pins flipped and renamed
(cmdhelp_pseudo_command_cmdtype_doconly,
cmdhelp_spaceform_docid_prefix_honoured + ambiguous/unknown guard,
cmdhelp_string_is_true_pseudo_doconly,
cmdhelp_string_is_prefix_honoured). punk::ns 53/53 (cmdflow + non-GAP
cmdhelp unchanged), punk::args 193 pass / 1 pre-existing skip,
punk::lib 35/35; full source-tree suite result in the detail file.
Live verification (punk902z src): 'i string is tr' renders
byte-identical to 'i string is true' except the failure banner echoing
the typed words.
Flip edits: G-051 index entry to GOALS-archive.md (achieved 2026-07-13),
detail Status flipped with acceptance review and verification record,
reference sweep updates G-052 Notes. Detail-file move to goals/archive/
follows as a pure rename; goals_lint transiently unclean between the two
commits.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
3 weeks ago |
|
|
72d50f91df |
punk::ns 0.3.0: restore bare-query failure banner in cmdhelp (project 0.12.12)
Regression report (user, vs older punk executables): "i if" / "i while" /
"i foreach" used to render the error-scheme box with a "Bad number of
trailing values..." message signalling the command cannot be called with
no arguments; recent builds rendered plain info-scheme usage with no
indication, while direct punk::args::parse {} withid ::foreach still
errored.
Root cause: deliberate suppression, not breakage - G-046 item 5 (ns
0.1.4) suppressed the failing advisory parse for the whole
no-supplied-words path because the message then carried internal-looking
attribution ("Bad number of leading values for punk::args::parse
$args_remaining ...", the "i string is" complaint). G-049 (ns 0.2.0,
same day) independently added -caller attribution making bare-query
messages accurate - but the suppression stayed, hiding now-useful
signal.
Fix: reversal rather than rewording (user decision) - both cmdhelp
render sites (alias path and main path) drop the no-supplied-words
special case; a failing advisory parse renders its message and error
scheme uniformly, and dict returns no longer rewrite the scheme to
info. "i if" now leads with "Bad number of trailing values for if. Got
0 values. Expected at least 2"; the original "i string is" case renders
an accurate "Bad number of leading values for string is. Got 0 leaders.
Expected exactly 1" instead of being hidden.
Tests: cmdhelp_leader_required_no_args_plain_usage flipped to
cmdhelp_leader_required_no_args_error_render (message present,
attribution never the internal parse); cmdhelp_return_dict_scheme
expects scheme error for the bare-query failure. punk::ns suite 53/53;
verified live in punk902z src.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
3 weeks ago |
|
|
d4519f41d3 |
G-071 achieved: punk::args 0.9.0 allocation choice screen - lseq-class optional-element arglists parse in-form (project 0.12.11)
Root cause: get_dict_can_assign_value blanket-satisfied the member check
for any argument carrying choices, so an optional restricted-choice value
(the lseq '..'/'to' noise word) consumed any word whenever arity
permitted, starving later elements/clauses and failing validation with a
confusing trailing-choices error ('lseq 0 10 2' shape).
Fix: an allocation choice screen using choiceword_match (the shared G-040
implementation - exact/alias/prefix/nocase semantics; -choicemultiple
words screened per list member within min/max), applied only where
allocation has an alternative: -optional arguments and further
occurrences of -multiple arguments. Required arguments are deliberately
not screened - the word must fill them and validation's choiceviolation
reporting stays informative (the existing parsestatus/cmdhelp/choices
pins forced and now document both refinements). -choicerestricted 0
behaviour unchanged.
Results: the allocation.test GAPs flipped ('1 2 3' and '1 2 by 3' parse
with correct clause shapes {{} 3}/{by 3}; '1 2 3 4' gets the plain
excess-values rejection instead of blaming the unrelated optional);
prefix normalization survives the screen; all noise-word variants and
if-shape guards unchanged. lseq moduledoc matrix parses per lseq.n under
-form range, and 'i lseq 0 10 2' works end-to-end. Remaining lseq
divergences trace to G-041 form selection or the -type expr laxity
recorded in G-055 - not allocation.
Also corrected an increment-1 mis-premise: parse_status ALREADY accepts
-form before the withid/withdef tail per its documented synopsis - the
probe had passed it trailing. GAP replaced by
parsestatus_form_option_order (correct-order acceptance incl. the form
key, trailing rejection). No code change was needed for that acceptance
clause.
Verification: punk::args suite 193 pass / 1 pre-existing skip / 0 fail;
punk::ns 53/53; full source-tree suite 813 pass / 13 skip / 1 fail =
exec-14.3 only (known baseline) - zero regressions (tclsh 9.0.3; lseq
verification in punk902z src, Tcl 9.0.2).
Flip edits: G-071 index entry moved to GOALS-archive.md (achieved
2026-07-12), detail Status flipped with the acceptance review and
before/after record; reference sweep updates G-041 (prerequisite fixed,
parse_status correction) and G-072 Notes. The detail-file move to
goals/archive/ follows as a pure rename; goals_lint transiently unclean
between the two commits.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
3 weeks ago |
|
|
17b8a6dbbd |
G-071 increment 1: allocation characterization suite + retreat-path debug silencing (punk::args 0.8.3, project 0.12.10)
G-071 flipped proposed -> active (user direction 2026-07-12).
New allocation.test (7 tests) with reduced fixtures isolating the failing
shape from the tclcore moduledoc: the lseq-range shape (start ?sep? end
?by-step clause?) reproduces the moduledoc failures exactly. Current
mis-allocation pinned as GAP tests ("1 2 3" -> invalid blaming sep,
"1 2 by 3" -> incomplete blaming end, "1 2 3 4" correctly invalid but
misblaming sep), noise-word variants and the if-shape noise-word clauses
pinned as regression guards, parse_status -form absence pinned as GAP.
Also silenced four more unconditional debug puts on get_dict allocation
retreat paths ((111)/(222)/(333)/(444)) - these printed to stderr during
NORMAL successful parses at every optional-skip retreat, polluting
interactive help/parse output for noise-word-modelled commands. Behaviour
unchanged; the retreat logic they marked is exactly this goal fix target.
Full punk::args suite 193 pass / 1 pre-existing skip / 0 fail (tclsh
9.0.3).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
|
3 weeks ago |
|
|
22606faebe |
G-045 increment 4: punk::args 0.8.0 @normalize directive; define_docs converts as consumer proof (project 0.12.7)
New bare @normalize directive: opts a definition into indent normalization of BLOCK-FORM multi-line field values (first line whitespace-only, as authored by opening a braced literal with a newline). The structural first newline and a whitespace-only trailing line are dropped, the content lines' common leading whitespace is the block's base indent, the first content line is unindented fully and subsequent lines are re-based to the standard 4-space continuation convention (deeper relative indents preserved; whitespace-only inner lines become empty). Fields in a record's -unindentedfields are exempt. Implemented as a resolve pre-pass over the split records (private::normalize_records / rebase_multiline_value); @normalize with options is an error. Head-form values are never altered - their base indent is unknowable (continuations uniformly at 6 may be base-4 with the deliberate +2 relative convention, or base-6 flush; re-basing would flatten the former). The idempotence test caught exactly that on a file-style definition during implementation, narrowing the user-confirmed re-base semantics to block form only - which also makes @normalize a proven no-op on conforming file-style definitions. Consumer proof (punk 0.2.5, per the recorded user decision): ::punk::helptopic::define_docs converts from interim left-margin authoring to indented block-form values under @normalize, dropping its -unindentedfields declarations; 'i help' and 'i help_chunks' verified aligned in punk902z src, including the blank-line separator in the combined basehelp+extra block. Tests: new normalize.test (5 tests: block re-base, block left-margin, head-form boundary, exemption byte-exactness, file-style idempotence); rendering.test P4 characterization stays pinned as the deliberate unopted default with its text updated to reference @normalize. punk::args suite 186 pass / 1 pre-existing skip / 0 fail; punk::ns 53/53; full source-tree suite 806 pass / 13 skip / 1 fail = exec-14.3 only (known baseline) - zero regressions (tclsh 9.0.3). define doc documents the directive. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com |
3 weeks ago |