Field failure (2026-07-27, second dev machine): 'make.tcl bake
punk9_beta' died in the vfslibs phase with
eventcollection ... key '$eventid' already exists in collection
because that machine's src/vfs/.punkcheck predates punkcheck 0.3.2.
The 0.3.2 note fixed the WRITER (a braced template wrote the literal
strings '$eventid' etc into event headers) but files written before it
keep the damage, and the modern installtrack constructor - which
reloads persisted events into a collection keyed by -id - collided on
the duplicate literals and aborted the whole bake.
- punkcheck 0.6.1: the constructor reload now self-heals instead of
aborting: an EVENT record with a missing or duplicate -id is
reconstructed under a synthesized unique id ('damaged-id-...') with
a stderr warning naming the file and the offending id. Synthesized
ids match no INSTALL record's -eventid reference, so healed events
age out through normal -keep_events pruning. Reload also tolerates
missing -source/-targets keys.
- oolib 0.1.4: the collection duplicate-key error no longer misnames
the object as 'col_processors' (stray copy-paste in the generic
class).
- regression test installtrack_damaged_event_history_selfheal seeds a
real two-event file, rewrites both -id values to the braced literal
{$eventid} (as the damaged files carry it - the record loader
evaluates records, so only a braced literal survives as the string),
and asserts the reload succeeds with both events kept under distinct
keys (one healed). Suite: 30/30.
- before/after proof against the released artifacts: punkcheck 0.6.0
(exact-pinned) reproduces the field abort on the crafted file;
0.6.1 heals it. Bootsupport promoted to punkcheck-0.6.1 + oolib-0.1.4
(superseded copies pruned), so make.tcl bakes get the fix.
Remedy already applied on the affected machine (file deletion); with
this fix, remaining old .punkcheck files anywhere self-heal with a
warning instead of failing builds.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
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
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
punk::cap::handlers::templates 0.3.0: module-pathtype layout refs resolve
against the providing module's own templates/project_layouts store (sibling of
its layout_refs folder) instead of the never-existing <modulebase>/src tree -
module-carried thin layouts become usable.
punk::mix::templates 0.2.0: ships the thin punk.project layout payload inside
the modpod (payload synced from src/project_layouts by make.tcl - see below);
shellproject_multivendor declaration fixed decktemplates -> src/decktemplates
(shell-project layouts/templates were invisible when cwd was outside any
project).
punk::mix::commandset::project 0.3.0: project.new injects bootsupport into the
generated project at generation time via new lib::bootsupport_inject - manifest
(include_modules.config) driven module resolution from the generating shell's
project bootsupport tree, or a standalone kit's tcl:™️:list paths (999999.*
dev versions never injected; latest-version non-glob semantics matching
make.tcl bootsupport; adjacent non-.tm support files such as struct sets_*.tcl
and textutil .tex data carried along; bootsupport lib* trees copied from a
shell project, notice emitted for manifest-less standalone kits); punkcheck-
recorded with plain-copy degradation. -layout now prefix-matches the live
layout set instead of the package-load-time snapshot.
punkcheck 0.4.0: start_installer_event no longer writes literal '$eventid'/
'$rel_source'/'$rel_target'/'$config' into event headers (braced-literal
expansion bug, latent since inception - collided as duplicate ids when install
and installtrack writers shared one db); sources with no common root vs the
punkcheck folder (e.g //zipfs:/ module-mounted layouts) are recorded as
independent absolute paths instead of erroring.
punk::mix::base 0.1.1 -> 0.1.2 (manually versioned rename): cksum_path no
longer hangs forever on vfs-mounted files - tcllib -file digest modes read via
fileevent+vwait and zipfs channels never deliver fileevents (empty
ZipChannelWatchChannel in core); non-native files are slurped and digested in
data mode (new cksum_data_command per algorithm + cksum_crc_data/
cksum_adler32_data helpers; exec-based sha3 errors cleanly for vfs paths).
make.tcl: custom/_project layout bootsupport-sync retired (project layouts
store no snapshots); sync_layouts retargeted to thin vendor layouts (make.tcl,
build.tcl + bootsupport manifest copies; punkcheck db at
src/project_layouts/.punkcheck) plus store->modpod punk.project payload sync
(excludes bin/sdx.kit and src/PROJECT_LAYOUTS_* marker; fossil settings kept
via core-exclude override); bootsupport copy onto a modpod the running
make.tcl has mounted records OK when target content is already identical
(FAILED-record churn fix); workflow text updated (DIAGRAM 1b) and help/argdoc
texts adjusted.
bootsupport include_modules.config: added previously-recordless-but-required
entries cmdline (fileutil dep), struct::set (make.tcl accelerators), textutil,
textutil::expander, textutil::patch - generated projects' make.tcl now boots
under a plain tclsh.
Docs: root/src/bootsupport/punk AGENTS.md updated for the retired sync and
build-managed modpod payload; goal detail G-087 stage-3 progress record;
CHANGELOG 0.16.0 + punkproject.toml bump.
Claude-Session: https://claude.ai/code/session_01WS3VakZo4sgbFzcQFW3twZ
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
install documented -choices on -overwrite, -source-checksum and
-punkcheck-folder with -choiceprefix defaulting to true, but the manual
dict merge parser validates option names only and never normalizes choice
values. PUNKARGS now declares -choiceprefix 0 so documented behaviour
matches the implementation (exact match required).
Assisted-by: harness=opencode; primary-model=openrouter/z-ai/glm-5.2; api-location=openrouter.ai
Resolves the build-maintenance TODO: built module trees no longer accumulate
superseded intermediate versions, and .punkcheck state stays consistent because
every deletion is recorded through punkcheck's event mechanism.
punkcheck (0.3.0):
- installsource_add_virtual + installevent method targetset_addsource_virtual:
'virtual' named-value SOURCE records (-type virtual -path virtual:<id> -value <v>)
compared by stored value, participating in targetset_source_changes. Needed
because successive module versions are built from the same physical source
files - the recorded virtual module_name/module_version identify which
product of the source fileset a target is, at install and delete time.
punk::mix::cli (0.5.0):
- lib::prune_superseded_target_modules: deletes lower-version .tm siblings only
when records prove the same module line (virtual module_name match, or legacy
fallback: recorded sources share the keep-version's source folder(s) and name
prefix). Unrecorded files are never deleted - reported to stderr instead.
- lib::prune_sourcevanished_targets: mirror-prune of recorded targets whose
recorded source files no longer exist (layout bootsupport copies, vendormodule
copies) - intentional multi-version vendoring is preserved.
- build_modules_from_source_to_base prunes after each module install/skip and
records virtual module identity sources on installs.
make.tcl:
- bootsupport: non-glob include_modules.config entries track only the latest
version - superseded recorded snapshot versions pruned; project-layout copies
mirror-pruned; virtual identity recorded on snapshot installs. Calls guarded
(info commands) so a stale bootsupport snapshot degrades to a warning and the
two-pass modules+bootsupport bootstrap self-heals.
- vendormodule copies in root modules*/ mirror-pruned after install.
docs/config:
- include_modules.config headers now document the entry format (non-glob =
latest-only + prune; glob chars = keep all matches; unrecorded never pruned)
- src/AGENTS.md TODO replaced with the durable prune contract;
src/bootsupport/AGENTS.md + src/tests/modules/AGENTS.md updated
tests: src/tests/modules/punk/mix/testsuites/cli/prune.test (19 tests) covering
virtual source recording/comparison and prune identity/safety rules.
Suites: punkcheck 64/64, full suite under Tcl 9.0.3 green except pre-existing
exec-14.3.
payload sync: bootsupport snapshots, project layouts and _vfscommon.vfs pruned
of superseded intermediates (~570k lines of stale .tm copies removed).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com