Browse Source

G-171 drafted (proposed): routine builds never write tracked paths - explicit commands own VCS-visible changes

Index entry + detail file goals/G-171-bake-writes-land-untracked.md; goals_lint
clean (81 live, 90 archived). Drafted at user direction from the 2026-08-06
consumer-machine incident: a stale untracked bin/punkzip.exe (pre-2.4.0)
received the v2.4.0 -b flag, swallowed it as the archive-name positional
(misdirected 90MB src/-b archive), the kit-container step failed and the died
bake stranded half-replaced tracked src/vfs trees - the failure class this
goal removes by construction.

Contract: routine bake/bakehouse/vfslibs phases write only to VCS-ignored
locations (declared payloads materialize into ignored staging; merge-time
layering enacts drop-in-wins identically on records-free fresh clones);
deliberate tracked-tree writes remain available only as explicit
materialize/tidy commands whose output is an ordinary reviewable VCS change,
with docs steering to declarations by default. Acceptance keys on a kill-probe
(clean tree in, clean tree out at arbitrary kill points), phase write-target
self-checks, and a 'bake -hold' inspection point whose completion must equal a
single uninterrupted bake - staged assembly reused only under digest-confirmed
currency (machinery shared with G-162), held staging machine-owned (inspection
sanctioned, hand-edits redone, never shipped).

Related: G-004 (write-side complement), G-157, G-162, G-065, G-141, G-147,
G-006; deliberately revises archived G-115's operative-assembly-area stance
and generalizes archived G-127's staging pattern.

Claude-Session: https://claude.ai/code/session_01EukjNTv2r5msFgHzWgaCdS
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 4 days ago
parent
commit
6953f751a8
  1. 4
      GOALS.md
  2. 124
      goals/G-171-bake-writes-land-untracked.md

4
GOALS.md

@ -402,3 +402,7 @@ Detail: goals/G-166-cmdinfo-unavailable-surfacing.md
Scope: src/modules/punk/args-999999.0a1.0.tm (form selection/candidacy availability filter + tailored raises, option-scan unavailable-name recognition, synopsis/table renderers - annotated form lines, unavailable option rows, automated other-shapes note, formstatus 'available' field, -form display-vs-parse split); src/modules/punk/ns-999999.0a1.0.tm (cmdhelp -return text form-section heading annotation; form narrowing inherits the availability filter); src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm (adoption on curated real 8.6-vs-9 deltas); src/tests/modules/punk/args/testsuites/args/ (new suite + formviability/tclcoreparity extensions)
Detail: goals/G-167-punkargs-version-delta-availability.md
### G-171 [proposed] Routine builds never write tracked paths - explicit commands own VCS-visible changes
Scope: src/make.tcl (bake/bakehouse/vfslibs - VFSPAYLOAD + PACKAGES phases, kit assembly, new explicit materialize/tidy commands); src/vfs/ (payload declarations, _targets staging generalization, README.md + AGENTS.md precedence spec); src/_bake (assembly staging); bin/packages (lib-tier consumption); .gitignore + .fossil-settings/ignore-glob (staging ignore coverage); src/tests/shell/testsuites/punkexe/ (kill-probe + precedence characterization)
Detail: goals/G-171-bake-writes-land-untracked.md

124
goals/G-171-bake-writes-land-untracked.md

