CLAUDE.md keeps only the rules the code cannot teach
This commit is contained in:
parent
3a2837c278
commit
aca3edff41
143
CLAUDE.md
143
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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user