From aca3edff41e33d3a4c245caed6d9ea1f32f6064a Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Fri, 25 Sep 2026 10:32:05 +0700 Subject: [PATCH] CLAUDE.md keeps only the rules the code cannot teach --- CLAUDE.md | 143 ++++++++++++++---------------------------------------- 1 file changed, 36 insertions(+), 107 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 3a08fcc2..2383974f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,125 +1,54 @@ # Working in this repository -For any agent working here, including a lane in its own worktree. These are -standing rules, not preferences. Where a rule has a reason, the reason is given -once — the rules without one are the ones that have already cost something. +Standing rules for any agent here, including a lane in its own worktree. ## Never -- **Never touch anything under `/home/joe/Development/fnm/`.** That is the - author's own working copy of the falling-sand game, open in an editor with a - live session attached. `fnm/flan/sand.flan` is not the same file as this - repository's `sand.flan` and is never to be read-and-written-back, moved or - edited. The copy in this repository is ordinary tracked source and may be - edited like any other file. -- **Never execute `examples/*.flan`, `sand.flan`, or anything that links - raylib.** They open a window on the author's desktop, which strobes it. - Compile them, emit them, diff them — never run them. -- **Never run `dune clean`.** It walks up out of a worktree and deletes the main - checkout's `_build`, which takes the author's `flan` binary with it. This has - happened. Run `dune` with `--root .` from inside your own worktree. -- **Never kill a `flan dev` daemon you did not start.** The author keeps a live - one attached to their editor all day. Orphans from finished lanes are fair - game; anything whose cwd is under `fnm/` is not. -- **Never put a `Co-Authored-By`, a `Claude-Session` trailer, or any other - watermark in a commit message.** +- **Touch anything under `/home/joe/Development/fnm/`.** The author's live + working copy, with an editor session attached. This repository's `sand.flan` + is a different file and may be edited normally. +- **Execute `examples/*.flan`, `sand.flan`, or anything linking raylib.** They + open a window that strobes the author's desktop. Compile, emit, diff — never run. +- **Run `dune clean`.** It escapes a worktree and deletes the main checkout's + `_build`. Run `dune` with `--root .` from inside your own worktree. +- **Kill a `flan dev` daemon you did not start.** The author keeps one attached + to their editor. +- **Put `Co-Authored-By`, a `Claude-Session` trailer or any watermark in a commit.** -## Commits and branches +## Commits -`master` is the trunk and tracks `origin/master`. Lanes work in their own git -worktree off it and do not merge or push — merges are resolved by the session -that dispatched the lane. - -A commit message is a single declarative sentence in the repository's voice, -saying what is now true rather than what was done: "A thunk named for the order -it was minted in is a different signature after a reorder", not "fix thunk -naming bug". A body is for the reasoning, when there is any. +`master` is the trunk. Lanes work in their own worktree and never merge or push; +the dispatching session merges. A commit message is one declarative sentence +saying what is now true, not what was done. ## Tests -`dune test --root .` is the suite and takes seconds. Run it constantly; it must -be green before a lane reports. - -`dune build @checks` is `@page`, `@x86` and `@cells` — the reference page's -examples still compile and print what the page says, the hand-written x86 -backend still agrees with LLVM, and a `--dev` build still calls through its -indirection cells. `@sanitize` and `@valgrind` run the corpus under ASan/UBSan -and memcheck and take tens of minutes. - -Those three stay out of a lane's own run. They are swept in a batch after -several lanes have merged, and the fixes are batched with them. Keeping the -default run fast is deliberate: a suite that takes tens of minutes is a suite -nobody runs. - -Note that ASan does not see a stack-lifetime bug — uninitialised stack reads -need `@valgrind`. +`dune test --root .` must be green before a lane reports; grep its output for +FAIL, since the exit code alone has lied. `@checks` (`@page`, `@x86`, `@cells`), +`@sanitize` and `@valgrind` are slow and run once between batches of lanes, with +the author's permission, never inside a lane. ASan misses uninitialised stack +reads; `@valgrind` catches them. ## Evidence -Read the source, do not recall it. `docs/REFERENCES.md` lists the reference -clones on this machine — Odin, SBCL, Zig, Carp, clojure-mode, CIDER, raylib and -the rest — and what each one answers. A claim in these notes that came from one -of them was read out of the clone; the ones that were recalled instead have been -wrong before. +Read the source, do not recall it — this repository and the reference clones +listed in `docs/REFERENCES.md`. Verify a brief's facts before building on them. -The same applies to this repository. Cite a file and a line because you opened -it. When a brief hands you a list of facts, verify them before building on them -— a brief written from a stale tree has sent a lane a full day in the wrong -direction. +## Records -## Diagnostics +Keep only what the code cannot say. -Elm's shape: the source line, a caret, what the compiler understood, and the fix -named. Beyond that: +- `TODO.org` — one `**` heading per item under a subsystem: `TODO` a gap, `NEXT` + decided and queued, `WAIT` blocked (say on what), `CANCELLED` rejected with a + one-line reason so it is not re-proposed, `DONE` only when the decision is not + obvious from the code (two lines, what it rules out). On a merge conflict keep + both sides. +- The reason for non-obvious code goes in a comment beside it. +- `docs/BUILT.md` holds only reasoning that spans several files. +- No handoff files. -- A message is written for someone who has never used Flan and does not know its - history. Never "X is now Y", never "X was renamed", never our rationale. If - `defvar` no longer exists, the message says `defvar` does not exist — not that - it became something else. -- The clauses come in one order: what the compiler understood, then what - conflicts with it, then the fix — "expected i32, found string". -- Every suggestion a message prints must compile. -- An assertion about the compiler's own invariants is prefixed `internal:` and - says it is a compiler bug. A user never caused one. +## Reviews -## Writing - -User-facing prose — the README, `web/index.html`, the Emacs manual — is plain. -Odin's website is the reference: declarative rather than second-person, the -concept defined before the mechanics, the code example after the prose that -frames it, and rationale given its own subsection rather than mixed in. - -No aphorisms, no closing lines built for effect, no rhetorical inversions. If a -sentence's only content is its own style, cut it. This applies to reports and -commit messages as much as to documentation. - -## The records - -- `TODO.org` — every decision, question and known gap, one `**` heading each - under a subsystem heading, with an org keyword saying where it stands: `TODO` - for a gap, `NEXT` for what is queued, `WAIT` for what is blocked and on what, - `DONE` for what was settled, `CANCELLED` for an idea considered and rejected. - A lane records its decision here, as a few lines saying what was decided and - what it rules out — never the argument and never the measurements. On a merge - conflict in this file, keep both sides: two lanes recording two decisions is - not a conflict. -- `docs/BUILT.md` — why the parts that exist are shaped the way they are. The - largest and most load-bearing document here. Reasoning that will not fit in a - few lines goes here, and `TODO.org` carries one line pointing at it. -- `docs/handoffs/` — one report per finished work session. -- `docs/README.md` indexes all of it. - -A `CANCELLED` entry is not housekeeping. An idea rejected without a record is an -idea that gets re-proposed, so the one-line reason is the whole value of it. - -## The shape of the work - -The author dogfoods the language in a separate project, hits friction, and -reports it. Work is dispatched as parallel lanes in isolated worktrees; every -lane is reviewed by an independent agent before it merges; the dispatching -session resolves the merges. - -A review is adversarial. Verify by building and running rather than by reading, -measure both sides of a claimed fix, and say what you actually measured. A lane -that reports a number you did not reproduce is a lane with a number you should -reproduce. +Every lane gets an independent adversarial review before it merges: build and +run rather than read, measure both sides of a claimed fix, and reproduce any +number a lane reports.