feat(config): modes - a mode is an artifact kind, the lenses it runs and its effort

The config defines the modes (modes.<name>): the kind of artifact the mode
reviews - reply, series or commits, the three shipped partitions; a kind
is a mode of its own name - the lenses it runs, in its kind's gate order,
and the effort it runs at, else the kind's default (max for a reply or a
series, xhigh for a commit range). `run --mode` names any of them, the
dump records mode and kind, and everything that decided by the mode's
name - the partition and hash, the prompts, the schemas, the disposition
and reuse-key rules, what the CLI requires - decides by the kind.

Every lens stays off until a mode lists it; lenses.<name>.run is retired
with a warning that says so, and a lens of another kind, a name that is
no lens, a lens listed twice and an unknown effort are config problems.
The defaults run no lens; the template ships the three kinds as modes
with every lens of their kind at the kind's effort, to trim (the owner's
ruling of 2026-11-01), and init says so as it writes it - a kept config
is the repository's own, and only one that lists no lens gets a step.

The readers of the retired key follow: the CI smoke config, the shipped
skill, the procedure (its description of the config as well as its
mechanics), the manifest template, the run's messages and the comments
that named the three modes. The run lock, the run numbers and the dump
names are the kind's, so one full run per hash holds across the modes
of a kind and their rounds count on together; the dump says which mode
ran. The database broker starts for a lens the mode runs, as every other
reader of the lenses off reads them. A named mode runs through the CLI
in the kernel-modes test.
This commit is contained in:
Jorijn van der Graaf 2026-11-01 01:31:40 +01:00
commit d5e54ffeb3
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
25 changed files with 1277 additions and 711 deletions

View file

