diff --git a/CLAUDE.md b/CLAUDE.md index c5629db..33aa4f1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -187,6 +187,60 @@ Key invariants in the code: `git commit` is preceded by an explicit message proposal and user approval. No AI attribution in commit messages. +## Build hygiene + +`target/` is git-ignored and 100% regenerable, but it grows +without bound — cargo never garbage-collects old hash-suffixed +artifacts, so stale test binaries (each ~100 MB, statically +linking the bundled engine + debug info), incremental-compile +caches, and orphaned example binaries pile up across sessions +(it reached **~38 GB** before the first sweep). + +Two prevention levers are configured in `Cargo.toml` `[profile.dev]` +(the `test` profile inherits both): + +- **`incremental = false`** — the incremental cache alone reached + **16 GB** here (≈28 compilation units × every historical config, + never evicted), for little benefit in a full-`cargo test` workflow. + Off, it never regrows; the cost is whole-crate recompiles instead of + partial — seconds for a crate this size. +- **`debug = "line-tables-only"`** — the default `debug = 2` is + ~85–90 % of each test binary; line tables keep file:line in panics + and backtraces (we debug via `tracing` logs) at a fraction of the + size. + +Even with those, stale artifacts still accumulate (cargo has no +target/ eviction). **Run `cargo sweep` every now and then** to reclaim +that — `cargo-sweep` (installed) prunes everything *except* the current +build's artifacts: + +- **Keep only the current build (the usual sweep):** stamp, + build, then delete everything the build didn't touch — + ``` + cargo sweep --stamp + cargo build --all-targets # touch the artifacts to keep + cargo sweep --file # remove everything older than the stamp + ``` + Add `--dry-run` to `--file` first to preview what goes. Caveat: + `build --all-targets` only updates the mtime of what it + actually (re)builds, so already-fresh *dependency* artifacts + fall before the stamp and get swept too — they recompile once + on the next build (a one-time cost; everything is regenerable). + The first 38 GB → 20 GB sweep freed **19 GiB** this way. +- **Lighter routine options:** `cargo sweep --time 30` drops + artifacts untouched for 30+ days; `cargo sweep --maxsize 10GB` + trims oldest until under a size cap. +- **`--installed` is *not* the tool for same-toolchain cruft.** + It keeps only artifacts from currently-installed rustup + toolchains, so it frees space *only after you uninstall/replace + a toolchain*. For the usual "many builds, one toolchain" + accumulation it cleans **nothing** (verified: it would free 0 + here) — use the stamp/file workflow instead. + +A good cadence is a sweep between major milestones (e.g. at +session handoff). `cargo clean` remains the nuclear option (wipes +all of `target/`, forcing a full from-scratch rebuild). + ## Things deliberately deferred These are explicitly tracked (mostly in `requirements.md`) but @@ -202,11 +256,11 @@ not yet implemented: - **m:n convenience** (C4): auto-generates a junction table with appropriate FKs — depends on relationships being solid (they are). -- **Friendly error layer** (H1): partial — FK errors are - enriched both ways; full SQL→English translation pending. - **Strong syntax-help in parse errors** (H1a): point users at missing keywords/clauses rather than the unexpected - character. + character. *(H1 — the friendly **database**-error layer — is + done, ADR-0019; H1a is its separate parse-error sibling, + ADR-0021, still partial.)* - **Tutorial/lesson system**: acknowledged as in scope for design; needs its own ADR. - **Session log + Markdown export** (V4): the bigger UX diff --git a/Cargo.toml b/Cargo.toml index a42d918..b11af84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,21 @@ insta = { version = "1.47.2", features = ["yaml"] } pretty_assertions = "1.4.1" tempfile = "3.27.0" +# Dev/test build hygiene (see CLAUDE.md "Build hygiene"). `cargo test` +# links ~25 separate integration-test binaries, each statically +# embedding the bundled engine + every dependency; the `test` profile +# inherits these from `dev`. +# - incremental = false: the incremental cache reached 16 GB here for +# little benefit in a full-suite workflow; disabling it keeps target/ +# bounded. +# - debug = "line-tables-only": full debug info (the default `debug = 2`) +# is ~85-90% of each test binary; line tables keep file:line in panics +# and backtraces (we debug via `tracing` logs, not a step-debugger) at +# a fraction of the size. +[profile.dev] +incremental = false +debug = "line-tables-only" + [lints.rust] unsafe_code = "forbid" unreachable_pub = "warn"