@sylad/cadence 1.36.0 → 1.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -193,12 +193,14 @@ usability (code only when the lot is not `visible`). Failing tests (reported red
193
193
 
194
194
  **A project without `orchestrate.test` is flagged (L327)**: without the key the wave never runs the suite itself — only the review does, if it decides to (it ran 12 test files of a project on 2026-10-25 and a red test reached « ready »). `cadence orchestrate --dry-run` writes one line per repository, under the first lot of that repository: `<repo> · porte de tests absente : orchestrate.test n'est pas déclaré, la vague ne lancera pas la suite (seule la revue le fera si elle le décide) · commande probable : npm test (à déclarer en orchestrate.test)`, and [`cadence lead tour`](lead.md#lead-tour) writes the same line for every project of the folder. The probable command is read from the repository, never run: `npm test` when `package.json` has a `scripts.test` (the `npm init` placeholder « no test specified » does not count), `pytest` when `pyproject.toml` names pytest, `mvn test` when there is a `pom.xml`; with none of them the line carries no command. A `cadence.yaml` that cannot be read gives no such line (it has its own error). Declaring `test:` (and `build:`) in the project's `cadence.yaml`, once the command is known to be green, removes the line.
195
195
 
196
- **Tests already red at the start (L213)**: a lot is no longer handed back « tests rouges » for failures that were there before it. When `orchestrate.test` fails (or the session reports red tests), the program reads the failing tests from the runner's output (vitest/jest `FAIL`/`●`, pytest `FAILED`, go `--- FAIL:`, TAP `not ok`), replays the same command at the sha the lot started from (the parent of the lot's oldest work commit, plan-only commits left out, else the `HEAD` before its first session) in a throwaway `git worktree` outside the repository, and compares: if every failing test was already red, it is not a defect of the lot — no correction pass, the code review takes place, the reviewer is told, and the final table lists them apart (`déjà rouge au départ (<sha>) : <test>`, 30 at most then a count). The worktree gets links to the repository's ignored folders at any depth, such as `.venv` and, in a monorepo, `packages/*/node_modules`, when their parent exists at that sha; build outputs such as `dist` or `coverage` are left out. Each `node_modules` is rebuilt entry by entry, every entry linked to the live one except the workspace links of npm, pnpm and yarn (`node_modules/@x/shared -> ../../packages/shared`, a link to code of the repository outside any `node_modules`), which are remade towards the worktree's own copy so that the start sha is tested against its own sources, not the lot's (a workspace package that does not exist at the start sha gets no link). Known limit: only `node_modules` links are remade; whatever points into the live repository by an absolute path, such as an editable Python install (`.venv` with a `.pth` file naming the live `src`, `pip install -e`) or an absolute symlink in another ignored folder, still runs the lot's code in the baseline. Likewise, a workspace package consumed through its build output (`main: dist/...`) cannot load in the baseline worktree: output dirs are not linked, so such a monorepo keeps the pre-L213 « tests rouges » outcome unless `orchestrate.build` is declared (the build is then played first in the baseline worktree, see below). A lot resumed in a later wave keeps the same baseline: the sha is the parent of its oldest work commit, not the `HEAD` of the new wave, so a failure the lot itself introduced in an earlier wave is never excused. A test red now and not at the start stays a blocking finding, and only that one is given to the correction (the others are counted as « already red »). When the output names no test, or the baseline cannot be run, the tests stay red as before (no comparison is guessed). A failure the output does not tie to a test (unhandled error, a spec file that fails to load such as jest « Test suite failed to run » or vitest `FAIL a.test.ts [ a.test.ts ]`, coverage threshold) keeps the tests red. Without `orchestrate.test` the program cannot replay anything: a session that reports green tests and lists under `echecsDeBase` the failures it saw at the start sha gets them listed apart, marked « non vérifié » in the table, and the review takes place; a session that reports the tests red stays red, the brief asking it not to report red for base failures alone — unless (L215) the report says so in a structured way: with `vert: false`, a non-empty `echecsDeBase` and an empty `nouveauxEchecs` (the list of tests red now that were not red at the start sha), `vert: false` is not a reason to correct, the lot carries a « non vérifié » warning, the reviewer is told that the baseline is unverified and the review takes place. A non-empty `nouveauxEchecs` with `vert: false` triggers a correction pass (the new failures are in the finding); an absent `nouveauxEchecs`, or an empty `echecsDeBase`, keeps the correction. With `orchestrate.test` declared (L361), the same structured report is honoured when the program's own gate is green (`orchestrate.test` exits 0): `vert: false` with a non-empty `echecsDeBase` and an empty `nouveauxEchecs` goes straight to the review, with a warning, without a correction pass and without the « tests rouges » escalation; without those two fields the claim of red tests still triggers the correction. The program never guesses from the text of the result (« 24 failed »). The `implement` and `fix` briefs ask for `echecsDeBase` and `nouveauxEchecs`.
196
+ **Tests already red at the start (L213)**: a lot is no longer handed back « tests rouges » for failures that were there before it. When `orchestrate.test` fails (or the session reports red tests), the program reads the failing tests from the runner's output (vitest/jest `FAIL`/`●`, pytest `FAILED`, go `--- FAIL:`, TAP `not ok`), replays the same command at the sha the lot started from (the parent of the lot's oldest work commit, plan-only commits left out, else the `HEAD` before its first session) in a throwaway `git worktree` outside the repository, and compares: if every failing test was already red, it is not a defect of the lot — no correction pass, the code review takes place, the reviewer is told, and the final table lists them apart (`déjà rouge au départ (<sha>) : <test>`, 30 at most then a count). The worktree gets links to the repository's ignored folders at any depth, such as `.venv` and, in a monorepo, `packages/*/node_modules`, when their parent exists at that sha; build outputs such as `dist` or `coverage` are left out. Each `node_modules` is rebuilt entry by entry, every entry linked to the live one except the workspace links of npm, pnpm and yarn (`node_modules/@x/shared -> ../../packages/shared`, a link to code of the repository outside any `node_modules`), which are remade towards the worktree's own copy so that the start sha is tested against its own sources, not the lot's (a workspace package that does not exist at the start sha gets no link). Known limit: only `node_modules` links are remade; whatever points into the live repository by an absolute path, such as an editable Python install (`.venv` with a `.pth` file naming the live `src`, `pip install -e`) or an absolute symlink in another ignored folder, still runs the lot's code in the baseline. Likewise, a workspace package consumed through its build output (`main: dist/...`) cannot load in the baseline worktree: output dirs are not linked, so such a monorepo keeps the pre-L213 « tests rouges » outcome unless `orchestrate.build` is declared (the build is then played first in the baseline worktree, see below). A lot resumed in a later wave keeps the same baseline: the sha is the parent of its oldest work commit, not the `HEAD` of the new wave, so a failure the lot itself introduced in an earlier wave is never excused. A test red now and not at the start stays a blocking finding, and only that one is given to the correction (the others are counted as « already red »). When the output names no test, or the baseline cannot be run, the tests stay red as before (no comparison is guessed). A failure the output does not tie to a test (unhandled error, a spec file that fails to load such as jest « Test suite failed to run » or vitest `FAIL a.test.ts [ a.test.ts ]`, coverage threshold) keeps the tests red. Without `orchestrate.test` the program cannot replay anything: a session that reports green tests and lists under `echecsDeBase` the failures it saw at the start sha gets them listed apart, marked « non vérifié » in the table, and the review takes place; a session that reports the tests red stays red, the brief asking it not to report red for base failures alone — unless (L215) the report says so in a structured way: with `vert: false`, a non-empty `echecsDeBase` and an empty `nouveauxEchecs` (the list of tests red now that were not red at the start sha), `vert: false` is not a reason to correct, the lot carries a « non vérifié » warning, the reviewer is told that the baseline is unverified and the review takes place. A non-empty `nouveauxEchecs` with `vert: false` triggers a correction pass (the new failures are in the finding); an absent `nouveauxEchecs`, or an empty `echecsDeBase`, keeps the correction. With `orchestrate.test` declared, when the program's own gate is green (`orchestrate.test` exits 0, L361; made unconditional by L522) the claim of red tests is never believed, whatever `echecsDeBase` and `nouveauxEchecs` hold (absent, empty or not, a non-empty `nouveauxEchecs` included): one warning (`tests annoncés rouges par la session, mais la porte du programme verte (<command>, code 0) : l'annonce n'est pas crue, pas de correction`), the review takes place, no correction pass and no « tests rouges » escalation. A red gate (non-zero exit) keeps the rules above. The program never guesses from the text of the result (« 24 failed »). The `implement` and `fix` briefs ask for `echecsDeBase` and `nouveauxEchecs`.
197
197
 