@ -0,0 +1,124 @@
# G-171 Routine builds never write tracked paths - explicit commands own VCS-visible changes
Status: proposed
Scope: src/make.tcl (bake/bakehouse/vfslibs - VFSPAYLOAD + PACKAGES phases, kit assembly, new explicit materialize/tidy commands); src/vfs/ (payload declarations, _targets staging generalization, README.md + AGENTS.md precedence spec); src/_bake (assembly staging); bin/packages (lib-tier consumption); .gitignore + .fossil-settings/ignore-glob (staging ignore coverage); src/tests/shell/testsuites/punkexe/ (kill-probe + precedence characterization)
Goal: routine build operations (bake/bakehouse/vfslibs and every phase they run) write only to VCS-ignored locations - declared payloads materialize into ignored staging and merge-time layering enacts drop-in-wins precedence identically on every machine - so an interrupted, buggy, or stale-tool bake cannot modify, delete, or shadow tracked files and git/fossil status stays truthful during and after any build; deliberate writes into tracked .vfs folders (materializing a fetched/built package as drop-in content, retiring superseded committed files) remain available only as explicit separately-invoked commands whose output is an ordinary reviewable VCS change, with help and docs steering to the declaration-based route by default.
Acceptance: from a clean tree, a full bake/bakehouse run - including runs killed at arbitrary mid-run points (kill-probe characterization) - leaves git status and fossil changes reporting nothing outside ignore-covered paths; the VFSPAYLOAD/PACKAGES phases self-check their write destinations and abort before writing any tracked path; a hand-dropped file shadowing a declared payload entry survives assembly with drop-in-wins precedence on a records-free fresh clone (characterized, with the unified regime including _targets documented in src/vfs/README.md); the explicit materialize/tidy command(s) exist and are documented as the sole sanctioned tracked-tree write path, and no bake/bakehouse phase invokes them; a bake -hold run stops after assembly leaving the resolved per-kit images inspectable in staging, and a subsequent plain bake completes to kits identical to a single uninterrupted bake - staged assembly is reused only under digest-confirmed input currency, and stale or hand-modified held state is redone, never shipped.
## Context
The kit merge already runs entirely in ignored staging (src/_bake). The only step
writing tracked paths is payload materialization: G-115's declarations (achieved
2026-07-31 - see goals/archive/G-115-declarative-vfs-composition.md) automate filling
the same .vfs folders that were previously hand-assembled, so machine writes land in
tracked space as an evolutionary artifact, not an architectural necessity.
Three structural problems follow. (1) Drop-in-wins is enacted in place via punkcheck
records that are machine-local and VCS-ignored, so the authored-vs-installed
distinction does not travel between machines - replace=true exists to wipe rather
than reason, which is exactly the operation that strands trees when a bake dies.
(2) Two precedence regimes coexist: in-folder materialization preserves drop-ins,
while _targets staging (G-127, achieved - see
goals/archive/G-127-crosstarget-vfs-bake.md) merges OVER the per-kit .vfs.
(3) Any bake failure mid-materialization leaves tracked files modified/deleted -
uninterpretable for a non-developer, and the reason three separate mid-bake-status
traps are recorded in project memory.
Incident evidence 2026-08-06: on a consumer-shaped machine (reset --hard + pull +
fetch + bake), a stale untracked bin/punkzip.exe (pre-2.4.0) received the v2.4.0
-b flag, wrote a misdirected 90MB archive to src/-b, the kit-container step failed,
and the died bake stranded half-replaced tracked trees across the declared kits -
a wall of git modifications/deletions with no user-facing recovery story. Under
this goal that whole class strands only ignored staging: recovery = rerun.
## Approach
1. Generalize the G-127 staging pattern: ALL declared payload entries (not just
%platform% forms) materialize into ignored staging; the tracked .vfs folder is
never a materialization target of any routine phase.
2. Unify precedence at merge time: staging merged first, authored .vfs merged over
it (drop-in wins), supersedes/replace expressed as merge-time masks; record the
deliberate flip of the current _targets-over-.vfs order; document in
src/vfs/README.md; characterize.
3. Explicit commands own tracked-tree writes: a tidy command retiring superseded
committed files (report-then-act), and a materialize command that deliberately
lands a fetched/built package into a .vfs folder as drop-in content for the
developer/builder persona (user direction 2026-08-06) - both producing ordinary
reviewable VCS changes, with help text steering to declarations by default.
4. Defense in depth: the phases enumerate write destinations and abort before
touching any tracked path.
5. Kill-probe characterization: clean tree in, clean tree out, at arbitrary kill
points.
6. Optional interim hardening (independent value if migration is staged):
temp-sibling + atomic-swap for the current in-folder materialization, removing
the stranded-mid-replace mode before the full move lands.
7. Hold point: 'bake -hold' stops after assembly (post payload-staging + merge +
per-target selection, pre container/deploy) with the resolved per-kit images
in staging for inspection; a subsequent plain bake completes. Deliberate holds
and interrupted bakes unify: any completing run re-verifies staged assembly
against per-kit input digests (the G-162 machinery, write-side) and reuses
only what is confirmed current. Held staging is machine-owned - inspection is
sanctioned, hand-edits are not, and a digest mismatch means redo, not ship.
bakelist surfaces held state alongside its freshness verdicts. The
project-version gate applies to both invocations.
8. DOX revision: src/vfs/AGENTS.md + README.md - the authored .vfs remains the
drop-in surface; the resolved view is src/_bake (optionally a resolved-view
report); revise the "operative assembly area" language accordingly.
9. Coordinate with G-162: digest inputs become authored .vfs + staging (or
declarations + tier); the digest infrastructure serves both bakelist's
read-side verdicts and hold/resume's reuse decision (Approach 7); record the
decision in both files.
## Alternatives considered
- Generalized per-kit ignore lines (punkdeclare pattern for every kit) - workable
interim, rejected as endpoint: machine writes still land inside tracked folders,
ignore bookkeeping grows per kit, authored-vs-machine mixing persists, and
supersedes still mutates tracked files from inside bake.
- Hardening only (step 6 atomic swap) - rejected as endpoint: shrinks the window
but any bake bug can still mutate tracked files; the class survives.
- Requiring committed payload removal first - rejected as sequencing: that is
G-004's own arc (artifact coverage per package); this goal works with committed
payloads still present and decouples their eventual removal from bake behaviour.
## Notes
- Related: G-004 - parent hygiene arc; write-side complement: bake stops being the
maintainer of committed payload copies, so G-004's per-package removals decouple
from bake behaviour. No dependency on G-004's completion.
- Related: G-157 - sibling commit-policy goal; shares the working-modes-stay-
first-class posture (uncommitted drop-ins and derived-project permissiveness
remain untouched).
- Related: G-162 - input-freshness digests consume payload trees; the staging move
changes the digest input set, and the per-kit digest machinery is shared with
the hold/resume seam (Approach 7, 9).
- Related: G-065 - declarative vendoring is the source-side sibling surface; its
sync command is the same explicit-command pattern, and its audit's
undeclared-drop-in reporting complements an authored-only .vfs.
- Related: G-141 - consumption-driven libfetch selection reads the same
*.vfs.toml declarations; unaffected by the write-location move.
- Related: G-147 - fetch-side sibling from the same 2026-08-06 evidence
(content-keyed tier tree currency).
- Related: G-006 - consent posture untouched: this goal moves write locations
only; every network-consent gate stays as-is.
- Related (archived): G-115 (achieved 2026-07-31 - see
goals/archive/G-115-declarative-vfs-composition.md) - the declarative surface
consumed here; this goal deliberately revises its "folder remains the operative
assembly area" stance: the authored folder stays the drop-in surface,
machine-written content leaves it.
- Related (archived): G-127 (achieved - see
goals/archive/G-127-crosstarget-vfs-bake.md) - the ignored-staging + merge
mechanism generalized here, and the origin of the second precedence regime this
goal unifies.
- Related (archived): G-155 (achieved 2026-08-02, archived) - the _bake/_mint
stage-workdir vocabulary this staging extends.
- Tool-level fixes from the 2026-08-06 incident (punk::zip accelerator version
handshake before emitting v2.4.0-only flags; punkzip strict rejection of unknown
dash-flags) harden the trigger and are deliberately outside this contract - this
goal removes the blast radius, not the trigger.
- Overlap survey 2026-08-06 (goals_xref paths over src/vfs, src/make.tcl,
src/_bake, bin/packages): related in substance - G-004, G-141, G-065, G-162,
plus policy/evidence siblings G-157, G-147, G-006 added conceptually; surveyed
and judged not related in substance: G-089, G-114, G-131 (boot/_config surface),
G-019 (payload content trimming), G-020 (Scope names a lib_tcl9 path only),
G-116 (tcltls payload constituent - its removal stays G-004-era work).
Loading…
Cancel
Save