node_modules/
dist/
.vite/
*.tsbuildinfo
.DS_Store
# The deploy build at the ROOT only. This read `public/` unanchored until 2026-09-03, which also
# ignored line/scaffold/app/public/media/stub-frame-*.svg — two files port-scaffold.mjs and
# scaffold/MANIFEST.json name — so every fresh clone had an incomplete scaffold and a tree id
# (line-version.mjs hashes scaffold/) that no clone could reproduce. Templates keep their own rule
# below: their public/media/ ladders are generated from media-src/ and stay out.
/public/
templates/*/public/
templates/*/variants/*/public/
.firebase/

# scratch probes, never deliverables
.probe*.mjs
.shots-tmp.mjs
kotest.mjs

# Scratch that got COMMITTED because the rule above only matched one filename shape.
# Removed 2026-09-03: .tmp-probe/ (211 MB of capture-bisect PNGs, referenced by nothing — its
# findings live in capture.mjs's named passes), .ullage-start.mjs, 28 loose captures at the repo
# root, and private/tmp/claude-501/... — an agent scratchpad path materialised inside the repo.
# Widened from names to SHAPES, because the next scratch file will not be called probe.mjs.
.tmp-*/
private/
tmp/

# Fixtures the selftests write for themselves. Regenerated on every run; never source.
source-corpus/.selftest/

# What a gate paints on every run is output, not a record. verify-deploy.mjs rewrites every frame
# here each time it runs (67 PNGs churned in every commit until 2026-09-04); the README stays so
# the path the deploy brief names resolves in a fresh clone.
episodes/_deploy-check/*.png
# the verified-deploy record (verify-deploy --commit-state): what THIS machine's public/ held when it
# was last verified AND uploaded — machine state, not history; another clone starts with a full sweep
episodes/_deploy-check/verified*.json

# Model calls made with no episode open land in <tree>/prompts/gemini-log/<date>.jsonl — a day file
# appended to by every hand run, 22 MB inside the instructions folders by 2026-09-04. The ones from
# before that date are filed under episodes/_unfiled-transcripts/ (they are the only transcripts of
# episodes 001-003); new ones stay out. The README is tracked so the directory survives a clone.
**/prompts/gemini-log/*
!**/prompts/gemini-log/README.md

# The flat index build-methods.mjs writes by hand into docs/methods/ — an index of renderings, not
# a document. docs/defects.html stays tracked: check-tool-paths.mjs requires every path a shipped
# tool builds to exist, and build-defect-report.mjs builds that one. docs/archive/ is tracked.
docs/methods/
firebase-debug.log

# Repo leases are live, machine-local runtime state: which episode currently holds chromium,
# next-line, deploy, graph or queue. They are created and removed as steps run, they name a pid
# and a host, and they mean nothing in another checkout. Committing one would put a stale claim
# into somebody else's tree, where repo-lease would read it as a real holder — the opposite of
# what the file is for. Untracked until now, which is how episodes/_leases/queue.json turned up
# in `git status` mid-run on 2026-09-19 with 021's live claim in it.
/episodes/_leases/

# The per-episode browser lease is live runtime state, exactly like episodes/_leases/ above:
# browser-lease.mjs writes it while a step drives Chromium and removes it when the step ends. It
# names a pid and a host and means nothing in another checkout. episodes/014/BROWSER-LEASE.json
# was committed once and removed in a later commit, so this is a proven hazard rather than a
# theoretical one — and 021's live lease was sitting untracked in the shared tree when this was
# written, where either operator could have swept it into a commit.
episodes/*/BROWSER-LEASE.json
.codex-stop

# The line's packets (next-line/tools/package-template.mjs, step 12 package): React source + a clean-room dist/
# per unit, their ZIPs and the gate's screenshots. Output, rebuilt from templates/ — never committed. The
# episode keeps its own record (episodes/<e>/package/PACKAGED.json), which is.
/exports/