198
198
  **The build is played before the tests (L333)**: the gate of the wave runs `orchestrate.build` first, then `orchestrate.test`, because tests that read the build output (end-to-end tests over `dist`) are red without it — on 2026-10-25 three projects had to declare `test: astro build && npm test` (13 tests out of 15 red without `dist`), which played the build twice on every pass. A red build hands the lot back as a single « build » finding and the tests are not run. The L213 baseline plays the build first in its throwaway worktree too, then the tests: without it the start sha, with no `dist`, would excuse a test wrongly or turn everything red. A build that fails at the start sha gives no baseline (the build says nothing about the tests there): the tests stay red as before, no comparison is guessed. Without `orchestrate.build` nothing changes. A project that wrote `build && test` into its `orchestrate.test` can drop the duplicate build.
199
199
 
200
200
  **The program's gate is a visible step (L395)**: while `orchestrate.build` or `orchestrate.test` runs (after a writing session, at the rebased tip, and for the replay that follows a red), no claude session runs, and the lot used to read `implémentation` in `--status` and `→ implement` in the `cadence-hud` band: on 28-10 the gate of L392 ran 5 silent minutes. The lot's state now carries `gate` (`build` or `tests`, with its start), set when the command starts and removed when the checks end, red or green. `--status` prints the state `porte tests (3 min)` instead of `implémentation` (only for a running wave: a `gate` left in the state of a killed wave is not shown as running), and the band prints `porte@tests 3 min` where it printed `→ implement`. `--status --wave <wave>` is the same as `--status <wave>` (it used to show the last wave of the folder); two different ids are refused.
201
201
 
202
+ **No correction pass without a finding, and a red that passes alone is proposed, not corrected (L522)**: the study of L517 classified 580 correction passes of the waves of 2026-10-23 to 2026-11-01: 73 were « sans-constat » (13 %), and 48 of those 73 ended with no commit. Two causes are closed. (1) A non-conforme review, code or UX, that lists no actionable finding no longer opens a fix pass: a finding is actionable when it is blocking or major and its text, trimmed, is not empty (minors never are, on this path); the review can announce `bloquants: 1` with `constats: []`, and `conforme` is false on the announced totals. The lot is handed back (`handed-back`) with the cause `revue non conforme sans constat actionnable (N bloquant(s), M majeur(s) annoncé(s), aucun constat lisible) : pas de passe de correction` in the table and in the wave log; `pass` is left as it was, `next` is cleared (never `fix`: the lot is handed back) and the lot's findings are emptied, so a resume does not reopen the pass. A conforme review is untouched (minors pass, proposals). (2) A test red in the whole suite, absent from the baseline and green when replayed alone (the replay of L354, which needs `orchestrate.testReplay`) is still noted unstable as before (warning, wave log, `instables`) and now adds one lot proposal, `[instable] <test> — rouge dans la suite, vert rejoué seul : à stabiliser`, once per test; a « délai trop juste » test (L510) keeps its own warning and adds no proposal. The `fix` brief asks the session to replay each red test it is given alone before writing code, to leave a test that is green alone untouched and to list it under `choix` as unstable. **Measure**: the before/after reading is the `sans-constat` row of `cadence corrections` read by `node scripts/temps-d-un-lot.mjs --corrections <corrections.json>` (L517, unchanged by this lot): start of the window, 73 passes out of 580 classified (13 %), 48 of those 73 finished without a commit. The row also counts the passes opened on red tests with no review, so the drop expected after this lot is the unstable reds and the announced reds (L361 rule above), not the real red tests.
203
+
202
204
  **A red test is replayed alone before it counts, only on a declared command (L354)**: on 2026-10-26, with 32 cores and a cap of 4 sessions, every suite ran vitest at 31 workers, and four correction passes (L344 11 min, L342 9, L349 7, B28.12 4) found nothing to fix — each time « a test that passes alone ». cadence does not guess how a file is replayed on your runner (a first version appended the files to `orchestrate.test` and, on a composed gate, excused a real regression), so the replay is **off unless the project declares its command**: `orchestrate.testReplay`, where `{files}` is replaced by the files of the red tests, e.g. `testReplay: "npx vitest run --maxWorkers=$CADENCE_TEST_WORKERS --minWorkers=1 {files}"` (a value without `{files}` is refused when the file is read). **Without it nothing is replayed and nothing is held for unstable**: a red test is counted as before. With it, a red test of the gate (`orchestrate.test`, played after every writing session and at the rebased tip) that is absent from the baseline is **replayed alone, twice at most**, by that command, in the lot's worktree (vitest names `file > suite > test`, pytest `file::test`, jest `FAIL file` and `● Suite › test`, the latter tied to the `FAIL` line that precedes it in the same output and replayed with that file; the file is the part before the first `::` or ` > `, so either of them inside a test title is not part of the path). Green at a replay, the test is **« instable sous charge »**: it is not counted, it triggers no correction pass, even when the session reported its tests red (`vert: false`: a session that plays the suite under the same load sees the same red; the announcement is not held against the lot when every red of the gate is unstable, as it is not when every red was already red at the start), the lot goes on to its review, and the trace is a lot warning (so a line of the final table), a journal line `<project>:<lot> · N test(s) instable(s) sous charge …`, the lot's `instables` list in its journal, and the `cadence perf` line `tests instables sous charge` (`instables` in `--json`). Red at both replays it is counted as before. A red name that designates no file (a plain `FAIL name`) cannot be replayed alone and is counted at once. **A replay in which the test did not run counts red**: only a replay that exits 0 after running tests proves a test green, and only for the tests whose file appears in the replay's output, as a whole path on a line of the runner — never in the launcher's echo of the command: npm 12 writes `npm notice run 'vitest' run … <files>` on stderr for `npx …` as for `npm test -- …`, npm and pnpm write `> vitest run … <files>`, yarn `$ …`, and those lines name every file asked for, played or not (a runner that silently skips a file it cannot find, such as vitest given a path of another workspace, exits 0 without playing it: that test stays red; with a reporter that does not list files, nothing is ever excused; `a.test.ts` is not found in `src/a.test.ts`); a replay that fails, or that runs no test (the runner's closing line `No test files found, exiting with code`, `No tests found, exiting with code` or `no tests ran in`, even with exit code 0; the same words inside a test title or a test's output do not count), leaves every test it was asked about red. In a vitest workspace the names read `|package| src/a.test.ts > case`: the `|package|` prefix is dropped to find the file. The reviewer is told which tests were red under load (`instables` of the check, also when the baseline holds red tests of its own), so it does not report them, and the correction finding lists only the tests still red after the replays. The baseline run is included: with `testReplay`, a red test of the L213 baseline (the gate played at the start sha, in its throwaway worktree) is replayed alone there, twice at most, before it is retained as « already red at the start »; green at a replay it is dropped from the baseline (a journal line `… · ligne de base <sha> : N test(s) rouge(s) sous charge, vert(s) rejoué(s) seul(s), non retenu(s) …`), so a test the lot really breaks is not excused by a load failure of the start sha. The baseline replays are not the lot's « instables »: they say nothing about the lot's code. **A composed gate is not supported (decision of 26-10)**: `orchestrate.testReplay` is refused when `cadence.yaml` is read if `orchestrate.test` has `&&` or `||` outside quotes, or a parenthesis (sub-shell `( … )`, `$( … )`, function): a first runner that goes red cuts the next one, so a green replay of its tests says nothing of the rest, and a replay command written for one runner of the gate cannot replay the tests of the other. Write the replay for a gate that launches a single runner; without `testReplay` a composed gate is played as before, nothing is replayed. A jest `FAIL` line may carry a duration (`FAIL src/a.test.ts (6.21 s)`) or a project name (`FAIL backend src/a.test.ts`): the file is its last word, and any other `PASS`/`FAIL` line ties no file to the `●` lines that follow. The `FAIL project file` line is itself a red name (`project file`) and is replayed with that file, like the `●` tests under it.
203
205
 
204
206
  **A test that expires close to its limit even alone is a « délai trop juste », not a bug (L510)**: on 2026-10-31 a test of warhammer (L61) took 25 s alone for a 30 s delay: it passed alone, expired under the slightest load, and the gate sent four correction passes and the escalation for a defect that was not one. A composed gate declares its parts (`orchestrate.test` as a list, L512, below) to get the same. The replay alone now also reads the **duration** of the test (its own line `✓ file > test 25012ms`, else the `✓ file (3 tests) 24s` line of its file, an upper bound) and the **delay** it expired at in the whole-suite output (vitest `Test timed out in 30000ms`, jest `Exceeded timeout of 5000 ms for a test`). Green alone at **80 %** of that delay or more, the test is no longer filed with the unstable-under-load ones: no correction pass, the lot's `delaisJustes` (test, duration, delay) and a warning that names it (`délai trop juste, pas un bug … : test/a.test.ts > plan-data (25 s seul pour 30 s de délai) — relever le délai du test`), shown in the end-of-wave table. A test still red alone is a bug whatever its delay; a test with no delay in the suite output or no readable duration stays an ordinary unstable test.
@@ -216,7 +218,9 @@ orchestrate:
216
218
 
