Implemented and achieved same day. punkboot::utils 0.6.0 gains
kit_offsetstyle_report (argdoc'd thin classifier over
punk::zip::archive_info), synced via modules + bootsupport (one stale
dead-pid .punkcheck.lock removed per the recorded recovery) and promoted into
_vfscommon. make.tcl: guarded getter, post-assembly probe beside the
smoke-require block (recapped BUILD-WARNING only on a FILE-relative attached
payload; plain/none/unreadable silent; NOTE on stale bootsupport), and the
'check' row (ACTIVE (advisory) + contract lines). Characterization:
offsetstyle.test 7/7 (mkzip -runtime/-offsettype hermetic fixtures for
plain/archive/file, none on text + metakit-magic binary, unreadable detail,
src/_build baseline sweep - no kit image probes file);
maketcl_check_offsetstyle_pin added (payload-check suite 4/4). Full utils
suite 69/69, punkexe suite 81/0, live punkluck86 bake silent as the
acceptance's baseline clause requires. Docs: src/AGENTS.md pin bullet with
does/does-not-guarantee, bin/AGENTS.md deployed-kit section, ARCHITECTURE.md
check-family bullet (architecture_lint clean). Reference sweep: no live-tier
references beyond the index entry; goals_xref shows no pairs bridged solely
by G-134. Archive move follows as a pure-rename commit.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
goals_xref score re-run at activation: no relationships beyond those already
recorded (G-028's overlap is lexical - the probe reads assembled build
images, not deployed exes, so no locked-exe interplay; G-131/G-127 already
carry Related coverage). goals_lint clean.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
bin/AGENTS.md gains the user's 2026-07-29 principle: the multishell polyglot
mechanism exists to serve BOOTSTRAPPING (no-tclsh/no-toolchain cold start -
punk-runtime, punk-getzig) and, being complex and potentially fragile long
term, is not to be expanded unnecessarily - capabilities that only run with a
tclsh present belong in-tree behind make.tcl. G-006's Notes record the
corresponding fetcher-shape leaning (non-contract): no punk-gettool polyglot;
the make.tcl-integrated downloader the goal's Approach already leans toward is
the indicated shape (build-tool fetching always has a tclsh - make.tcl IS the
consumer), with punkres on the punkbin tools tier noted as the first concrete
artifact the channel would serve. Doc-only, non-shipped surfaces - no version
bump.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Post-push verification against the live server: punkres-x86_64-windows-0.3.1.exe
fetched from gitea punkbin, sha1 matches the published sha1sums row and the
staged value (166cd176...), fetched binary runs. Every acceptance clause is
satisfied (full evidence in the detail file's flip entry: post-hoc stamping
with tool-self read-back + twapi cross-check, boots, convergence, both
section shapes, file-relative refusal/consented preserve crc-verified,
zip64/multi-disk refusal, WSL non-windows e2e with host recorded, seam
selection + parity + zig-optional degradation, distribution both ways now
LIVE, RT_VERSION-ready tree handling, licensing/provenance).
Flip mechanics: detail Status achieved 2026-07-29 with evidence appended;
index entry moved to GOALS-archive.md (record format incl. that file's
arrow convention); reference sweep - G-127 cross-host mention, G-134
Related line and G-101's container-review rider gain achieved/archive
markers, PROVENANCE.md's explicit detail path repointed to the archive.
goals_xref: no live pairs were bridged solely by G-128. Archive MOVE of the
detail file follows as a separate pure-rename commit (Doc Restructures
move/edit separation).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Distribution convention (recorded in src/tools/punkres/PROVENANCE.md): the
tool publishes to the punkbin tools tier as
win32-x86_64/tools/punkres-x86_64-windows-<ver>.exe (arch-os-version beside
the zig archives; immutable), integrity via that tier's sha1sums.txt.
0.3.1 STAGED as punkbin commit 1b471fc (sha1 166cd176..., built by the tool
step from vendored 0.3.1/f0af880, all other sha1sums SAME) - push is
maintainer-gated per punkbin AGENTS.md, and agents never push. Route
documented in bin/AGENTS.md; the seam's skip notice names both remedies
(build from vendored source, or fetch the prebuilt artifact). Demonstrated
in the program-files checkout: artifact placed as bin/punkres.exe reports
0.3.1 and make.tcl tool list reads it CURRENT against the vendored tree.
Reproducibility note recorded: zig builds differ across invocations in the
PE-header timestamp region - the published sha1 pins THE artifact.
Goal Progress: increment 1f; the only remaining acceptance item is the
maintainer push making the fetch URL live - achieved flip flagged for
confirmation at that point. punkres.test 8/8 re-verified.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Progress increment 1e: route (a) hermetic cross-compile from the pinned
windows zig ran tool-level (linux punkres stamps punk91, full read-back on
linux) and seam-level (make.tcl bake punkluck86 under the WSL tclsh 8.6.14
embedded via punkres on a linux host - the exact cross-host gap this goal
closes); route (b) fetched linux zig 0.16.0 and ran the suite natively
(33/33 after the usage-pin fix) with a byte-identical stamp from the
natively-built binary. Windows confirmed both artifacts (icon bytes, twapi
inside the stamped kit, boots). Cross-host determinism recorded: linux and
windows post-hoc stamps byte-identical; the 4-byte CheckSum delta vs the
fleet artifact is the stub-time-vs-whole-file ordering artifact, both arms,
loader-ignored. Remaining acceptance item: punkbin publication route only.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Closes the observed UX gap (G-128 detail, program-files checkout findings):
fetch reports an active runtime, but bakes reference the suffixless WORKING
name that only 'use' materializes - so a first fetch left bakelist reading
runtime=missing with nothing pointing at the next step. Both payloads (ps1 +
bash, parity wording) now print
note: bakes and projects reference <working> - materialize it with:
punk-runtime use <artifact>
after fetching an -r<N> artifact whose working name is absent, and stay
silent once it exists (the downloads-never-bind rule is unchanged - fetch
still materializes nothing).
Sources edited under src/scriptapps/bin and bin/punk-runtime.cmd regenerated
via scriptwrap multishell (-force 1; checkfile ERROR-free, 4 normal
possibly-bogus warnings) - committed together per the wrap workflow;
runtimecmd_roundtrip byte-identity passes. New pin
runtimecmd_fetch_materialize_hint in runtimecmd_freshness.test (11/11, ~+5s:
hint present on both payloads via the fixture server, absent after use via
the cmd route). Live-verified against the real punkbin server from the
spaced test checkout: hint fires on the no-download path too, silent with
the working copy present.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
punkres.test gains punkres_spaced_paths (8/8, ~3s file total): the store
fixture copied into a directory AND filename carrying spaces, stamped with
the consent flag and read back byte-identical - characterizing the Tcl-list
exec quoting the seam relies on (kit_icon_embed_punkres builds its command
with list/lappend and evaluates it via catch of a pure list: word-per-element,
no {*} needed, no re-substitution).
Goal detail records the live evidence from the user's test checkout at
'C:/repo/jn/program files/punkshell': bake punk9_beta there embedded via
punkres with every path spaced (kit wears PUNKSHELL, boots, bakelist
deployed=current), punk-runtime.cmd fetch/use polyglot fine under spaces,
tool build via PUNK_ZIG override; plus the runtime-store finding - fetch
downloads only the -rN artifact, materialization of the mapvfs-named working
copy needs 'use <full-artifact-name>' (suffixless use selects existing
runtimes only), bakelist reads runtime=missing until then - with candidate
UX improvements flagged for the user.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Forced fleet rebake (user-directed): all ten win32 kits now carry the embedded
PUNKSHELL group icon via punkres, verified per kit (punkres list, sidecar
icon_group=PUNKSHELL + embedding=punkres, extract-ico byte-identical spot
check) and booting (incl. metakit punksys 8.6.13 / punk86 8.6.17 and
punk902z 9.0.2). punkmagic excluded (runtime absent - keeps its old icon and
_build cache); punkshell902 linux = not applicable.
The first fleet pass surfaced a real shape: mingw-built runtimes (tclsh902z,
tclkit-win64-dyn family) keep COFF symbol/debug tables AFTER their sections,
the extraction head carries them, and punkres correctly refused those stubs
as data-classified overlay. Measured against twapi-era artifacts: Windows'
EndUpdateResource has always silently STRIPPED exactly those bytes at
stub-stamp time (leaving PointerToSymbolTable dangling) and the kits work -
so punkres 0.3.0 (upstream dca8634, re-vendored, 33/33) encodes the
distinction: -drop-opaque-overlay DISCARDS expendable trailing data and
zeroes the orphaned symbol-table header fields, vs -allow-opaque-overlay
which RELOCATES a real self-locating payload; conflicting flags rejected;
drop is inert on zip overlays. The seam's punkres arm passes -drop
(twapi-arm-equivalent stub hygiene; bin/AGENTS.md documents it).
Recovery note: a 10-minute foreground timeout killed the first 3-kit rerun
during deploy - stale src/_build/.punkcheck.lock removed after a dead-pid
check per the recorded procedure; the completion bake deployed the
already-wrapped kits. Full punkexe suite 83 tests 0 failed; goals_lint +
architecture_lint clean.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
RT_GROUP_ICON name policy (user decision 2026-07-29): kit_icon_process derives
icon_group from the icon FILE's uppercased rootname (RC convention) -
punkshell.ico -> PUNKSHELL for the default icon and per-kit overrides alike -
and passes it to whichever mechanism embeds. punkres arm uses set-icon -group
(punkres 0.2.0); kit_icon_embed_twapi gains the matching optional
group_override (name only - language adoption unchanged) so the arms stay in
parity. Replaces the retained stub-lineage names (punk91 "SFE", suite kits
"TCLSH"); already-deployed kits keep theirs until their next natural rebuild
(the policy is not in the punkcheck source set).
Sidecar gains icon_group (recorded whenever the icon file exists);
bin/AGENTS.md format doc + ARCHITECTURE.md updated, architecture_lint clean.
Live-verified on punkluck86 rebakes: punkres arm and twapi arm (TCLLIBPATH
route) both emit RT_GROUP_ICON "PUNKSHELL" lang 1033, extracted icons
byte-identical between arms; sidecar icon_group=PUNKSHELL; final deployed
state punkres-stamped and booting. Full punkexe suite 83 tests 0 failed.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
punkres 0.2.0 @ upstream c0eb919: set-icon -group <id|name> overrides the
adopted RT_GROUP_ICON name (stored as given, case-insensitive lookups; lang +
codepage adoption unchanged; re-stamps without the flag adopt the renamed
group - convergent). Vendored tree tests 32/32; bin/punkres.exe rebuilt via
the tool step; punkexe punkres.test 7/7 unchanged. Seam group-name DEFAULT
deliberately not changed - proposal (icon-filename-derived name, twapi arm
gaining the same override for parity) outstanding with the user.
Goal records: metakit 'kit'-shape acceptance clause recorded satisfied-for-now
(user decision) with a rider in G-101's Notes asking its container decision to
include a post-hoc stamping-support review; BSD-2-Clause confirmed. The
2026-07-29 environment finding is CORRECTED: the twapi arm's availability is
launch-cwd sensitivity (make.tcl adds src/vendorlib_tcl9/<host> to library
paths only when startdir tail is 'src'), not a missing root vendorlib tier as
commit 5e9f1c75's message stated - root vendorlib_tcl9/ never exists.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
src/make.tcl kit icon seam (G-057): mechanism selection is now punkres-first -
kiticon::punkres_available (memoized; binary presence at bin/punkres(.exe) is
the selection signal) + kit_icon_embed_punkres (exec wrapper; punkres verifies
its own output). twapi arm unchanged as fallback; when NEITHER serves the skip
notice combines both reasons and names the 'make.tcl tool build punkres'
remedy. Sidecar embedding value gains 'punkres' (bin/AGENTS.md format doc,
ARCHITECTURE.md kit-icon bullet updated; architecture_lint clean).
Live-bake fallback matrix on punkluck86 (win32-ix86 = PE32 arm live): punkres
present -> embedded via punkres, kit boots + smoke OK; punkres absent + twapi
loadable -> via twapi; both absent -> unavailable with combined notice,
embedding none (exact pre-G-128 degradation). Live parity: both arms' baked
kits listing-identical (codepage host-ACP noise finding recorded in the goal
detail) with byte-identical extracted icons.
New src/tests/shell/testsuites/punkexe/punkres.test (7/7 under the
tclsh9.0.5-punk runner; self-gates on bin/punkres + store fixture): overlay-
unsafe refusal exit 3 with untouched input, consented file-relative shift with
convention preserved, payload intact via punk::zip members + crc-verified
extraction, icon replaced (extract-ico == punkshell.ico), idempotent re-stamp
byte-identical, make.tcl tool info punkres provenance records. Full punkexe
suite 83 tests 0 failed (no collateral).
Goal detail: Notes findings (codepage noise, root-vendorlib twapi fragility,
nested tclsfe payload, metakit move-safety -> G-101 pointer updated) +
Progress increment 1 with the two remaining acceptance items (non-windows-host
e2e, punkbin publication route) and one acceptance-wording flag for the user
(metakit 'kit' shape vs 'zip overlay' clause). punkshell 0.30.1 + CHANGELOG.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
goals_xref score G-128 re-run at activation; two relationships recorded as
Notes: G-105 (host-native punkres build for the e2e non-windows clause;
cross-target builds + naming live there) and G-101 (the 'kit' shape is the
sdx/metakit container - post-hoc stamping of it rides the opaque-overlay
taxonomy, move-safety to be measured). goals_lint clean.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Acceptance verified in full on 2026-07-29 (evidence in the detail file's
Progress section): windows-host bakes embed the default punkshell.ico
into all 10 buildable win32 kits across zip (x64 + ix86), sdx-metakit
and stamped-concat assembly, verified by twapi resource inspection
byte-matching the source ico; override round-trip proven and reverted;
boots for zip, metakit and concat images from scratch copies; linux
cross-target kit gets its sidecar with NOT APPLICABLE; the two
incapable-host conditions produce their distinct notices in REAL bakes
(mingw tclsh86: twapi not loadable; WSL linux cross-bake: cross-host
with the G-128 remedy named - and the cross-baked kit boots on windows,
the recorded known shortcoming live); idempotence converges; runtime
store originals untouched; vendored-twapi no-toolchain arm proven under
tclsh9.0.5-punk.
Index entry moves to GOALS-archive.md (ID position); the detail-file
move to goals/archive/ follows as its own pure-rename commit. Reference
sweep: G-023, G-028, G-127 and G-128 notes gain achieved/archive markers
plus what each consumes from the delivered mechanism (G-128: the seam
now exists - kit_icon_process entry point, sidecar record, cross-host
notice naming it as remedy; G-028: the stub-first ordering concentrates
the locked-target exposure at deploy, punk9_beta observed). AGENTS.md
owning-doc pointers land alongside: src/vfs (override convention),
src/runtime (default-icon role + derivation sidecar), src/assets/logo
(propagation honesty: G-057 consumes the src/runtime copy - syncing the
four build-consumed copies after artwork changes stays deliberate, with
assetorigin stale-detection as the drift signal), and an ARCHITECTURE.md
build-section bullet (architecture_lint clean).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Every kit a bake builds now gets a <kitname>.resources.toml sidecar
(build folder + deployed beside bin/<kit>) recording the build-time icon
choice: schema-1 flat TOML in the G-135 tolerant family - kit, target,
kit_type, icon_origin default|override, icon_source (repo-relative),
icon_hash, provenance source+hash lifted from the icon's assetorigin
sidecar (the chain reaches the SVG master), embedding, embedding_status
embedded|not-applicable|unavailable|failed, embedding_reason. Byte-stable
(no timestamps, write-only-if-changed); named "resources" so the parked
RT_VERSION follow-on extends the same file. Format doc: bin/AGENTS.md.
win32-target kits get the icon embedded as RT_ICON/RT_GROUP_ICON via the
twapi resource-update APIs - the tcl-sfe sfe-0.2.tm mechanism (Ashok P.
Nadkarni) generalized: enumerate all existing icon/group entries via
extract_resources, delete ALL, write ids 1..N plus one group under the
first pre-existing group's name+lang (fallback 1/1033) in a single
update transaction - idempotent by construction. Ordering is stub-first:
a PER-KIT copy of the extraction phase's payload-free raw runtime prefix
is stamped BEFORE payload attach, so the resource rewrite can never
corrupt an overlay; all three assemblers (zipfs mkimg, zipcat/concat,
sdx wrap) consume the stamped copy; runtime store originals untouched.
::punkboot::kit_icon_process is the single internal entry point with
mechanism selection inside (a G-128 portable stamper becomes a
substitution). Skip taxonomy: non-PE target / runtimeless .kit =
NOT APPLICABLE; cookfs, missing icon, missing raw prefix, cross-host
(non-windows process family), twapi-unloadable = UNAVAILABLE with
distinct named reasons; embed errors = recapped BUILD-WARNING + status
failed. Sidecar written in every case. Default icon joins the kit's
punkcheck source set (icon changes rebuild kits); sha256 self-contained
(bootsupport has sha1/md5 only), memoized per run.
Verified (evidence in the goal detail file Progress): full bake embeds
all 10 buildable win32 kits (zip x64+ix86, sdx metakit trio) with
resource inspection byte-matching the source ico (punk91, punk86,
punk91ix86 inspected; group name SFE preserved); scratch-copy boots for
zip, metakit and a stamped concat image (androwish exe-path mount);
override round-trip via punk9wintk903.vfs (solid ico embedded +
recorded, then reverted); linux cross-target punkshell902 sidecar with
not-applicable; mingw tclsh86 bake takes the concat path with the
distinct twapi-unloadable notice; vendored twapi 5.0b1 arm proven under
tclsh9.0.5-punk; double-restamp converges. punk9_beta embedded+built
but deploy still blocked by the known bin file lock (stamped product
waits in src/_build).
make.tcl workflow text gains the icon step + sidecar output; punkshell
0.29.0 -> 0.30.0 (minor: kits now wear the punkshell icon; new shipped
sidecar) with CHANGELOG entry. G-057 detail file: ordering + override +
sidecar + seam decisions recorded with tcl-sfe attribution; cross-host
known-shortcoming + G-128 remedy recorded per acceptance.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
User-directed proposed->active flip. Activation freshness survey
(goals_xref score G-057) found no relationships beyond those already
recorded in the detail file (G-128 and G-127 linked bidirectionally;
G-123 referenced with the optional back-pointer absent; higher-scoring
unlinked pairs are lexical coincidence). goals_lint clean.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
User-approved resolution of the open call recorded at G-135 achievement:
src/vfs/_vfscommon.vfs/punkshell.ico gains its assetorigin sidecar
(schema 1, hash equals source_hash - byte-identical derived copy of
src/assets/logo/punk-mark.ico, source recorded ../../-relative). The
sidecar is root-level user-curated payload beside the icon itself
(vfscommonupdate regenerates the modules/lib subtrees, not these), and
ships inside every kit that merges the common payload from that kit's
next bake; inside a kit the recorded source is absent, so a checker
truthfully reports source-absent there while still hash-confirming the
icon bytes - in this tree it verifies (assetorigin_check: 9 records, 9
verified). The per-kit mkzipfix.vfs / punk8_statictwapi.vfs copies stay
unrecorded (no decision requested; unrecorded is silent and supported).
src/assets/logo/AGENTS.md ownership bullet and the G-057 handoff note
updated to record the made call. No bake run - deployed kits pick the
sidecar up when next baked.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Acceptance verified in full (evidence in the detail file's new Progress
section): format documented with schema key in src/assets/logo/AGENTS.md;
tolerant reader; six-state checker proven on constructed fixtures under
tclsh 8.6.11, Tcl 9.0.3 and the punk91 kit runtime; generator with no
Windows-only component regenerating all four .icos plus the web rasters
byte-identically before make-ico.ps1 was removed; sidecars exist and
verify for every generated artifact under the four asset directories
(live tree: 8 records, 8 verified).
Index entry moves to GOALS-archive.md; the detail file move to
goals/archive/ follows as its own pure-rename commit (root AGENTS.md
"Doc Restructures": moves separate from edits). Reference sweep:
G-057 and G-136 Related lines gain achieved/archive markers plus
pointers to the concrete deliverables they consume (G-057: record
format, checker, the verified src/runtime/punkshell.ico derived-copy
sidecar, and the still-open kit-shipping user call; G-136: the
committed project-default icon.ico + sidecar pair its injection copies
verbatim). src/assets/logo/AGENTS.md G-135 mentions gain archive paths.
Notes record the implementation-time resolutions: self-contained
flat-toml subset reader + embedded sha256 (no tomlish, no tcllib);
src/runtime/punkshell.ico sidecar written (passive file, nothing
ships); _vfscommon.vfs / mkzipfix.vfs / punk8_statictwapi.vfs copies
stay unrecorded pending the user call on shipping sidecars inside kits.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
User-directed proposed->active flip. Activation freshness survey
(goals_xref score G-135) found no relationships beyond those already
recorded in the detail file (G-136, G-057, G-128, G-133 all referenced;
higher-scoring unlinked pairs are lexical coincidence). goals_lint clean.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Activation and achievement same day at user direction ('activate and
start on it'). Activation freshness survey (goals_xref score G-033)
recorded in the detail file: G-043's one-directional reference is the
only unlinked real relationship; G-123/G-127/G-131 overlap by
punk_main.tcl/bin co-location only.
Detail file gains the Progress record (option (a) inline-walk
decision, verification evidence on the rebaked punk91 kit, the
moduledoc-0.1.1 live-help note and the pending vfscommonupdate
promotion) and moves content-identical to goals/archive/; index entry
moves GOALS.md -> GOALS-archive.md.
Reference sweep: G-016/G-047 relationship notes point at the archive
and the ::punkboot::proj_root_find delivery; G-032's Approach now
says the packagemode leader text is LIVE and its remaining lane is
rendering/parse wiring; G-089's Related note records that the visitor
root walk it rides is live, remains defined post-boot, and that the
boot-interface packagemode hint it needs is still absent; G-031 gains
the fork-drift datapoint (proj: landed in punk_main.tcl only,
project_main.tcl still lacks src mode and proj:); G-018/G-035/G-043
mentions gain achieved/archive markers.
goals_lint clean (85 active, 51 archived), architecture_lint clean.
Claude-Session: https://claude.ai/code/session_0156PuejSCGjgeGb7jiABrDU
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Pre-activation review outcome (user-approved wording): G-135's record
shape pivots from one assetorigin.toml per directory to a per-asset
sidecar, <asset-filename>.assetorigin.toml beside the asset it
describes.
G-135 contract: Scope (both tiers, mirror-identical) names per-asset
*.assetorigin.toml sidecars. Acceptance rebuilt - records are bound by
the sidecar's own filename (suffix stripped, same directory; files
ending in the suffix are records, never assets; reader tolerance kept);
the checker's state model is repaired to six states evaluated in table
order with first match winning (artifact-absent added for records whose
paired asset is gone; verified now requires every hash the sidecar
records to match, so a hash-only sidecar verifies on the artifact hash
alone; fixtures must distinguish stale / replaced / artifact-absent);
the generator clause requires byte-identity per the invocation profile
that produced each .ico and that the generator (re)writes each produced
artifact's sidecar, so regeneration cannot leave a stale record; the
final clause requires sidecars to exist and verify for every generated
artifact under the four asset directories.
G-135 body: Approach carries the pairing rationale (no path key, file-
pair lifecycle, survives wholesale and single-asset copies, composes
under merge_over same-path replacement) and the hash-required minimum;
the six-row state table gains the evaluation-order and unhashed-claims
notes. Alternatives inverted: the per-directory [[asset]] record is now
the rejected shape (shared-state writers - the punkcheck G-094/G-095
lesson; file-level clobber at a .vfs root under overlay merges;
invisible dangling entries; single-asset copies lose their record), and
a fauxlink-carried record is recorded as considered-and-rejected (the
filename would encode a mutable fact; overlay pairing would need a
nominal-keyed composition invariant in every composer), preserving the
nominal-keyed idea as fauxlink hardening independent of this goal (71
fauxlinks in tree, zero same-directory nominal collisions, surveyed
2026-07-28). Notes add the override-without-sidecar kit behaviour
(travelled common sidecar truthfully reads replaced), the eased checker
parsing posture, and the open pre-activation items (which of the four
build-consumed punkshell.ico copies get sidecars; whether a
_vfscommon.vfs sidecar shipping inside every baked kit is the intent).
G-136: acceptance names icon.ico.assetorigin.toml and the per-asset
dependency; Approach/Notes reworded to match. G-057: one Notes sentence
disambiguates its per-kit icon sidecar from G-135's record sidecars.
goals_lint clean (index/detail mirrors exact, archived-goal references
markered); goals_xref score G-135 re-run - G-136 and G-057 linked.
G-135 stays proposed; activation is the user's flip.
Claude-Session: https://claude.ai/code/session_014wNGMsdNFFrU1duADeirgm
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Non-contract Notes addition (user-directed). G-133 (achieved 2026-07-27) landed the
structural arch scan this goal's Acceptance still asks for: a recapped BUILD-WARNING
naming file, found architecture and kit target; no warning for multi-arch
platform-subdir packages or recognised vendor spellings; and the scan running for
cross-target kits. That covers the clause in full.
The clause is deliberately left in place rather than trimmed - trimming an Acceptance is
a contract edit - so the note says how to read it: a regression pin on behaviour that
already exists, not work to do. It also states the goal's genuine remainder so whoever
activates it is not misled about the size: the bin/kits/<platform>/ output split, the
per-target payload declaration, and keeping G-133's smoke probe pointed at wherever the
relocated artifact lands.
Goal, Acceptance and Scope are unchanged.
Assisted-by: harness=claude; primary-model=claude-opus-5[1m]; api-location=anthropic.com
Two proposed goals from the src/assets/logo work, split rather than combined:
"the master-to-derived chain is verifiable anywhere" and "generated projects
arrive with an icon" are separate outcomes with separate acceptance, and the
second merely consumes the first.
G-135 - asset provenance records. Nothing currently states that
src/runtime/punkshell.ico came from punk-mark.svg, so one failure is
undetectable: edit the SVG, forget to regenerate, and the committed .ico
silently stops depicting the master. An optional directory-scoped
assetorigin.toml records the derivation; a plain-Tcl checker classifies each
asset as unrecorded / verified / source-absent / replaced / stale, advisory
only. Absence of a record is the DEFAULT and stays silent - a record is an
opt-in claim, and every field but path is optional, so "I know this file, I
don't know where it came from" is expressible.
The same goal retires the Windows tie in make-ico.ps1. The dependency is one
line - System.Drawing, decoding PNG to raw BGRA - since pwsh and rsvg-convert
are both cross-platform and Tcl core ships zlib.
G-136 - generated projects seeded from src/assets/logo/project-default/ at
generation time, as a sibling to bootsupport_inject with punkcheck install
records, rather than storing artwork in layout trees. Layout storage would mean
three copies with no master (project-0.1, basic, and the punkcheck-managed
modpod-templates copy), reversing G-087's thin-layout achievement. Because
G-135's record is directory-scoped with relative paths it copies verbatim and
reads `verified` at the destination.
Scope for G-135 separates the two tools rather than bundling them: the generator
is replaced in place under src/assets/logo/ (it operates on the files beside it
and is already documented there), while the checker is a lint in the shape of
goals_lint and architecture_lint and belongs in scriptlib/developer/ - with the
home explicitly revisited if it becomes a bake step, since scriptlib/ is
user-only and make.tcl must not depend on it. That deferral follows G-057's
existing "helper proc location decided in the work" pattern.
Both goals record the workflow questions deliberately kept OUT of their
acceptance: when the checker runs (bake step vs subcommand), and which layouts
declare an icon slot.
G-057 gains a Related pointer to G-135 per the dependency-direction convention -
its per-kit sidecar is specified to carry "source .ico identity and provenance",
which these records are the natural source for.
goals_lint clean (86 active-index goals, 50 archived); the G-133 reference
carries its archive marker in Notes per the Archive rules.
Claude-Session: https://claude.ai/code/session_01YNjnq6oDzecknLg7AuWZgU
Assisted-by: harness=claude; primary-model=claude-opus-5[1m]; api-location=anthropic.com
The four build-consumed copies are renamed and their artwork replaced with
src/assets/logo/punk-mark.ico (all four byte-identical to the master):
src/runtime/punk1.ico -> src/runtime/punkshell.ico
src/vfs/_vfscommon.vfs/punk1.ico -> .../punkshell.ico
src/vfs/mkzipfix.vfs/punk1.ico -> .../punkshell.ico
src/vfs/punk8_statictwapi.vfs/punk1.ico -> .../punkshell.ico
Recorded as delete+add rather than renames: the content is entirely different,
so git's similarity detection finds no link and --follow will not trace through.
The pre-2026-07 artwork keeps its own lineage under src/assets/logo/legacy/,
now the only place the punk1 name survives.
No code referenced the old name - every mention was documentation or goal prose,
checked before renaming.
G-057's contract lines are updated for the new path (Scope in both tiers, plus
Goal and Acceptance): pure path substitution, no semantics changed. Its Context
gains a dated note recording the rename and artwork swap, and its _vfscommon.vfs
override-detection wrinkle now names punkshell.ico. goals_lint clean.
Adds src/assets/logo/project-default/, a frozen monochrome placeholder - a blank
screen wearing the crest - held as the single copy for seeding generated
projects. Unbranded so it reads "replace me" rather than as a product identity.
Bezel and crest are ONE union path (drawn as two shapes the bezel's top edge
cuts a visible line across the mohawk) and the screen is filled rather than
outlined (a solid mass survives 16px where nested thin strokes merge). It shares
only the crest with punk-mark.svg and must not be re-derived from it: tracking
the real mark would churn every generated project on every logo tweak.
Also corrects a defect introduced in 91fa500e. The Ownership bullet in
src/assets/logo/AGENTS.md said "do not repoint build consumers at this directory
on your own initiative" and then, in the next sentence, instructed re-copying
them by hand after regeneration - so whichever half an agent read first would
win. It now states the dated fact and names G-057 as the owner of future
propagation. Distribution machinery does not belong in an AGENTS instruction,
and drift wants a check rather than a standing manual obligation.
Stale punk1.ico copies were also swept from the untracked build trees
(src/_build x12, bin/test, bin/test2, scratch, testsdx) so the next bake cannot
merge both names into a kit payload.
Claude-Session: https://claude.ai/code/session_01YNjnq6oDzecknLg7AuWZgU
Assisted-by: harness=claude; primary-model=claude-opus-5[1m]; api-location=anthropic.com
Clears the 5 informational goals_lint warnings, all on this file: G-096, G-098,
G-099, G-100 and G-103 were referenced with no achieved/archive marker anywhere.
The check reads a 3-line window around each G-<n> mention for
achieved|archive|landed and ORs across every mention in the file, so ONE marked
mention clears an id. That matters here: G-103's only mentions are in Scope
(index-canonical) and Acceptance (detail-canonical), both proposal-first. Neither
is touched - the marker goes in Notes per the goals/AGENTS.md Archive rules,
carrying the archive path and stating what G-103 contributes (the artifact-
metadata contract those two lines name: a published runtime's record carries its
target, which for this goal must name the 32-bit platform).
G-096/G-098/G-099/G-100 are marked in place in Context. That mention is pure
history - the phrasing was already factual rather than pending-tense - so a
compact "all achieved and archived" is proportionate to the rules' guidance
rather than four inline archive paths.
Context paragraph reflowed to the file's ~90-char wrap (the marker insertion had
pushed one line to ~118). Body lines now top out at 97, a pre-existing line; the
1180-char maximum is the Acceptance line, single-line by header grammar and
unchanged.
goals_lint clean (84 active-index goals, 50 archived).
Claude-Session: https://claude.ai/code/session_01Y1diJnhjUxKgEG6EwYAzxj
Assisted-by: harness=claude; primary-model=claude-opus-5[1m]; api-location=anthropic.com
Every acceptance clause is met: vendored source green under the pinned
zig 0.16 toolchain via the make.tcl tool step (zig optional), upstream
extract-to-directory + pinned porcelain listing, punk::zip accelerator
with the parity suite (identical names/bytes/mtimes both engines over
the G-124 shapes and the file-relative piperepl kit; pure path proven
when absent), recorded benchmark (crossover ~15-20 members, material
from ~50, x2.3-2.6 native / x3.8-4.9 kit-hosted), and PROVENANCE.md
origin/re-vendor/licence records.
Index entry moved to GOALS-archive.md; detail Status flipped (the file
moves to goals/archive/ in the adjacent pure-rename commit). Reference
sweep: G-101's pending-tense accelerator mention rewritten as achieved
with the archive path; G-128's Depends-on gains the archive pointer
plus the now-existing pattern surface and the zig-0.16 traps its port
should read first.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
The final G-126 acceptance clauses:
- punk::zip::accelerator (auto|none|<path>): auto probes
env(PUNKZIP_EXE) then a punkzip beside [info nameofexecutable];
resolution cached until reconfigured
- unzip hands whole-archive member WRITING to the accelerator only when
the call is one it serves identically (globs {*}, no excludes,
default -overwrite/-mtime/-verify, ascii member names) and re-stamps
mtimes with punk::zip's local-time convention afterwards, so the two
engines produce identical trees; preflight refusals, member selection
and the returned names always come from punk::zip's own reader (the
G-124 floor, unchanged); accelerator failure falls back to pure Tcl
silently; last_unzip_engine/last_accelerator_note expose the per-call
decision
- parity suite zipaccel.test (9 tests): identical names, bytes and
mtimes through both engines over the G-124 shapes and whole-kit
extraction of the file-relative tclsh90b4_piperepl.exe (841 members);
listings engine-independent; punkzip porcelain agrees with punk::zip
member dicts on every shared field (mtime excluded by design - UTC vs
local convention); pure path proven when the binary is absent;
selective calls proven to run pure. Implicit directories (kits store
no dir entries) are excluded from mtime comparison - neither engine
stamps them
- recorded benchmark (in the goal detail): accelerator fixed cost
~9-13ms, crossover ~15-20 members, material (>= x1.7) from ~50;
x2.3-2.6 at kit scale under a native tclsh and x3.8-4.9 kit-hosted
(punk91.exe 21.9s -> 5.7s) - the bake-from-kit case the goal
motivated
- full runtests at recorded baseline under tclsh9.0.5-punk: 1186/1211,
1 failed = the pre-existing exec-14.3 baseline
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
New surface for the vendored first-party build tools under src/tools:
make.tcl tool list|info|build|test ?<toolname> ...? ?-test 0|1?
- discovery is convention-based (a src/tools directory carrying
build.zig is a tool), so the G-128 tool will appear with zero
make.tcl edits; per-tool records are read tolerantly from
build.zig.zon (version, minimum_zig_version floor) and PROVENANCE.md
(upstream, vendored commit)
- list/info report installed-binary state (current|stale|absent vs
bin/<name><exe-suffix>) and the resolved toolchain
- toolchain resolution: PUNK_ZIG=<path> overrides; otherwise
bin/tools/zig* is scanned and the LOWEST release satisfying the floor
wins - deterministic as newer toolchains get unpacked beside the
pinned one; dev builds count only when their base version exceeds
the floor
- build runs the tree's own 'zig build test' as an EXIT-CODE gate
(expected stderr warnings do not fail it), then builds ReleaseSafe
and installs to bin/; nothing installs when the gate or build fails;
-test 0 skips the gate; build caches are deliberately left in place
between runs for rebuild speed (git- and fossil-ignored)
- zig stays OPTIONAL: packages/bake never require the step; without a
suitable toolchain, list reports the state and build/test exit
nonzero with bin/punk-getzig.cmd guidance
- full subcommand accompaniments per src/AGENTS.md: punk::args argdoc
(SUMMARIES/HELPTEXTS/bespoke passthrough definition), SUBGROUPS
("vendored tools"), known_commands, degraded-mode dispatch, plain
help text, bootsupport-staleness exemption, workflow text (new
OUT-OF-BAND SUBSYSTEMS section also covering buildsuite), project
version 0.28.3 + CHANGELOG entry
- piped characterization (zig-independent):
src/tests/shell/testsuites/punkexe/maketcltool.test - 4/4 green
- verified live: 'tool build punkzip' gated on the vendored tree's
130/130 suite and installed bin/punkzip.exe (ReleaseSafe, v2.3.1,
1.1MB) over the stale Nov-2024 v2.1.0 binary; list state flipped
stale -> current; PUNKBOOT_PLAIN degraded dispatch and tabled help
verified
G-126 Progress updated: the acceptance's build-step clause is
satisfied. Remaining: punk::zip fast path, parity suite, benchmark.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Vendored per the goal's developer decision: build.zig, build.zig.zon,
LICENSE + LICENSE-time-dot-zig, README.md and src/ (sources and test
fixtures) from the clean upstream checkout at commit
0882f0373eb2c983142e713c814b91aa82cfcea7 (punkzip v2.3.1). Upstream
doc/ (article mirrors), reference/ (hwzip 2.4 C source) and repo-local
agent/porting notes are deliberately not vendored.
- src/tools/punkzip/PROVENANCE.md: origin, vendored commit, re-vendor
procedure (clean-upstream-only), G-063-style licence records
(public-domain hwzip lineage, MIT musl time.zig, zero dependencies)
- src/tools/AGENTS.md: new DOX child - vendored-tools boundary,
upstream-first editing policy, pinned-toolchain verification; indexed
from src/AGENTS.md
- .fossil-settings/crlf-glob: cover the vendored fixtures (hamlet.txt
is CRLF byte-exact test data the compression tests pin sizes
against; git stores it verbatim - core.autocrlf false)
- verified from the vendored location with the pinned
bin/tools/zig-x86_64-windows-0.16.0 toolchain: zig build test 25/25
steps, 130/130 tests green; build outputs (.zig-cache/, zig-out/)
were already gitignored at any depth
Goal Progress updated: the acceptance's vendoring clause (origin,
state, re-vendor procedure, licensing) is satisfied. Next: the
make.tcl tool build step.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Upstream punkzip 0882f03 fixes the long-standing dir-mtime limitation
via a deferred post-extraction stamping pass (windows direct
CreateFileW BACKUP_SEMANTICS + SetFileTime; Io best-effort elsewhere),
pinned by tests at the stored epoch including the -d route and the
build roundtrip. Notes bullet updated from proven-fixable to fixed.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
File mtimes preserved exactly (no regression old->new exe); atimes and
directory mtimes not preserved - the dir case is the long-standing zig
limitation, still present in 0.16 Io, but proven fixable via direct
CreateFileW(BACKUP_SEMANTICS, WRITE_ATTRIBUTES) + SetFileTime with a
deferred post-extraction pass. Also records the DOS-time-as-UTC vs
UT-extra-field semantics difference vs bsdtar for the parity suite.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Upstream punkzip 572d893 (v2.3.0, 130/130) turns the January build
scaffolding into a working streaming recursive zip writer per user
decision (finish rather than remove - the shipped tool should be useful
from the start). Progress records the design (per-member streaming,
sorted deterministic entries, dir members, zip64 refusal) plus the
second zig-0.16 trap found en route (OpenFileOptions.allow_directory
defaults true, breaking file-vs-dir probes). Remaining-for-acceptance
list now starts at vendoring.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Upstream punkzip 7f88096 (v2.2.0, suite 128/128) delivers both
upstream-side prerequisites from the goal's Approach: the
extract-to-directory argument and the machine-readable listing mode
with its format pinned by CLI tests. Progress records the v1 porcelain
format contract for the parity-suite work; remaining-for-acceptance
list trimmed accordingly. Also noted: user-committed reference/
hwzip 2.4 C source upstream (cb2a731).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Upstream punkzip commits 3b87087 (0.16.0 port, floor moved, Init/Io
threading, build-graph install-order fix, msys overlapped-stdout fix,
v2.1.3, verified 841-member CRC extraction from the file-relative
piperepl kit) and 2e49c75 (three prefixed-zip container tests pinning
base_offset for both offset conventions; suite 125/125). Notes gain the
overlapped-stdout trap record (applies to the G-128 tool as well);
Progress section added with the remaining-for-acceptance list.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Status proposed -> active in the index with the detail-file mirror
updated. Pre-activation baseline is recorded in the detail file Notes;
first work item is the zig 0.16 port of the upstream checkout.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Upstream c:/repo/jn/zig/punkzip commits e9b5b553 (0.15.2 migration
completed, zig build test 122/122 green - bitstream wiring fixed, CLI
suite compiling and pinning current output) and 78453fc0 (localtime
banner restored dependency-free on stderr; zeit stays out per user
decision). Context refreshed; Notes record the decisions, the
stdout/stderr contract, and the known upstream gaps (base_offset
untested zig-side, build subcommand scaffolding, 0.16 argsAlloc).
Non-contract detail-file updates only; status stays proposed -
activation flip awaits user confirmation. goals_lint clean.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Two halves of one file-relative policy decision. G-134 (new, proposed): advisory
post-assembly punk::zip::archive_info probe at the G-133 seam pins make.tcl's own
kit outputs archive-relative - by-construction property becomes a checked contract;
mkzip -offsettype file and modpod stay available for deliberate manual creation.
G-128: the straight file-relative refusal becomes default-refuse with a consent-flag
preserve (central-directory offset fix-up by the shift delta, zip64/multi-disk still
refused), plus Notes recording the rationale, the Authenticode sign-after-stamping
rule, and the convention-conversion parking. goals_lint clean (85 active, 49
archived).
Assisted-by: harness=opencode; primary-model=openrouter/moonshotai/kimi-k3; api-location=openrouter.ai
goals_xref report showed G-127<->G-131 (sole bridge G-133) and G-123<->G-127
(both bridges now archive-tier) as unlinked pairs with real overlap - recorded
directly in G-127's Notes per the flip's shared-archived-refs rule.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Activation (user-directed this session) through achieved flip in one lifecycle
change-set: index entry moved to GOALS-archive.md (Scope relocated verbatim;
title preserved with the [achieved] status transform; Detail: line becomes the
archive detail pointer - the standard flip transformations), detail file gains
the activation survey Related: notes (G-114 prevention-side sibling, G-128
sibling PE surface), the advisory-as-drafted open-decision resolution, and the
full Progress/verification records (live bake evidence on
punkluck86/punk91ix86/punk86/punkshell902, the zint real finding, 92.6ms avg
scan cost, suite results). Reference sweep pushes the archived file's
actionable notes to G-024 (toml schema home), G-131 (one-vocabulary +
runtime_caps), G-127 (target-addressing adoption), G-130 (subdir exemption for
32-bit growth), G-123 (publication citation), G-114 (detection-side sibling).
Detail file moves to goals/archive/ in the following pure-rename commit.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Candidate goal from the G-129 aftermath (user-observed 32-bit kit breakage):
an advisory binary-architecture scan over the merged tree at the G-125 gate
seam (platform-subdir aware, covers cross-target kits) plus a per-kit
post-bake smoke-require probe through the artifact's own tclsh subcommand
(plain package require - the only observer of version-preference shadowing).
Overlap survey named G-024/G-131/G-127/G-028/G-130/G-123, non-overlap G-115,
precedent G-125/G-129. Advisory-vs-gate for smoke failures recorded as the
open decision at activation.
Claude-Session: https://claude.ai/code/session_01UEgomWq6kA6c4A8GswqqGW
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Detail file: Status flipped, Context table corrected (the LUCK backport HAS a
::zipfs ensemble - just no root subcommand), Progress + verification records
added (both 32-bit kits boot and resolve from their mounts, four 64-bit kits
byte-identical before/after, unattributable-mount stderr report demonstrated,
both zip offset conventions verified on the backport, kitmountpoint.test 4/4,
full suite at the exec-14.3-only baseline). Index entry moved to GOALS-archive.
Reference sweep: achieved/archive markers added at the G-129 mentions in G-101,
G-024, G-130 and G-131 (pending-tense Approach line rewritten); forward-pointing
notes pushed to their targets - G-131 gets the factored-derivation shape,
measured mount tables, app/main.tcl hook and the LUCK both-capability probe row;
G-123 gets the bin/AGENTS.md kit-wrappable requirements as its publication
criterion pointer.
Claude-Session: https://claude.ai/code/session_01UEgomWq6kA6c4A8GswqqGW
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Index entry + detail mirror flipped proposed->active. Activation-freshness
overlap survey (goals_xref score G-129) found one relationship drafted since
the goal was written: G-130 points here with no back-pointer - recorded as a
Related: note in the detail file.
Claude-Session: https://claude.ai/code/session_01UEgomWq6kA6c4A8GswqqGW
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Both pairs read as one-directional in goals_xref (G-131 -> G-129 scoring 3.55, G-131 ->
G-101 scoring 2.03) because the dependency convention has the consumer point at its
predecessor. Adding the reverse edge so a reader who opens G-129 or G-101 - the two goals
likely to be activated first - sees what is waiting downstream. Non-contract Notes only;
neither goal's Goal or Acceptance changes, and both still stand alone.
G-129: G-131 generalises its derivation from "where is the zipfs image mounted" to "which
container is attached at all". That does not change what G-129 delivers, but it does say
something about HOW - keep the derivation factored as a step that answers a question about
the running kit rather than inlining a zipfs assumption into the surrounding path assembly,
so the metakit arm can be added beside it rather than around it.
G-101: this is the more consequential one. G-131 wants a runtime that boots from EITHER
container, which bears on how G-101's decision should be FRAMED - if G-131 is wanted, the
useful outcome is not "pick one container for 8.6 and close the question" but "establish
that metakit is carryable AND that the zipfs backport is carryable, and record which is the
default". The file already surveys both candidates and both look additive; the two sections
were written independently as competing options, and G-131 is the reason to read them as a
possible pair. Recorded explicitly that this does not block G-101's decision - it can still
be decided without committing to G-131.
goals_xref now reports both pairs as linked.
Assisted-by: harness=claude; primary-model=claude-opus-5[1m]; api-location=anthropic.com
'make.tcl bootsupport' failed three times this session replacing the zip-based
punk::mix::templates modpod, always with:
error copying "<src>" to "<dst>": invalid argument
Root cause, demonstrated rather than inferred. A zipfs mount MEMORY-MAPS its archive
(tclZipfs.c CreateFileMappingW + MapViewOfFile), and windows refuses to overwrite a file
with a user-mapped section open - ERROR_USER_MAPPED_FILE (1224). Any holder blocks it: a
running punk shell that loaded the modpod, a src-mode session, or the build itself.
Reproduced directly: the same file copies fine unmounted, fails while zipfs-mounted, and
copies fine again once unmounted.
The message is a dead end BY CONSTRUCTION, which is why two earlier attempts at
characterising this (in commit messages and in the archived G-124 detail file - first "a
modpod make.tcl has itself mounted", then "a transient lock") were both wrong in different
ways. Tcl_WinConvertError maps only Win32 codes 0..267 and sends everything above them to
errorTable[1], which is EINVAL - so EVERY high-numbered windows error surfaces as "invalid
argument", naming neither cause nor remedy. Byte-identical code in 8.6 and 9.1b1.
FIX. ::punkboot::replace_possibly_mapped_file tries the ordinary copy and, on failure,
falls back to DELETE-THEN-PLACE, which windows does permit: unlinking a mapped file leaves
the holder reading its own mapping while new content lands at the name (measured: delete
succeeds while mounted, the mount keeps serving its old content afterwards). Replacement
content is staged to a sibling <target>.punkboot-new first, so a mid-sequence failure can
never leave the target missing; a 'broken' return - unlinked and unrestorable - is reported
as a build failure naming the file to restore by hand. This replaces a narrower prior
workaround that only recognised the already-identical case and otherwise recorded FAILED.
DIAGNOSIS. ::punkboot::mapped_file_hint fires when a genuine failure carries the catch-all
message and explains what it actually means and which process class to look for, instead of
leaving "invalid argument" bare. It stays silent for unrelated errors.
Verified on the real failure: the bootsupport run that has failed all session now reports
"(in-place overwrite refused - replaced by delete-then-place; target was memory-mapped, e.g
a mounted modpod)" and completes, with no hand-copy and no rerun. Helper-level checks cover
the unmapped path (plain copy, unchanged), the mapped path (recovers, content correct,
holder's mapping intact, no temp left behind) and both hint branches. Full suite 1167 tests,
1146 passed, 1 failure - core/tcl exec-14.3, the documented baseline.
Documented in src/bootsupport/AGENTS.md, including the general warning that 'invalid
argument' from ANY windows file operation in Tcl means "some windows error above 267" and
must never be read at face value.
Also drafts G-132 (user-approved): the errno catch-all is upstream's defect, not ours, and
deserves reporting. The goal is deliberately shaped so an AGENT DRAFTS AND THE DEVELOPER
SUBMITS - no account use, no web form, no API - following the G-039 precedent, with the
submission-ready text staged in TEMP_REFERENCE and the finding, reproducer, eventual ticket
URL and disposition kept in the tracked detail file, because TEMP_REFERENCE is one
'git clean -xdf' from gone. The report's claim is deliberately narrow: the errno conversion
is plainly wrong, while the related fact that 'file copy -force' over a mapped file succeeds
on unix and fails on windows rides along as context rather than as a second demand.
punkshell's workaround is explicitly not removed if upstream fixes it - an upstream fix
dates it rather than deletes it.
Assisted-by: harness=claude; primary-model=claude-opus-5[1m]; api-location=anthropic.com