@ -12,7 +12,7 @@ This file is for changing crafter-review itself. `README.md` says what it is and
- Processes run on the seats of the consumer's `.env` (`:SeatPool`). A lens's processes get the environment the config names: `none`; `browser`, a Playwright MCP server per pass (`:Mcp`, `:Pool`); `supabase`, the local stack's database through the `sql` helper (`:PgWire`); or `browser+supabase`.
- A browser pass holds a stack of its own (`Pool::Stacks`), and a pass launches only when it fits in free memory at its environment's measured cost (`Pool::Admission`, `:Memory`).
- Drivers on one machine share one board, `~/.cache/review-gates/seat-board.json` (`SeatPool::Board`). `State::RunLock` allows one full run per hash.
- The kernel modes (2026-10-31): `--mode series` and `--mode reply` run the pre-send pipeline of a kernel contributor's workbench with the same machinery. Their own pieces: the inventory of a cover letter, a mail draft and the camera review's shape (`:Inventory` PartitionReply, PartitionMail), the ten kernel lenses with their gates (`Plan::Lenses` rows with `kernel`, `Plan::Gates(mode)`), text units keyed on what they cite and the anchor (`Plan::TextDeps`) and a series' code units on the code like the push gates, the persona gate - one `maintainer-persona` instance per `--reviewers` entry, its whole pass pruning the not-mine units - with the persona vocabulary in `:Schema`, `:Normalize` and the matrix, the references prefetched through `utilities/lore.py` and the persona corpora (`:Refs`), the kernel texts in `:Prompt`, the `GATES CLEAN` verdict, `personaPass` in unit-state, and the subsystem's journal in the run layer and the dispositions block. Their prompts, keys and plans were checked byte for byte against the pipeline they replace, on its own artifacts.
- The kernel modes (2026-10-31): `--mode series` and `--mode reply` run the pre-send pipeline of a kernel contributor's workbench with the same machinery. Their own pieces: the inventory of a cover letter, a mail draft and the camera review's shape (`:Inventory` PartitionReply, PartitionMail), the ten kernel lenses with their gates (`Plan::Lenses` rows with `kernel`, `Plan::Gates(kind)`), text units keyed on what they cite and the anchor (`Plan::TextDeps`) and a series' code units on the code like the push gates, the persona gate - one `maintainer-persona` instance per `--reviewers` entry, its whole pass pruning the not-mine units - with the persona vocabulary in `:Schema`, `:Normalize` and the matrix, the references prefetched through `utilities/lore.py` and the persona corpora (`:Refs`), the kernel texts in `:Prompt`, the `GATES CLEAN` verdict, `personaPass` in unit-state, and the subsystem's journal in the run layer and the dispositions block. Their prompts, keys and plans were checked byte for byte against the pipeline they replace, on its own artifacts.
## The rule it lives by
@ -100,7 +100,7 @@ Conventions:
- **The dump's `driver` field and the first log line** read `crafter-review <version> (prompt v1)`. Nothing reads them.
- **`freeze.json` records `gitVersion`.** When the hashes differ, `freeze --verify`'s MISMATCH names a git version change as the likely cause (Freeze).
- **A repository's own lens sections** (`lenses.<name>.section` in the config, `Config::LensSectionsOf`, `SectionProblems`): `Prompt::Charter` appends the file the config names for the lens to the shipped charter after one blank line, so `charterSha` and every reuse key cover it; the path is relative and inside the repository (the check `slots.dir` shares: an absolute path or a `..` part is a config problem, and `LensSectionsOf` resolves no other), a file missing or one the run could not use (`Prompt::ReadSection`, the reader `Charter` uses too: a dangling link, no regular file, unreadable, not UTF-8) is a config problem (the run refuses), a name that is no lens is Merge's unknown key, and the run logs which charters got one. Nothing lists a directory (2026-11-01, Jorijn: a path per lens, where a listed directory had to tolerate or refuse every foreign entry) (Config, CommitsMode, KernelModes).
- **A reply's gate-state is beside the draft**, a directory artifact's inside it; the run lock, the dumps and the resume file are named by the mode (`reply-<h8>-run-N.json`). A kernel mode requires `--subsystem`; commits refuses `--reviewers`; `--reads` is 1 for a reply. The kernel modes check no tree (the lenses read several), excuse no unit from the holes, and their `lensesOff` and `environments` in the dump list the mode's lenses alone (KernelModes).
- **A reply's gate-state is beside the draft**, a directory artifact's inside it; the run lock and the dumps are named by the kind (`reply-<h8>-run-N.json`), the resume file by the hash alone (`resume-<h8>.json`); a mode of another name shares them all, and the dump's `mode` says which ran. A kernel mode requires `--subsystem`; commits refuses `--reviewers`; `--reads` is 1 for a reply. The kernel modes check no tree (the lenses read several), excuse no unit from the holes, and their `lensesOff` and `environments` in the dump list the kind's lenses alone (`Plan::KindLenses`; `lensesOff` those of them the mode does not list) (KernelModes).
- **The repository under review is the freeze record's**, not the working directory's: `Run::reviewed` is named in the prompt and keys the calibration, and `--trees` defaults to the record's worktree, else its repository when that is not the working directory, else `.` (`Freeze::ReviewedBy`, `TreeOf`). The working directory stays `Run::repo`: the config, `.env`, the slots, the lens processes' cwd and every logged path. That is how a workbench reviews other repositories with `freeze --repo` (Freeze, Runs).
- **`config` reports an absolute `functional.mcp.command` that is no program here**, such as `/usr/bin/npx` inside the Flatpak, whose `/usr` is the Sdk's. `config` then exits 1, and a run stops at preflight (Config).
- **JSON edge cases.**
@ -138,7 +138,7 @@ Conventions:
- In the Flatpak, a pass's `SHELL` is `/bin/bash` (Platform).
- **Commands beyond the gates**: `init`, `doc`, `browser install`, `stop`, and `--version`, which prints the home and the charters' sha256s (Commands).
- **Order, not value:** `estimate.cacheWrite`'s last digit depends on the order the passes ran, because it is a float sum.
- **Every lens is off until the consumer's config turns it on** (2026-10-31, Jorijn: "all lenses off by default and opt in only"). `Config::Defaults()` gives every row `run: false`; a config that turns on none - no `lenses` key included - has the one problem that names the lenses, so `config`, `freeze` and `run` all say so, the template ships every lens off, and `init` tells the consumer to turn lenses on (Config, Commands, ReviewFixes, the Goldens' config cases). A consumer config without a `lenses` key needs one.
- **A mode is an artifact kind plus the lenses it runs and its effort** (2026-11-01: `modes.<name>` in the config, `Config::ModeOf`, `ModeNames`, `LensesOff(config, mode)`). The three kinds (`Plan::Kinds`: reply, series, commits) are modes of their own name; a mode of another name states its `kind`. The kind decides the partition and hash, the common text and run layer, the schemas, the disposition and reuse-key rules and what the CLI requires (`Run::Arguments::kind`, `Plan::IsKernelKind`); the mode decides which of the kind's lenses run (`Plan::KindLenses`, in the kind's gate order, `Plan::Gates`) and the effort (`modes.<name>.effort`, else the kind's default). Every lens is off until a mode lists it (2026-10-31, Jorijn: "all lenses off by default and opt in only"): `Config::Defaults()` runs no lens, while the template lists every lens of each kind at the kind's effort, to trim (Jorijn, 2026-11-01, on the populated template as the example: "looks good"; `init` says to trim); `lenses.<name>.run` is retired with a warning that says so; a lens of another kind, a name that is no lens, a lens listed twice and an unknown effort are config problems; `--mode` names any configured mode, the dump records `mode` and `kind`, and a reuse key carries no mode name, so a clean read bought in one mode counts in another of the same kind. The run lock, the run numbers and the dump names are the kind's (`<kind>-<h8>-run-N.json`): one full run per hash across the modes of a kind, their rounds counting on together; the dump's `mode` says which ran (Config, CommitsMode, KernelModes).
- **The commit-truth lens** (`repo-facts.md`, 2026-10-31): Gate 4, after the proofs, so the messages and documents are read once the code they describe has settled. Its block kinds are text, doc and slot: the message units keyed on their text, the base and the code up to their commit (`MessageDeps`); a documentation unit on its file, its normalised text, the base and the code of the whole range (`DocKeyParts`); a diffstat on its text alone; `whole:order` and `whole:absent` in slot passes of its own (a lens with no whole pass asks the slots named in its row; never stored). A documentation file's diff header and a part the commit writes nothing in are mechanical n/a. Budgets 60/40 for a text or doc block, 50/35 for a slot; one read. The owner's gate is 5. The other lenses' prompts, keys and plans are untouched (CommitsMode, CodeKeys, Runs, the Goldens' series and gates).
**Known quirks, kept:**