217
219
  **Each session gets its share of the machine (L350)**: the wave computes `CADENCE_TEST_WORKERS = max(1, cores ÷ session cap)` (`--max-sessions` or `CADENCE_MAX_SESSIONS`; 32 cores and a cap of 4 give 8; a `CADENCE_TEST_WORKERS` already set in the environment that launches the wave wins when it is a positive integer). It is put in the environment of every session and of every command of the gate (tests, build, baseline, replays), recorded as `testWorkers` in the wave state, and the `implement`, `fix`, minors and librarian briefs tell the session to respect it: `vitest run --minWorkers=1 --maxWorkers=$CADENCE_TEST_WORKERS` (vitest 2 refuses `--maxWorkers` alone, its default minimum being the core count: « options.minThreads and options.maxThreads must not conflict »), `jest --maxWorkers=$CADENCE_TEST_WORKERS`, `pytest -n $CADENCE_TEST_WORKERS`. The gate command itself must honour it for the share to bind: cadence's own `vitest.config.ts` reads it (`poolOptions.forks.maxForks`, `threads.maxThreads`); in another project write `orchestrate.test: npx vitest run --minWorkers=1 --maxWorkers=$CADENCE_TEST_WORKERS` (or the equivalent of its runner).
218
220
 
219
- **The session plays the gate's own commands (L399)**: the briefs of the writing sessions (implement, fix, minors pass, librarian pass) name the exact `orchestrate.test` and `orchestrate.build` of the project (`The program's gate, played after every writing session, is exactly: …`) and ask to run them as written, not a narrower equivalent. Measured on 22–28-10 (`docs/mesures/portes-rouges-2026-10-28.md`): sessions that played `npm run build` (`src` only) announced a green lot that `npx tsc --noEmit` (tests included) sent back to a correction pass. Without `orchestrate.test` and `orchestrate.build` there is no line.
221
+ **The session plays the gate's own commands (L399)**: the briefs of the writing sessions (implement, fix, minors pass, librarian pass) name the exact `orchestrate.test` and `orchestrate.build` of the project (`The program's gate, played once by the program after your writing session, is exactly: …`) and ask to run the build as written, not a narrower equivalent (the tests are targeted since L518, below). Measured on 22–28-10 (`docs/mesures/portes-rouges-2026-10-28.md`): sessions that played `npm run build` (`src` only) announced a green lot that `npx tsc --noEmit` (tests included) sent back to a correction pass. Without `orchestrate.test` and `orchestrate.build` there is no line.
222
+
223
+ **One full gate per lot (L518)**: the writing sessions no longer replay the full suite. Measured by `scripts/temps-d-un-lot.mjs` (study L517, `docs/mesures/temps-d-un-lot.md`): 1 945 full suites played inside the sessions (2.7 per lot, median 2, 1.8 min each) on top of the 1 337 the gate plays after the writing sessions; one UI separator (ol L239) replayed the suite 5 times. The briefs (implement, fix, minors pass, librarian pass) now say: play only the tests of the code you touch (targeted, once, before committing) and the build as written; the full suite is the program's gate, played once after the session, and `cadence verify --gate` takes its verdict back (L397) instead of playing it again. The `{{gate}}` text carries this when the project declares `orchestrate.test`; with `orchestrate.build` alone the text lists the build and tells the session to play the full suite itself, once (the program plays no suite then); with no gate declared the briefs tell the session to play the full suite itself, once, since nobody else will. The wave measures it: the `suites` column of the final table (and of `--status`) is the number of times the program played the full `orchestrate.test` for the lot (`suiteRuns` in the lot state: one per writing pass, replays alone of red tests not counted; `—` when none was played, a gate without `orchestrate.test` or a state written before L518). The suites a session plays itself stay measured by `scripts/temps-d-un-lot.mjs` from the transcripts (the program does not read them), so the table shows the gate's share only: with the briefs followed, a lot of one writing session reads `1`.
220
224
 
221
225
  **Review sized to the lot (L108)**: a lot whose `estimate` is ≤ `orchestrate.review.threshold` (0.25 day by default)
222
226
  is *light*: one single review (Sonnet by default, `code-reviewer` agent, same criteria), no minors pass — the minors are
@@ -238,7 +242,7 @@ orchestrate:
238
242
  escalation: { model: fable } # no default: absent = nothing changes
239
243
  ```
240
244
 
241
- The name is passed as it stands to `claude --model` — no closed list `haiku|sonnet|opus` (the same holds for `@<model>` of a lot and for `orchestrate.review.light` / `full`, L345: the three aliases keep their meaning, any other name goes through unchanged, and `--dry-run` prints `⚠ modèle « <name> » hors des alias …` for each such name, without refusing), and no default value, because the account may not have the model. When the review is still not compliant after the planned passes (`MAX_PASSES`, or `MAX_PASSES_CONVERGING` when it converges), or when the lot would be handed back « tests rouges » after them, the wave plays **one** correction and then **one** fresh code review, both on that model, before handing the lot back. The lot is handed back only if that escalated review is not compliant (`… ; rendu malgré l'escalade <model>`); the escalated correction that leaves the tests red hands it back without a review. A compliant escalated review ends the lot as any compliant review does (minors pass, UX review, `ready`). The UX review keeps its own rule: a lot handed back for a non-compliant UX review is not escalated. The escalation counts as a correction pass (`passes` of the table) and is played at most once per lot, a resume included (`escalation` in the lot's journal).
245
+ The name is passed as it stands to `claude --model` — no closed list `haiku|sonnet|opus` (the same holds for `@<model>` of a lot and for `orchestrate.review.light` / `full`, L345: the three aliases keep their meaning, any other name goes through unchanged, and `--dry-run` prints `⚠ modèle « <name> » hors des alias …` for each such name, without refusing), and no default value, because the account may not have the model. When the review is still not compliant after the planned passes (`MAX_PASSES`, or `MAX_PASSES_CONVERGING` when it converges), or when the lot would be handed back « tests rouges » after them, the wave plays **one** correction and then **one** fresh code review, both on that model, before handing the lot back. The lot is handed back only if that escalated review is not compliant (`… ; rendu malgré l'escalade <model>`); an escalated review that is not compliant and lists no actionable finding (L522) hands the lot back at once, with the outcome `revue non conforme sans constat actionnable …` and the journal line `escalade <model> : lot rendu malgré l'escalade`, no further correction; the escalated correction that leaves the tests red hands it back without a review. A compliant escalated review ends the lot as any compliant review does (minors pass, UX review, `ready`). The UX review keeps its own rule: a lot handed back for a non-compliant UX review is not escalated. The escalation counts as a correction pass (`passes` of the table) and is played at most once per lot, a resume included (`escalation` in the lot's journal).
242
246
 
243
247
  The lot's budget is respected: the escalation needs what a correction and its review need (`REVIEW_RESERVE`, as for any correction pass), and the budget of a lot in a project that declares `escalation` reserves its share for it (`ESCALATION_RESERVE`, see **Budget**). When the budget does not cover it, it is **not played** and the outcome says so (`escalade <model> non jouée (budget du lot …)`); the lot is handed back to the lead with its findings. The final table prints one line per escalated lot, `<project>:<lot> — escalade <model> : <outcome>` (`en cours` only while the lot still runs — the table also serves `--status` and a suspended wave —; a lot withdrawn (`--drop`), failed by an error or stopped by an incident of the repository before the model's verdict says `engagée, lot rendu avant le verdict du modèle`: the model did not judge it and it is not counted against the model —, compliant review, lot handed back despite the escalation — for the human or an arbitration of the lead —, not played, or an escalated session that returned nothing (empty output, launch error, cut, timeout; the only case said `session escaladée sans résultat`) — then the model never judged the lot and the lead takes it up, `rendu malgré l'escalade` is said only for a lot handed back on a verdict). A lot whose escalated review was compliant but is handed back later (non-compliant UX review, refused integration) keeps `revue neuve conforme` and says its lot line is the reason, the wave log traces the three moments, and `cadence perf` counts the escalated lots of each window and their outcome (`docs/perf.md`). The price grid of `cadence perf` knows `sonnet`, `opus` and `haiku`: the cost of an escalated step on another model reads `n/d`.
244
248
 
