Hard-won rules for working on this tree. Design notes are in notes/design/ and claude-notes/.
- Never build Lean on a small or shared desktop. One
leancan take several GB; parallel builds tens of GB. Agents runninglake/leanlocally once OOM-killed every session on the host. - Wait on long jobs by blocking, not polling. Run the job as one blocking command in the
background so its exit is the notification. Never
setsid nohup+until … sleeploops: they waste time and hide jobs that never started. Check a job actually launched before waiting on it. - Keep runs short. Stage lemmas ≤ ~5 s, instruction rules ≤ ~3 s,
timeouton every run; profile (set_option profiler true) before adding facts. Slow patterns: whole-goalsimpper symbolic step, unrolled loops, longswp_runs, symbolic decoding (use the evaluation bridge). - Large literals run away. A proof-mode hypothesis
[∗map]over a concrete 33k-entry map blew past 28 GB. State such resources as quantifiers (∀ k v, get? m k = some v → …) behind lookup lemmas; nevershow/decidethrough the literal. Bound such compiles (timeout;ulimit -v≥ 40 GB, smaller caps abort Lean spuriously). - One
lakeper tree at a time. Concurrentlake env lean/lake buildin one tree race to rebuild shared dependencies; one looped printingTask.get … (sync := true)backtraces into a 729 GB log and filled the build disk. Build first, then run profiles/probes, and cap their output (| head -c).
- One kernel function per Spec/Proof/Link triple (
Xv6/Spec<F>,Proof<F>,Link<F>); alternate contracts of one function may share. Shared helpers go in a*Defs.lean. Coverage relies on it. - Design authority:
claude-notes/(readLEAN.mdfirst) andnotes/design-rulings.md. The Rocq tree is archived on therocqbranch; it is a reference, not tracked. - Kernel/user images: regenerate only from the matching ELF (pins in the generated headers;
make check-gen). Derive data addresses from the image, never from another build's ELF.
- Full
lake build Xv6 MachCSL,tools/ci/lint.shand nosorrybefore every push (module builds miss cross-file name clashes). Push each green commit toorigin lean. - A change that moves axioms/opaques, the TCB module set, coverage or generated files must update the
baseline in the same commit:
tools/audit/baseline.json,tools/tcb/expected.json(tools/ci/tcb.sh --update),tools/ci/coverage_*.txt, the generators. Docs-only pushes:[skip ci]. - CI (
lean-ci.yml) runs on the sharedcoqdevrunner (24 cores); runs can queue behind Rocq jobs.
- Build VM:
/shared/xv6rocq/gcp-rocq/run-on-gcpmirrors$PWDto the VM and runs there (96 cores, 365 GB, shared with a collaborator: kill by PID, neverpkill -f). Run it from a worktree, never from/tmp(it syncs the whole directory);--sync-onlyafter writing new files; seed a new remote tree withcp -a /mnt/rocq/lean-seed/.lake .. Each synced tree keeps a full.lake(several GB) under/mnt/rocq/trees/: when a worktree is removed, delete its remote tree too (stale agent trees once held ~500 GB). - Agents: one private worktree each (
.claude/worktrees/lane-<L>); landing helper.claude/coord/land.sh(outside the repo)./shared/xv6iris-leanis a stale wrong-design attempt: ignore it. - Sail with the Lean backend: opam switch
lean-xv6; the model needs the short-circuit fix (README, "Regenerating the Sail model").