chore: bound target/ growth — incremental off, line-tables debug

target/ had reached 38 GB, dominated by a 16 GB incremental cache
(~28 compilation units × every historical config, never evicted) and
~25 separate integration-test binaries each statically embedding the
bundled engine + full debug info.

[profile.dev] (inherited by the test profile):
- incremental = false: the cache earns little in a full-suite workflow
  and never self-evicts; off, target/ stays bounded.
- debug = "line-tables-only": keeps file:line in panics/backtraces (we
  debug via tracing logs) at a fraction of debug=2's size.

Net: a clean full build dropped from 38 GB to ~1.6 GB. Document the
rationale plus the cargo-sweep workflow (the GC cargo lacks) under a
new CLAUDE.md "Build hygiene" section; also drop the now-shipped H1
from CLAUDE's deferred list (H1a remains).
This commit is contained in:
claude@clouddev1
2026-06-02 20:07:54 +00:00
parent be7b078878
commit 42f95533ac
2 changed files with 72 additions and 3 deletions
+57 -3
View File
@@ -187,6 +187,60 @@ Key invariants in the code:
`git commit` is preceded by an explicit message proposal `git commit` is preceded by an explicit message proposal
and user approval. No AI attribution in commit messages. 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
~8590 % 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 ## Things deliberately deferred
These are explicitly tracked (mostly in `requirements.md`) but 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 - **m:n convenience** (C4): auto-generates a junction table
with appropriate FKs — depends on relationships being solid with appropriate FKs — depends on relationships being solid
(they are). (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 - **Strong syntax-help in parse errors** (H1a): point users at
missing keywords/clauses rather than the unexpected 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 - **Tutorial/lesson system**: acknowledged as in scope for
design; needs its own ADR. design; needs its own ADR.
- **Session log + Markdown export** (V4): the bigger UX - **Session log + Markdown export** (V4): the bigger UX
+15
View File
@@ -45,6 +45,21 @@ insta = { version = "1.47.2", features = ["yaml"] }
pretty_assertions = "1.4.1" pretty_assertions = "1.4.1"
tempfile = "3.27.0" 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] [lints.rust]
unsafe_code = "forbid" unsafe_code = "forbid"
unreachable_pub = "warn" unreachable_pub = "warn"