@@ -422,6 +426,7 @@ Once the sheet exists, the steps after it all read it (L174, `src/orchestrate/av
422
426
  - **A self-check list before handing back (L222).** Both `implement.md` and `fix.md` carry the same fixed list (plain text, no marker, no new variable), taken from the recurring findings of the reviews of 2026-10-15: the usage documentation (README and architecture documentation) updated in the same commits as the behaviour; one test named `Rn — …` per rule of the sheet (one per business rule of the lot when there is no sheet); no dead code and no test that cannot fail (an assertion always true, or a test that does not exercise its rule); for a modified screen, the capture due of each state at 1440 and 390 px with a file name (where it goes is the Playwright paragraph's rule) (a lot with no modified screen owes none and says so); no false comment, docstring or message. The session goes through it point by point on its own commits before it reports, and a point it cannot hold is written under `choix` or `nonVerifie` of its report: the report schema has no new field. In `fix` the list covers only what the session changed, and "fix them, and nothing else" stays. The other briefs (`fix-minors`, `spec`, `spec-back`, `accept`, `review-small`…) are unchanged. The before/after measure — correction passes per lot, replayed with `cadence corrections` (`--until <bound>` for the "before", `--since <bound>` for the "after", the bound being the time of the `npm run service` that puts the list in service) — is in [docs/mesures/autocontrole-avant-revue-2026-10-15.md](mesures/autocontrole-avant-revue-2026-10-15.md).
423
427
  - **Auto-verification once the tests are green (L236).** After the self-check list, `implement.md` and `fix.md` carry a second fixed block: when the full suite and the build pass, the session re-reads the complete diff of its lot (of its fix commits, in `fix`) against the grid of the `code-reviewer` agent — code bug, architecture drift, `docs/architecture.md` (or the project's architecture documentation) up to date, edge cases, one test per changed behaviour — fixes what it finds at once (test first, a `fix(<lot>): …` commit, suite and build replayed), then starts `resume` with an « auto-vérification » paragraph: what it re-read, found and fixed, could not hold. No new report field. The cost bound is written in the brief: one reading of the diff, not a second review (no subagent, no files the diff does not touch). Measure before the block (`cadence corrections --classify`, 10 to 17-10): 356 passes, 53 % code bug, 19 % architecture drift, 14 % unclear spec; `cadence perf` of 17-10: 37 % right the first time. Target: above 50 % on the next window with tokens per lot stable (`cadence perf`).
424
428
  - **Limits and rules before the walkthrough (L428).** `implement.md` (not `fix.md`) carries a third fixed block between the self-check list and the real walkthrough, aimed at the first cause of correction passes: a code bug the review finds in the diff (100 of the 143 classified passes of the 23–29-10 window, `cadence perf`). The session re-reads its diff against the fiche and the lot and, **per rule** (`Rn`), names the test that fails if the code breaks it and the line that holds it; **per function, parser, pattern, threshold or command it adds or changes**, lists the inputs at the edge (empty, absent, twice, wrong order, wrong type, refused, the real shape of the data, the other callers) and gives each a test that fails without its code, except a case the fiche does not cover: with a fiche, the session does not code a rule the fiche does not state, so that case goes under `"nonVerifie"` or `"choix"`, neither coded nor tested (a lot without a fiche has no such exception: every listed case is due a test, and one left untested goes under `"nonVerifie"`); **per figure, « all », « never » or « always »** written in README, docs, comments or tests, checks it against the code or by running it. A listed case left untested goes under `"nonVerifie"`. The reading of the 23–29-10 passes that led to it, and the way to measure its effect on two windows, are in [mesures/bug-code-2026-10-29.md](mesures/bug-code-2026-10-29.md). Test: `test/limites-et-regles-l428.test.ts`.
429
+ - **The grid of the code-reviewer, edge cases first, and the pre-check's reading (L523).** The study L517 found `bug-code` in 52 % of the correction passes (223 of them edge cases) and architecture drift in 10 %, and 13.4 reading round trips per lot. `implement.md` (not `fix.md`) therefore carries a fourth fixed block, « Grid of the code-reviewer (L523) », a paragraph of its own between « Limits and rules » and the real walkthrough (plain text, no marker, no new variable): the families the review applies to the diff (code bug, architecture drift, a test missing or that cannot fail, dead code, an error swallowed, documentation that does not follow, a written convention not followed), the order « write the test of each edge case of the goal and see it fail for the right reason BEFORE the first line of code » (a case the sheet does not cover is neither coded nor tested: `"nonVerifie"` or `"choix"`), and the re-reading of the diff against the grid before the last commit (a point not held goes under `"choix"` or `"nonVerifie"`, no new report field). The pre-check carries the other half: its report has an optional `lu` field (the files the lot concerns as `path:line`, the neighbouring code to imitate, the existing tests opened). The program stores it, trimmed and cut at 4000 characters (the end `[…tronqué]` included), in `precheckLu` of the lot's state when the verdict is `non`, `partiel` or an unproven `oui`; nothing is stored when `lu` is absent, empty or not a string (the last case adds the warning `contrôle préalable : champ lu ignoré (mal typé)`), for a proven `oui` (the lot is handed back), or for a `non`/`partiel` of the local model with `orchestrate.precheck: local` (accepted without a re-read by Sonnet, its reading is not trusted; after a local `oui` it is Sonnet's `lu` that is stored). The first `implement` pass then gets, after the pre-check finding and a blank line, a block « Pre-check reading (L523) »: start from those files, code and tests without searching for them again, reopen a file only to modify it or when the reading is not enough, re-read the lines you edit. A pass resumed after an interruption and a `fix` pass never get it (the reading dates from the start of the lot). `precheck` and `precheckVerdict` keep their meaning, an older state without `precheckLu` replays unchanged, and `cadence corrections` still reads `precheckVerdict`. Effect: [before/after measure](mesures/brief-implementation-enrichi-avant-apres.md) (passes per lot, cause of the passes, reading round trips, with `scripts/temps-d-un-lot.mjs`).
425
430
  - **The edge-cases point, sharpened (L447).** `cadence corrections` now sub-classifies the `bug-code` passes ([corrections](corrections.md)); on the 24→30-10 window the dominant link is the `implement` brief (99 of 136 passes; 96 of them, 71 %, are edge cases). The « edge cases » bullet of the L428 block therefore carries, marked `[L447]`, two more demands: the list of edge inputs is written before the first line of code, and before reporting each listed input is played once on the real path (a real file or call, not only the fixture). It is the same block, not a second one; no other brief changes. Table, protocol and the two windows to measure (L428 and L447 together, from 2026-10-30): [docs/mesures/bug-code-2026-10-30.md](mesures/bug-code-2026-10-30.md).
426
431
  - **Real walkthrough before the auto-verification (L344).** Reading a diff did not show three major review findings of 26-10 (a command impossible in its own documented path, a « champs exclus » read against a decision of 22-10, a failure banner out of view). `implement.md` therefore asks, once the tests are green, to play what was delivered as a user would: a command in a throwaway repository (`git init` in a fresh temporary folder), following the documentation the lot wrote, command by command; a screen in each of its states, failure included and shown where the action takes place, with a capture of each. What breaks is fixed in the same session (test first) and played again; the report says it in a paragraph of `"resume"` that starts with « parcours réel » (no new field; a lot with nothing to play says so). `fix.md` does not carry it: a correction pass fixes the findings it is given.
427
432
  - **Decisions to respect (L344).** The program (not the pre-check session, which many lots skip) reads the notes of the lot and of its parent lot (`parent:`) and keeps those that name who decided (Sylvain, the human, the lead, the user) and say that they decided, validated, asked or refused (`src/orchestrate/decisions.ts`). The notes the program writes itself are never taken for one, whatever they quote: a hypothesis of a fiche (« Hypothèses (fiche …) — », a choice nobody validated), a minor of a review (« Revue de … — mineur : »), a replaced title (« titre remplacé : », the stale one), « remis en attente » and « abandonné : ». Each is given with its date and its text as written (cut at 1500 characters) under « Decisions to respect » in the `implement` and `fix` briefs (and in the `--dry-run` briefs), with the rule: an interpretation that departs from one of them is a question under `"questions"`, never a choice under `"choix"`. Nothing is written when no note qualifies. The effect is measured by the share right the first time of `cadence perf` over two windows.
@@ -553,6 +558,17 @@ except a copy that is still needed, which stays and is said: a copy that a live
553
558
  The waves that count are those of the launch folders the script knows (`<folder>/.cadence/runs/<wave>/wave.json`): the repository itself and the working directory of every wave the orchestrator's registry still lists (`~/.cadence/orchestrate/waves/<pid>.json`; the registry drops a dead wave when another registers, so it does not know suspended waves by itself). There is no search over the whole disk: a suspended wave launched from another folder is not protected here, and `--resume` repairs its snapshot instead (above). A wave never marked `done` keeps its copy until it is, or until its folder is removed. A failure of the purge (unreadable copy, busy file) once `service` and the links have switched is a warning on the error output (`avertissement : purge des anciennes copies interrompue …`): the new version is in service, the fingerprint is printed, the exit code is 0, the next put in service tries again. The same run updates the **local copy of the `cadence-hud` mod** (L419), the one `CLAUDE_CODE_PLUGIN_DIRS` makes Claude Code load (`~/.claude/mods/cadence-hud`, `--mod-dir` for another folder): `plugins/cadence-hud` of the copy just put in service (not the working repository) is synchronised into it with `rsync -a --delete`, which leaves out `.claude-plugin/types` (generated by Claude Code in the copy). The output says `mod cadence-hud : copie locale mise à jour (<dir>)`. A machine without that folder gets no copy created (`copie locale absente … non mise à jour`), and a failed `rsync` is a warning on the error output (`avertissement : mod cadence-hud non mis à jour …`), exit code 0 like the purge: the version is in service. Before L419 the copy was updated by hand at each release and a forgotten one left the old mod loaded. The first run is also what installs the links in `~/.local/bin`. It prints the fingerprint of the copy
554
559
  (bin, dist, package.json).
555
560
 
561
+ ## Express lane (L519)
562
+
563
+ A lot of **at most 0.1 day** (`estimate: 0.1` or less, no `screen:`, no `spec: true`) takes the express lane, with no key to set. The L517 study ([docs/mesures/temps-d-un-lot.md](mesures/temps-d-un-lot.md), lever 2) measures 15.5 min and 116 k counted tokens for such a lot, 44 % of them in review and preparation: the lane cuts about 4.9 min and 51 k tokens per lot. What changes:
564
+
565
+ - **One writing session.** No precheck (even on the local model), no edge-case probe (`orchestrate.probe` is ignored for the lot), no separate code review and no UX review: the lead reads the diff and looks at the capture. After the program's gate the lot is `ready`, with the verdict `conforme : voie express …` recorded in the plan at the sha of its last commit (so `raf done` and the review gate accept it).
566
+ - **The full gate plays once** (`orchestrate.build`, then `orchestrate.test`, as for any lot): a red test still sends the lot to a correction pass. Only the « code sans test » gate (`orchestrate.testGate`) is off, because a purely visual change has no new test to write; the `implement` brief says so (« Express lane »: a change of behaviour still gets its test first).
567
+ - **No News entry per lot.** The brief of a visible express lot asks for a capture and no `cadence news new`; the lead groups the entries at delivery. `raf check` still wants an entry for a visible lot, so write the grouped entry before `raf done`.
568
+ - `--dry-run` prints `voie express` and the single step `implement`.
569
+
570
+ A lot above 0.1 day, or with a screen or a spec sheet, keeps the full cycle. The threshold is `EXPRESS_MAX_ESTIMATE` in `src/orchestrate/express.ts`.
571
+
556
572
  ## The edge-case probe (`orchestrate.probe`, L497)
557
573
 
558
574
  Code bugs are the first cause of correction passes, and an edge case is the first sub-cause of those (64 % of the `bug-code` passes since the instruction of L447, 69 % before: writing it in the brief changed nothing). `orchestrate.probe: true` adds a step between the writing and the review: a **fresh Sonnet session** (`probe`, brief `templates/orchestrate/probe.md`, `effort.probe` medium, the delay of a write step `timeouts.work`) that has not written the code, reads the lot's diff, and tries to break it with tests at the edges: empty, absent, twice, wrong type, refused, the real shape of the data, the other callers. The diff is given as a command (`git diff <start sha>..HEAD`), never pasted; the sheet of the lot is named when there is one. Like `implement` and `fix`, the brief gives the program's exact gate (L399: the probe commits tests the gate replays, `tsc` and the quality script included) and the session's machine share (L350). The session writes its tests in new files and commits them all, the passing and the failing, with `probe(L<n>): …`; it does not touch the application code nor the sealed acceptance tests.
package/docs/raf.md CHANGED
@@ -52,7 +52,7 @@ raf gantt # .cadence/gantt.html (next to the plan)
52
52
  |---|---|
53
53
  | `raf --version` · `raf -v` | print the version of the package, as `cadence --version` does (L376); only as the first argument, `raf show --version` stays an unknown option |
54
54
  | `raf init [--project name] [--prefix L] [--no-hook]` | create the plan, install the hook, add `.playwright-mcp/` to `.gitignore` |
55
- | `raf add "title" [--estimate d] [--quickwin] [--visible [--screen page\|component\|journey]] [--spec] [--public "title"] [--after L2,L4] [--uses banc,passerelle] [--parent L3]` | add a lot or a sub-task, print its id (`--public`: the lot's title in the public's words, written as `public:` right after `title:`; `--screen`: the screen a visible lot creates or changes — a new `page`, a new `component` or a modified `journey` — written as `screen:` right after `visible:`, shown by `raf show`; it requires `--visible`, and `raf check` reports a `screen:` without `visible:` or with another value as an error. Only `page` triggers the spec step of `orchestrate` (L209), never inferred from the title; `--spec`: the lot changes a behaviour (something a user, an API client or another service can observe), written as `spec: true` right after `screen:`, `visible:`, `quickwin:` or `estimate:` (whichever comes last), shown by `raf show`, refused on a sub-task. Also set by the lead at planning time, never inferred from the title); `--uses`: the shared resources the lot occupies, written as `uses: [banc, passerelle]` after `after:` and before `created:` ([shared resources](#shared-resources-uses-and-resources), L251), refused on a sub-task) |
55
+ | `raf add "title" [--estimate d] [--quickwin] [--visible [--screen page\|component\|journey]] [--spec] [--local] [--public "title"] [--after L2,L4] [--uses banc,passerelle] [--parent L3]` | add a lot or a sub-task, print its id (`--public`: the lot's title in the public's words, written as `public:` right after `title:`; `--screen`: the screen a visible lot creates or changes — a new `page`, a new `component` or a modified `journey` — written as `screen:` right after `visible:`, shown by `raf show`; it requires `--visible`, and `raf check` reports a `screen:` without `visible:` or with another value as an error. Only `page` triggers the spec step of `orchestrate` (L209), never inferred from the title; `--spec`: the lot changes a behaviour (something a user, an API client or another service can observe), written as `spec: true` right after `screen:`, `visible:`, `quickwin:` or `estimate:` (whichever comes last), shown by `raf show`, refused on a sub-task. Also set by the lead at planning time, never inferred from the title); `--local`: the lead edits this repository by hand for this lot, written as `local: true` right after `spec:` (or the last key before it), refused on a sub-task ([a lot of the lead](#a-lot-of-the-lead-local-l519)); `--uses`: the shared resources the lot occupies, written as `uses: [banc, passerelle]` after `after:` and before `created:` ([shared resources](#shared-resources-uses-and-resources), L251), refused on a sub-task) |
56
56
  | `raf add "title" --every <days>` · `raf did <id> ["text"]` | recurring lot: `every` (days) and `last` (last time done) fields; the lot stays `todo`, `raf now` and `session start` list it under « Récurrent » with « dû depuis N j » / « prochain dans N j »; `raf did` resets the count (spec: `docs/superpowers/specs/2026-10-04-L11-tache-recurrente.md`) |
57
57
  | `raf screen <id> page\|component\|journey\|none` | set, replace or remove `screen:` on an existing lot, to adopt the [spec step](orchestrate.md#the-spec-step-of-a-lot-with-screen) on a plan already written (only `page` adopts the [spec step](orchestrate.md#the-spec-step-of-a-lot-with-screen); `component` and `journey` do not); refused on a lot without `visible:` (like `raf add --screen`) and on a sub-task; `none` removes the key and leaves `visible:` alone |
58
58
  | `raf visible <id> on\|off` | set or remove `visible:` on an existing lot (a user-facing change: a news entry is expected, and `cadence orchestrate` adds its UX step), written right after `quickwin:`, `estimate:` or `status:` (whichever comes last); `on` on a visible lot changes nothing, `off` on a lot without the key neither; refused on a sub-task, and `off` is refused while the lot has a `screen:` (`raf screen <id> none` first: a screen is a visible change). It is the fix `raf check` points to for an open « Revue UX — » lot without `visible:` (L273) |
@@ -108,6 +108,18 @@ pre-commit block to an existing repository. A read-only plan is never started by
108
108
  Global options: `--file path` or `RAF_FILE`; `RAF_TODAY=YYYY-MM-DD` to freeze
109
109
  the date. `cadence raf …` is the same as `raf …`.
110
110
 
111
+ ## A lot of the lead (local, L519)
112
+
113
+ `raf add "…" --local` marks a lot (`local: true`) that the lead does by hand in this repository instead of giving it to a wave (a touch-up the lead would rather see in the editor, a change that needs the lead's eyes all along). Two commands carry it:
114
+
115
+ | Command | What it does |
116
+ |---|---|
117
+ | `cadence local start <lot> [--ttl minutes]` | locks the repository as a wave does (`orchestrate.lock`, under the name `local:<lot>`): no wave starts in it, `orchestrate --resume` and `orchestrate --add` are refused with « une tâche locale du lead y est en cours (<lot>, depuis …) », and `deliver` waits for the lock like for a wave. The lot goes to `doing`. The lock is **declared**, like `cadence lead hold`: no process carries it (the shell that runs the command dies with the Bash tool call, and the lead's session has no stable process name), it holds until `local done` or `local abort`, and `--ttl` (60 min by default) is only the announced duration — past it, the lock still holds and `cadence lead tour` and `orchestrate --status` print « ⚠ tâche locale échue : <lot> … » until the lead finishes or aborts it; it never lapses silently. Refused, with nothing locked or written, when the lot is unknown, not marked `local`, `done` or `dropped`, when a wave or another local task holds the repository, or when another lot of the plan is `doing` (it is named). |
118
+ | `cadence local done <lot>` | plays the project's gate **once** (`orchestrate.build`, then `orchestrate.test`, at `HEAD`, as `cadence verify --gate`) and, if it is green, frees the repository. Red (code 1) or nothing to replay (code 2): the lock stays, fix and run it again. Refused when this lot's local task does not hold the lock. |
119
+ | `cadence local abort <lot>` | frees the repository without playing the gate (the task is given up or will be resumed later); the plan is not touched — the lot stays `doing`, `raf todo <lot>` puts it back. Refused when this lot's local task does not hold the lock. |
120
+
121
+ `local start` writes the plan (the lot goes to `doing`): commit it with the first commit of the lot. After `local done`: take the capture of a visible lot, read the lot's diff and record the verdict yourself (`raf review <lot> "…"` — on a plan with `reviewSince`, `raf done` refuses a lot with commits and no verdict; the express lane records its own verdict because a session did the work and the lead reads the diff at delivery, here the lead did the work, so the verdict is the lead's own reading and is written by hand), `cadence deliver`, then `raf done <lot>` — the lot is traced in the plan like any other (its commits cite it, `feat(L12): …`). A local lot is never played by a wave: `cadence orchestrate <project>:<lot>` (launch, `--add`, `--continue`) refuses it by name. During the task the pre-push hook sees the lock as a local task, not as a wave: no wave check, no « état illisible » warning; the gate check (`CADENCE_PUSH_UNGATED`) applies as usual.
122
+
111
123
  ## Shared resources: `uses:` and `resources:`
112
124
 
113
125
  Some projects of a folder share one thing that only one lot at a time can use (a test bench, a gateway, a
package/docs/whats-new.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  ## In two lines
6
6
 
7
+ - **1.38.0**: an express lane plays a touch-up of at most 0.1 day in one session; `raf add --local` and `cadence local start|done|abort` lock a repository while the lead edits it by hand.
8
+ - **1.37.0**: one full test suite per lot, played by the gate (`suites` column); no correction pass without a finding; a richer implementation brief; `scripts/temps-d-un-lot.mjs` measures where a lot's time goes.
7
9
  - **1.36.0**: `cadence deliver` no longer waits for the CI of a sha whose commits only touch the plan, with timed steps and a `deliveries-steps.log` journal; `orchestrate --add` puts a lot in a live wave.
8
10
  - **1.35.0**: a test already red before a lot, or that only needs more time, no longer costs correction passes, including on a gate declared in parts; QA passes run in browsers of their own; design agents check contrast and AI tics.
9
11
  - **1.34.1**: republishes 1.34.0, whose npm publication failed after the tag; same features (edge-case probe, steadier `mise-en-service` tests).
@@ -64,6 +66,10 @@ Each is a paragraph in [docs/whats-new.md](whats-new.md) and a full section in [
64
66
 
65
67
  The long form of « In two lines » above (the README no longer carries a « What's new » section since L326: it links here). The full history, with the date of each version, is in [CHANGELOG.md](../CHANGELOG.md).
66
68
 
69
+ **1.38.0**: two ways to make a small change cheaper (L519, decided on 01-11 after a one-line UI separator cost 245 s of implementation). The **express lane**: a lot of at most 0.1 day with no screen sheet nor spec is played by `cadence orchestrate` in a single writing session, without precheck, edge-case probe, separate code review or « code sans test » gate, and without a News entry per lot; the lead reads the diff and the capture, groups the entries at delivery, and the program's gate still plays once (`docs/orchestrate.md`). The **local task**: `raf add --local` marks a lot the lead does by hand, and `cadence local start <lot>` locks the repository like a wave (no wave starts there, `--add` and `--continue` refuse it, and the task itself is refused while a wave or another lot of the repository runs). The lock is declared with a `--ttl` (60 min by default, like `lead hold`) and carried by no process; past its TTL it still holds and `lead tour` and `orchestrate --status` show a ⚠ until `cadence local done` (gate green) or `cadence local abort`. A wave refuses a `local` lot, and the pre-push hook recognises the task instead of reporting an unreadable wave (`docs/raf.md`).
70
+
71
+ **1.37.0**: the first release of the efficiency work, sized by a measure of 721 lots (L517, `docs/mesures/temps-d-un-lot.md`, script `node scripts/temps-d-un-lot.mjs`): a lot took 25 minutes and 265k tokens, tests were 62 % of the writing sessions' wall time and a correction pass cost about 12 minutes. The writing sessions of `cadence orchestrate` now play only the targeted tests of the code they touch; the full suite is played once by the program as the gate, `cadence verify --gate` takes its verdict back, and the final table and `--status` count the full suites of each lot in a `suites` column (L518, `docs/orchestrate.md`). A non-compliant review that lists no blocking or major finding no longer opens a correction pass: the lot is handed back with the announced totals as the cause; a test red in the suite and green alone is proposed as a lot to stabilise, and a green program gate always outweighs a session's claim of red tests (L522). The `implement` brief carries the code reviewer's grid, « edge-case tests first, seen failing, then code » and a re-reading of the diff before the last commit; the pre-check passes what it read (`precheckLu`) to the first implementation so it does not read the repository again (L523). The tests workflow tolerates the npm « previously published » refusal of its publish dry-run on a non-release commit, and nothing else (L515).
72
+
67
73
  **1.36.0**: `cadence deliver` stops waiting for a CI that proves nothing. When every commit since the previous delivery touches only the plan, it says `→ CI : non attendue (aucun fichier hors plan depuis <sha>)`, then runs the deploy and the checks; as soon as one commit touches anything else, or the proof is missing (no previous delivery, rewritten history, no plan, empty range), it waits as before (L516, `docs/deliver.md`). 42 % of the app deliveries measured on 2026-11-01 were such shas. Every step line of the output now starts with its UTC time and `✓ livré` ends with its duration, and each step played appends a JSON line to `deliveries-steps.log`, so a slow delivery can be read step by step. `cadence orchestrate --add <project:lot> [--wave <wave>]` adds a lot to a live wave instead of launching a second one: the lot is checked like a launched one, queued in the wave's `adds.log` and played as soon as a session slot is free; the refusal of a second wave in the same repository now names this command, with the lot and the wave (L421, `docs/orchestrate.md`). A session running in a sibling repository is no longer handed back for a commit on another repository's main branch once a lot was added to the wave.
68
74
 
69
75
  **1.35.0**: the wave's gate stops paying for reds that need no fix. With `orchestrate.testReplay`, a red that stays red alone in the lot is replayed alone at the start sha, and one already failing there is « déjà rouge »: no correction pass, no escalation; a test that expired in the whole suite and passes alone at 80 % or more of its delay is a « délai trop juste », a warning naming the test with its duration and its delay (L510, `docs/orchestrate.md`). On a gate played in several folders, `orchestrate.test` takes a list of parts `[{ dir, run, replay? }]` and each part plays, replays and attributes its own reds, so a composed gate gets the same two verdicts (L512, `docs/orchestrate.md`, « A gate declared in parts »; evatosorus `node --test` is not covered yet). `cadence corrections` now counts the passes launched on tests that ended without a code change (L510, `docs/corrections.md`). The gate can also run on another machine through `orchestrate.gate.host`, by ssh at the pushed sha, with a local fallback and a lost connection replayed locally, never counted red (L403, `docs/remote-gate.md`). The `qa-reviewer` opens a browser context and a profile of its own, so two QA passes started together no longer share a tab (L511, `docs/skills.md`). The `spec-writer` joins a `contraste.md` (WCAG 2.2 ratios, 4.5:1 at least) to each sheet, and the `ux-reviewer` gets a delivery grid and a static check of AI tics (L513, `docs/orchestrate.md`). Small fixes: `cadence release` prints its local tag before the gate and removes it when red (L508, `docs/releasing.md`), `raf ux` and `raf review` print the commit command for the regenerated plan (L509), and `cadence deliver` outside a wave commits the plan it wrote for the « article à rafraîchir » lot (L420, `docs/news.md`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sylad/cadence",
3
- "version": "1.36.0",
3
+ "version": "1.38.0",
4
4
  "description": "A small, repo-native working method: a versioned plan linked to your commits, a changelog with screenshots, session rituals and deliveries proven by their effect.",
5
5
  "license": "MIT",
6
6
  "author": "Sylvain Ladoire",
@@ -20,6 +20,7 @@
20
20
  "NOTICE",
21
21
  "docs/raf.md",
22
22
  "docs/orchestrate.md",
23
+ "docs/mesures/brief-implementation-enrichi-avant-apres.md",
23
24
  "docs/deliver.md",
24
25
  "docs/remote-gate.md",
25
26
  "docs/spec.md",
@@ -8,7 +8,7 @@ Documentation behind the lot:
8
8
  {{constats}}
9
9
 
10
10
  Read the diff of each commit above (`git show <sha>`), the project's CLAUDE.md, the README, the pages of `docs/`, the CHANGELOG and the news entries; update each document the change makes false or leaves out; where the README is a short home page, the detail goes in the pages of `docs/` and the README receives only a link. A document that the change really leaves true is left alone, but the gap stays open for the program until it is acknowledged: {{ack}} A session that neither writes the documentation nor acknowledges the gap hands the lot back to the lead: it never goes to review. Say why under "choix" as well.
11
- Rules: commit each document as soon as it is right, with explicit paths (never `git add -A` or `commit -a`), and a message that cites the lot (`docs({{lot}}): …`); run the project's documentation checks if it has any, and its full test suite and build if a test reads the documents, before reporting; do not push, deliver, run `raf done`, `raf ux` or `raf review`.
11
+ Rules: commit each document as soon as it is right, with explicit paths (never `git add -A` or `commit -a`), and a message that cites the lot (`docs({{lot}}): …`); run the project's documentation checks if it has any, and the targeted tests that read the documents plus the build, before reporting (the full suite is the program's gate: do not replay it; with no gate below, play the full suite yourself, once); do not push, deliver, run `raf done`, `raf ux` or `raf review`.
12
12
  Never run `git checkout` or `git switch` to another commit or branch in this repository: the orchestrator watches it and a moved HEAD breaks the other sessions of the wave. To look at another sha, use a throwaway `git worktree add --detach <tmp> <sha>`, removed afterwards.
13
13
  {{elsewhere}}
14
14
  Do not stop to ask: an interpretation you settle yourself goes under "choix" with the alternative you did not take; "questions" stays empty. Making no documentation commit is a valid outcome only with the acknowledgement above.
@@ -10,7 +10,7 @@ Minor findings:
10
10
 
11
11
  Fix each minor finding that is right, and nothing else. Rules: test first; commit each fix as soon as
12
12
  its tests pass, with explicit paths (never `git add -A` or `commit -a`), and a message that cites the
13
- lot (`fix({{lot}}): …`); run the project's full test suite and build before reporting; do not push,
13
+ lot (`fix({{lot}}): …`); run the targeted tests of the code you touch (once, before committing) and the build, before reporting: the full suite is played once by the program as the gate given below, do not replay it (with no gate below, play the full suite yourself, once); do not push,
14
14
  deliver, run `raf done`, `raf ux` or `raf review`. Read the project's CLAUDE.md first.
15
15
  Never run `git checkout` or `git switch` to another commit or branch in this repository: the orchestrator watches it and a moved HEAD breaks the other sessions of the wave. To look at another sha, use a throwaway `git worktree add --detach <tmp> <sha>`, removed afterwards.
16
16
  Do not stop to ask. A finding that is wrong, or not worth its change, is not fixed: list it under
@@ -9,9 +9,10 @@ Commits of the lot so far:
9
9
  Findings to fix:
10
10
  {{constats}}
11
11
 
12
+ Red tests named above (L522): before writing any code, replay each red test named alone, with the project's own single-test command. A test that is red alone is a defect: fix it. A test that is green when replayed alone is unstable under load, not a defect of the lot: do not change code for it, and list it under « choix » of your report as unstable, to be proposed to the lead for its own lot.
13
+
12
14
  Rules: test first; commit each fix as soon as its tests pass, with explicit paths (never
13
- `git add -A` or `commit -a`), and a message that cites the lot (`fix({{lot}}): …`); run the project's
14
- full test suite and build before reporting; do not push, deliver, run `raf done`, `raf ux` or
15
+ `git add -A` or `commit -a`), and a message that cites the lot (`fix({{lot}}): …`); run the targeted tests of the code you touch (once, before committing) and the build, before reporting: the full suite is played once by the program as the gate given below, do not replay it (with no gate below, play the full suite yourself, once); do not push, deliver, run `raf done`, `raf ux` or
15
16
  `raf review`. Read the project's CLAUDE.md first.
16
17
  Sealed test of ANOTHER lot: if what your own sealed tests require contradicts a sealed acceptance test of another lot (an `acceptation-<lot>.json` that is not yours), it is a question to the lead naming both tests (file and `Rn — …` name of each): never modify, rewrite or reseal it and never pick a side. Stop there and put the question in your report. The program compares the fingerprints of the sealed tests of every other lot at the end of each session and hands your lot back, naming the first offending commit, before any review.
17
18
  Never run `git checkout` or `git switch` to another commit or branch in this repository: the orchestrator watches it and a moved HEAD breaks the other sessions of the wave. To look at another sha, use a throwaway `git worktree add --detach <tmp> <sha>`, removed afterwards.
@@ -23,7 +24,7 @@ Self-check before handing back (the recurring findings of the reviews), covering
23
24
  - no false comment: a comment, a docstring or a message never describes a behaviour the code no longer has or does not have.
24
25
  A point you cannot hold is written under "choix" or "nonVerifie" of your report, not left unsaid.
25
26
 
26
- Auto-verification once the tests are green, before the review: when the full test suite and the build pass, re-read the complete diff of your fix commits (`git diff <HEAD before your first fix>..HEAD`, run in each repository where you committed a fix: the project and any neighbouring repository above) against the grid of the code-reviewer agent: code bug; architecture drift; docs/architecture.md (or the project's architecture documentation) up to date; edge cases; one test per changed behaviour. What you find in your own fix, fix it at once (a `fix({{lot}}): …` commit) and rerun the suite and the build; touch nothing else. Then write in "resume" a paragraph that starts with « auto-vérification »: what you re-read, what you found and fixed, what you could not hold. It is one reading of the diff, not a second review: no subagent, no new exploration, no re-reading of files the diff does not touch.
27
+ Auto-verification once the tests are green, before the review: when the targeted tests and the build pass, re-read the complete diff of your fix commits (`git diff <HEAD before your first fix>..HEAD`, run in each repository where you committed a fix: the project and any neighbouring repository above) against the grid of the code-reviewer agent: code bug; architecture drift; docs/architecture.md (or the project's architecture documentation) up to date; edge cases; one test per changed behaviour. What you find in your own fix, fix it at once (a `fix({{lot}}): …` commit) and rerun the targeted tests and the build; touch nothing else. Then write in "resume" a paragraph that starts with « auto-vérification »: what you re-read, what you found and fixed, what you could not hold. It is one reading of the diff, not a second review: no subagent, no new exploration, no re-reading of files the diff does not touch.
27
28
 
28
29
  If a finding is wrong, say so under "choix" with the reason. If you make no commit at all, "choix" MUST say why: a session with no commit and no reason is handed back to the lead without a new review (the review would reread the same commits). Ask (under "questions") only when a fix needs a decision that passes the rule below.
29
30
  A question is legitimate only if it names what it would change: the scope of the lot, the architecture, or a costly rollback (data, production, public API);
@@ -32,7 +33,7 @@ a spacing, colour or label value when a measurement or a rule justifies it; the
32
33
  a News entry: only if a finding asks for it; a written rule of the project's CLAUDE.md (apply it); who launches the review or UX pass (never the session: the program and the lead do).
33
34
  "not my job to touch the plan" is not a question: say it in the report.
34
35
  Never stop to ask about how to organise your own work (split or squash a commit, order of the sub-parts, whether to continue, "I have no question"): decide, list it under "choix", go on. Leave "questions" empty rather than writing a placeholder such as "no question".
35
- Tests already red before the lot: if the suite is red, check whether the same tests are red at the sha the lot started from (the parent of the oldest work commit that cites {{lot}}, plan-only commits left out, or the `HEAD` before this session if the lot has none: a throwaway `git worktree add --detach <tmp> <sha>`, removed afterwards). Failures already there are not a defect of this lot: do not try to fix them and do not report your tests as red for them; list their names under "echecsDeBase" in your report (one test per entry, as the runner prints it), list under "nouveauxEchecs" the tests that are red now and were NOT red at that sha (an empty list when there are none: with `vert: false`, a non-empty "echecsDeBase" and an empty "nouveauxEchecs" the lot goes to review without a correction pass; any entry in "nouveauxEchecs" with `vert: false` triggers one), and say under "nonVerifie" if you could not check. The program replays the suite itself and compares to the same baseline.
36
+ Tests already red before the lot: if the suite is red, check whether the same tests are red at the sha the lot started from (the parent of the oldest work commit that cites {{lot}}, plan-only commits left out, or the `HEAD` before this session if the lot has none: a throwaway `git worktree add --detach <tmp> <sha>`, removed afterwards). Failures already there are not a defect of this lot: do not try to fix them and do not report your tests as red for them; list their names under "echecsDeBase" in your report (one test per entry, as the runner prints it), list under "nouveauxEchecs" the tests that are red now and were NOT red at that sha (an empty list when there are none: with `vert: false`, a non-empty "echecsDeBase" and an empty "nouveauxEchecs" the lot goes to review without a correction pass; any entry in "nouveauxEchecs" with `vert: false` triggers one, unless the program's gate is green (L522): then the claim is not believed and nothing is opened), and say under "nonVerifie" if you could not check. The program replays the suite itself and compares to the same baseline.
36
37
  A finding you contest (it describes a state older than the code, or you think it wrong) is not a question and not a reason to stop: do not ask the lead to arbitrate. Write it under "choix" with the evidence (the command, the line, the commit), fix what is right, go on; the next fresh review re-reads it.
37
38
  You are one short session of an orchestrated wave: do not launch subagents (the Agent tool is disabled).
38
39
  Give your final report as the structured output (commits, tests, build, what you could not verify, choices, questions).
@@ -4,9 +4,9 @@ Goal: {{objectif}}
4
4
  {{repos}}
5
5
  {{fiche}}
6
6
  {{decisions}}
7
+ {{express}}
7
8
  Rules: test first; commit each sub-part as soon as its tests pass, with explicit paths (never
8
- `git add -A` or `commit -a`), and a message that cites the lot (`feat({{lot}}): …`); run the project's
9
- full test suite and build before reporting; do not push, deliver, run `raf done`, `raf ux` or
9
+ `git add -A` or `commit -a`), and a message that cites the lot (`feat({{lot}}): …`); run the targeted tests of the code you touch (once, before committing) and the build, before reporting: the full suite is played once by the program as the gate given below, do not replay it (with no gate below, play the full suite yourself, once); do not push, deliver, run `raf done`, `raf ux` or
10
10
  `raf review`.
11
11
  Sealed test of ANOTHER lot: if what your own sealed tests require contradicts a sealed acceptance test of another lot (an `acceptation-<lot>.json` that is not yours), it is a question to the lead naming both tests (file and `Rn — …` name of each): never modify, rewrite or reseal it and never pick a side. Stop there and put the question in your report. The program compares the fingerprints of the sealed tests of every other lot at the end of each session and hands your lot back, naming the first offending commit, before any review.
12
12
  Never run `git checkout` or `git switch` to another commit or branch in this repository: the orchestrator watches it and a moved HEAD breaks the other sessions of the wave. To look at another sha, use a throwaway `git worktree add --detach <tmp> <sha>`, removed afterwards.
@@ -24,9 +24,11 @@ Limits and rules, before the walkthrough (a code bug found by the review is the
24
24
  - edge cases [L447] (the first sub-cause of the code bugs: 96 of the 136 `bug-code` passes of the 24–30-10 window, 71 %): write the list BEFORE the first line of code, and before reporting play each listed input once on the real path (a real file or a real call, never only your fixture) and compare what comes out with what the rule says. For every function, parser, pattern, threshold or command you add or change, list the inputs at its edge — empty, absent, twice, wrong order, wrong type, refused, the real shape of the data (not the one of your fixture), the other callers of what you changed — and give each one a test that fails without your code, before handing back, except a case the fiche does not cover: with a fiche, you do not code a rule it does not state, so that case is written under "nonVerifie" or "choix", neither coded nor tested; a case you listed and did not test goes under "nonVerifie";
25
25
  - claims: each figure, « all », « never » or « always » that your README, docs, comments or tests state is checked against the code or by running it, not from memory.
26
26
 
27
+ Grid of the code-reviewer (L523), the one the review applies to your diff: code bug (wrong result, unhandled error, input trusted raw); architecture drift (a responsibility in the wrong module, a duplicated block, a layer skipped); a test missing or that cannot fail; dead code; an error swallowed; documentation that does not follow the change; a written convention of the project not followed. Edge cases first: for each edge case of the goal (the « edge cases » point above: empty, absent, twice, wrong order, wrong type, refused, the real shape of the data, the other callers of what you change), write its test BEFORE the first line of code and see it fail for the right reason, then code; a case the lot does not cover is neither coded nor tested, it goes under "nonVerifie" or "choix". Before your last commit, re-read your diff against this grid and fix what it shows; a point you do not hold goes under "choix" or "nonVerifie" of the report (no new field).
28
+
27
29
  Real walkthrough once the tests are green, before the auto-verification below: play what you delivered as a user would, not by re-reading the diff. A command: run it in a throwaway repository (`git init` in a fresh folder of the session's temporary folder, never inside the repository), following step by step the documentation the lot wrote (README, `docs/`), every command exactly as written there; a command the documentation cannot run, or whose documented path is impossible from the state the previous steps leave, is broken. A screen: open it in each of its states, failure included, the failure shown where the action takes place (in view from the control the user just used, not above or below the fold), and take a capture of each. What breaks, fix in this same session (test first, a `fix({{lot}}): …` commit) and play it again. Then write in "resume" a paragraph that starts with « parcours réel »: what you played, what broke and was fixed, what you could not play (also under "nonVerifie"); a lot with nothing to play (no command, no screen) says so in that paragraph.
28
30
 
29
- Auto-verification once the tests are green, before the review: when the full test suite and the build pass, re-read the complete diff of the lot, commit by commit (the commits `raf commits {{lot}}` lists, each with `git show <sha>`; never a `git diff` range, which would take in the commits of other lots) against the grid of the code-reviewer agent: code bug (wrong result, unhandled error, input trusted); architecture drift (a responsibility put in the wrong module, a duplicated block, a layer skipped); docs/architecture.md (or the project's architecture documentation) up to date; edge cases (the list of the edge-cases point above, each with its test); one test per changed behaviour. What you find, fix it at once (test first, a `fix({{lot}}): …` commit) and rerun the suite and the build. Then write in "resume" a paragraph that starts with « auto-vérification »: what you re-read, what you found and fixed, what you could not hold. It is one reading of the diff, not a second review: no subagent, no new exploration, no re-reading of files the diff does not touch.
31
+ Auto-verification once the tests are green, before the review: when the targeted tests and the build pass, re-read the complete diff of the lot, commit by commit (the commits `raf commits {{lot}}` lists, each with `git show <sha>`; never a `git diff` range, which would take in the commits of other lots) against the grid of the code-reviewer agent (the paragraph « Grid of the code-reviewer (L523) » above): code bug (wrong result, unhandled error, input trusted); architecture drift (a responsibility put in the wrong module, a duplicated block, a layer skipped); docs/architecture.md (or the project's architecture documentation) up to date; edge cases (the list of the edge-cases point above, each with its test); one test per changed behaviour. What you find, fix it at once (test first, a `fix({{lot}}): …` commit) and rerun the targeted tests and the build. Then write in "resume" a paragraph that starts with « auto-vérification »: what you re-read, what you found and fixed, what you could not hold. It is one reading of the diff, not a second review: no subagent, no new exploration, no re-reading of files the diff does not touch.
30
32
 
31
33
  Decide minor interpretation questions yourself (the wording of a message, a name, a default, the
32
34
  reading of an ambiguous line of the lot) and list each one under "choix" in your report, with the
@@ -39,7 +41,7 @@ a written rule of the project's CLAUDE.md (apply it); who launches the review or
39
41
  Never stop to ask about how to organise your own work (split or squash a commit, order of the sub-parts, whether to continue, "I have no question"): decide, list it under "choix", go on. Leave "questions" empty rather than writing a placeholder such as "no question".
40
42
  If the lot's commits already cover its open sub-tasks, do not ask whether to continue: make no commit and say so
41
43
  in your report (the review that follows re-reads those commits). If they do not cover them all, implement the rest.
42
- Tests already red before the lot: if the suite is red, check whether the same tests are red at the sha the lot started from (the parent of the oldest work commit that cites {{lot}}, plan-only commits left out, or the `HEAD` before this session if the lot has none: a throwaway `git worktree add --detach <tmp> <sha>`, removed afterwards). Failures already there are not a defect of this lot: do not try to fix them and do not report your tests as red for them; list their names under "echecsDeBase" in your report (one test per entry, as the runner prints it), list under "nouveauxEchecs" the tests that are red now and were NOT red at that sha (an empty list when there are none: with `vert: false`, a non-empty "echecsDeBase" and an empty "nouveauxEchecs" the lot goes to review without a correction pass; any entry in "nouveauxEchecs" with `vert: false` triggers one), and say under "nonVerifie" if you could not check. The program replays the suite itself and compares to the same baseline.
44
+ Tests already red before the lot: if the suite is red, check whether the same tests are red at the sha the lot started from (the parent of the oldest work commit that cites {{lot}}, plan-only commits left out, or the `HEAD` before this session if the lot has none: a throwaway `git worktree add --detach <tmp> <sha>`, removed afterwards). Failures already there are not a defect of this lot: do not try to fix them and do not report your tests as red for them; list their names under "echecsDeBase" in your report (one test per entry, as the runner prints it), list under "nouveauxEchecs" the tests that are red now and were NOT red at that sha (an empty list when there are none: with `vert: false`, a non-empty "echecsDeBase" and an empty "nouveauxEchecs" the lot goes to review without a correction pass; any entry in "nouveauxEchecs" with `vert: false` triggers one, unless the program's gate is green (L522): then the claim is not believed and nothing is opened), and say under "nonVerifie" if you could not check. The program replays the suite itself and compares to the same baseline.
43
45
  Report: commits (sha + subject), tests and build results with their numbers, what you could not
44
46
  verify, choices made, open questions.
45
47
 
@@ -9,4 +9,5 @@ Answer `oui` only when every part of the lot is present, with a proof for each (
9
9
  some parts are present (say which); `non` otherwise. When in doubt, answer `non`: an implementation session follows.
10
10
  You are read-only: do not modify, commit, push or run `raf start|done|note|review|ux`. Do not launch subagents.
11
11
  Give your report as the structured output: `dejaPresent` (oui | partiel | non), `preuves` (the proofs), `resume` (one sentence).
12
+ Also give, in the optional `lu` field, what you read to look: the files the lot concerns (`path:line`), the neighbouring code to imitate and the existing tests you opened, one line each (a few lines, not a copy of the code). The implementation session starts from it instead of searching again; leave `lu` out when you read nothing of use.
12
13
  {{tmp}}