@sylad/cadence 1.40.0 → 1.42.1

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.
Files changed (69) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/spec-writer.md +1 -0
  4. package/agents/ux-reviewer.md +2 -0
  5. package/dist/archive.js +103 -6
  6. package/dist/audit.js +2 -2
  7. package/dist/clean.js +0 -4
  8. package/dist/cli/context.js +129 -0
  9. package/dist/cli/deliver-commands.js +114 -0
  10. package/dist/cli/gates.js +234 -0
  11. package/dist/cli/lead-commands.js +161 -0
  12. package/dist/cli/lot-commands.js +257 -0
  13. package/dist/cli/read-commands.js +227 -0
  14. package/dist/cli/session-commands.js +152 -0
  15. package/dist/cli/setup-commands.js +72 -0
  16. package/dist/cli/spec-commands.js +298 -0
  17. package/dist/cli/stats-commands.js +138 -0
  18. package/dist/cli-add.js +37 -0
  19. package/dist/cli.js +85 -1669
  20. package/dist/config.js +21 -108
  21. package/dist/corrections.js +28 -42
  22. package/dist/deliver-lots.js +37 -0
  23. package/dist/deliver.js +15 -39
  24. package/dist/docs-ok-file.js +25 -0
  25. package/dist/docsync.js +15 -3
  26. package/dist/lead.js +6 -24
  27. package/dist/lot-lines.js +51 -0
  28. package/dist/orchestrate/attente.js +82 -0
  29. package/dist/orchestrate/command.js +26 -25
  30. package/dist/orchestrate/continue.js +6 -14
  31. package/dist/orchestrate/cycle.js +18 -27
  32. package/dist/orchestrate/integrate.js +7 -2
  33. package/dist/orchestrate/integration-vivante.js +138 -0
  34. package/dist/orchestrate/launch.js +6 -18
  35. package/dist/orchestrate/lock.js +3 -20
  36. package/dist/orchestrate/lot-budget.js +2 -2
  37. package/dist/orchestrate/maquette.js +3 -0
  38. package/dist/orchestrate/registry.js +8 -1
  39. package/dist/orchestrate/schemas.js +5 -1
  40. package/dist/orchestrate/snapshot.js +13 -0
  41. package/dist/orchestrate/spec.js +51 -6
  42. package/dist/orchestrate/state.js +17 -0
  43. package/dist/plan-extras.js +119 -0
  44. package/dist/plan-ids.js +95 -0
  45. package/dist/plan-read.js +146 -0
  46. package/dist/plan-states.js +119 -0
  47. package/dist/plan.js +119 -190
  48. package/dist/raf-close-checks.js +25 -0
  49. package/dist/raf-status.js +28 -0
  50. package/dist/ref/command.js +2 -3
  51. package/dist/resources.js +3 -9
  52. package/dist/state.js +31 -8
  53. package/dist/verify-gate.js +33 -2
  54. package/dist/verify.js +20 -3
  55. package/dist/yaml-keys.js +21 -0
  56. package/docs/cadence-hud.md +1 -1
  57. package/docs/deliver.md +25 -3
  58. package/docs/fonctionnement.md +9 -5
  59. package/docs/lead.md +9 -7
  60. package/docs/news.md +2 -0
  61. package/docs/orchestrate.md +24 -7
  62. package/docs/perf.md +1 -0
  63. package/docs/qualite.md +14 -4
  64. package/docs/raf.md +62 -7
  65. package/docs/spec.md +5 -2
  66. package/docs/whats-new.md +9 -0
  67. package/package.json +1 -1
  68. package/skills/lead/SKILL.md +1 -1
  69. package/templates/orchestrate/spec.md +2 -2
package/docs/raf.md CHANGED
@@ -52,11 +52,12 @@ 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] [--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) |
55
+ | `raf add "title" [--estimate d] [--quickwin] [--visible [--screen page\|component\|journey]] [--spec] [--local] [--public "title"] [--after L2,L4] [--uses banc,passerelle] [--set field=value]… [--parent L3] [--id AB-1.2 [--under AB-1]]` | add a lot or a sub-task, print its id (`--set`: the value of an [extension field](#extension-fields-planextras-l464) declared by `plan.extras`, refused on a sub-task; `--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 full spec step of `orchestrate` (L209), never inferred from the title; a visible lot above 0.1 day with `component`, `journey` or no `screen:` plays the light mockup (L459); `--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
+ | `raf add "title" --id <id> [--under <lot>]` · `raf estimate <id> <days>` | free identifiers and flat sub-lots in a writable plan (L465, `plan.idPattern`, below). `--id` gives the lot an identifier of the project's own (`AB-1.2`) instead of the generated `L<n>`; `--under` makes it a sub-lot (`parent: <lot>` written after `title:`; the parent must exist, archived included: `lot parent inconnu : <id>`). Both are refused with `--parent` (which adds a sub-task) and `--id` without `plan.idPattern`. `raf estimate` replaces `estimate:` of a lot of any status, archived included (days > 0 written in decimal, else `estimation invalide : <value typed>`: `0x10`, `1e1`, `abc`, `.5` are refused, and the message quotes what was typed (L535); a sub-task is refused) |
56
57
  | `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
- | `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
+ | `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) in full; `component` and `journey` get the [light mockup](orchestrate.md#the-light-mockup-l459) when the lot is visible and above 0.1 day); refused on a lot without `visible:` (like `raf add --screen`) and on a sub-task; `none` removes the key and leaves `visible:` alone |
58
59
  | `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) |
59
- | `raf spec <id> on\|off` | set or remove `spec:` on an existing lot (a lot that changes a behaviour, for the back-end spec step of `cadence orchestrate`, see [The spec step of a lot with `spec: true`](orchestrate.md#the-spec-step-of-a-lot-with-spec-true)); refused on a sub-task; `off` is refused on a lot that has `screen: page` (the page implies the spec: remove `screen:` first) and `on` there only says so and changes nothing; on `component` and `journey` (ordinary path since L209) both work and set or remove the back-end `spec:`. `raf spec` only takes `on`/`off`: `cadence spec check\|qa <fiche.yaml>` keeps its own subcommands. `raf check` reports a `spec:` that is neither `true` nor `false` (`spec : true ou false attendu`) |
60
+ | `raf spec <id> on\|off` | set or remove `spec:` on an existing lot (a lot that changes a behaviour, for the back-end spec step of `cadence orchestrate`, see [The spec step of a lot with `spec: true`](orchestrate.md#the-spec-step-of-a-lot-with-spec-true)); refused on a sub-task; `off` is refused on a lot that has `screen: page` (the page implies the spec: remove `screen:` first) and `on` there only says so and changes nothing; on `component` and `journey` both work and set or remove the back-end `spec:` (with `spec: true` the lot plays the back-end spec chain, without it a visible lot above 0.1 day plays the [light mockup](orchestrate.md#the-light-mockup-l459), L459). `raf spec` only takes `on`/`off`: `cadence spec check\|qa <fiche.yaml>` keeps its own subcommands. `raf check` reports a `spec:` that is neither `true` nor `false` (`spec : true ou false attendu`) |
60
61
  | `raf uses <lot> [<resource>…]` | replace the `uses:` list of a lot of any status (`done` and `dropped` included) by the names given (duplicates removed, order kept); with no name, remove the key. Prints nothing. A name is a word of lowercase letters, digits, `-` and `_` (else `ressource invalide : <name> (lettres minuscules, chiffres, - et _)`, plan unchanged); a sub-task is refused (`uses se pose sur un lot, pas sur une sous-tâche : L1/t1`); an unknown lot is `lot inconnu : <id>`. A name not yet declared is accepted: `raf check` refuses it (L251) |
61
62
  | `raf move <id> --before\|--after <id>` | reorder a lot in the plan file (L400): `<id>` is placed right before or right after the other lot, the others keep their order, and the lot travels with all its keys, its sub-tasks and its comments. Only among siblings: a lot among lots, a sub-task (`L1/t1`) among the sub-tasks of its own lot (`move : L2 et L1/t1 n'ont pas le même parent …`, plan unchanged). Exactly one of `--before` / `--after`, one id (else `usage : raf move <id> --before <id> \| raf move <id> --after <id>`); a lot placed where it already is, or an unknown id (`lot inconnu : <id>`), changes nothing. **Refused** on a read-only plan, plan kept by another tool (`plan en lecture seule : … — le modifier avec l'outil du projet`: reorder it with the project's own tool), on an archived lot (`move : L1 est archivé …`: the archive is presented in its former order and the order of the plan file never moves, see `raf archive`) and while a wave holds the repository (`move : orchestration en cours (vague …, pid …) — attendre …`: the lots of the wave rely on the order they read; the lock falls as soon as all of them are ready or handed back). The order is the order of the file, so it is the order `raf list`, `raf now`, the Gantt page and the draw of `cadence orchestrate` follow; the command only writes the plan, it does not commit it (`plan.commit` prints the command, as for every plan write) |
62
63
  | `raf add`, `raf note`, `raf done` during an integration (L425) | while a wave integrates a lot of the repository (the integration lock is held by a live process), these three commands write the plan as usual and print on stderr `avertissement : intégration en cours (vague …, pid …) — …`: the plan is a tracked file of the main tree, and an integration that sees it modified refuses its lot (`arbre du dépôt modifié`, 2026-10-29: a `raf add` of the lead during the integration of L416). Commit the plan right away. Exit code 0; nothing is printed in a lot's worktree (its plan is not the tree the integration checks) nor when the lock belongs to a dead process |
@@ -64,20 +65,21 @@ raf gantt # .cadence/gantt.html (next to the plan)
64
65
  | `raf public <id> "title"` · `raf public <id> --clear` | set, replace or remove the public title of a lot |
65
66
  | `raf start <id>` · `raf done <id> [--force]` · `raf drop <id> [--reason text]` | dated transitions (`done` refuses open sub-tasks unless `--force`, with the code-review gate active (`raf review enable`) a lot whose commits its review does not cover, **and a lot whose recorded review verdict says `non conforme` / `not compliant` even when it covers every commit** (L476: `non conforme : 1 bloquant` at the last commit no longer closes; `conforme après 1 correction` is compliant; redo the review with `raf review <id> "verdict"` after the fix, or `--force`), and a lot whose `acceptation-<lot>.json` is still `vert: false`, L366: closed like that it would lock every later wave of the repository, see `cadence spec green`; with `--force` it only warns on stderr. Like every `raf` command it only writes the plan file and **never commits** it: when the plan or a file `plan.onWrite` produces is left with changes, `done`, `ux <lot>` and `review <lot>` print the `git add` / `git commit` command that takes them, the subject from the `plan.commit` template, L371) |
66
67
  | `cadence spec green <lot>` | L366: run the dedicated acceptance command (`orchestrate.accept`) on a lot driven or closed by hand; green, set `vert: true` in its `acceptation-<lot>.json` and commit that file alone (subject `chore(<lot>): acceptation verte, vert: true posé par cadence spec green` or the `plan.commit` template; the resealed tests are listed in the commit body, never in the subject), resealing the fingerprints of the listed tests refined since the red commit (journal `resceaux`) so the lock goes quiet; a listed test changed but not committed is refused. Red: exit 1, nothing changed. A lot already `vert: true` whose tests lack fingerprints (L526) is replayed and, green, sealed (subject `chore(<lot>): empreintes de l'acceptation posées par cadence spec green`). Refused for a `todo` lot, during a wave, and while an unfinished wave keeps a lot of the repository open; see [orchestrate](orchestrate.md) |
68
+ | `raf status [<id> <state> ["message"] \| <id> --back ["message"]]` | the project's **detailed states** (L463, `plan.states`, [below](#detailed-states-planstates-l463)): sets the `state:` of a lot under the guard of `plan.transitions` and notes the message (`état bloque : attend la passerelle`); the base status is derived from the state — a `todo` lot moved to a `doing` state starts (`started:` set), `doing` → `todo` is done here too (so a blocked state of base `todo`, or the return `--back` to a `todo` state, works; `started:` is removed) under the gate of `raf todo`: refused as soon as work commits cite the lot (`L1 a 1 commit(s) qui le citent : le remettre en attente perdrait leur lien — un état doing (raf status L1 <état>), ou raf drop L1`), so a lot with work never goes back to `todo`, where `raf check` would refuse it and a wave could take it again; any other change of base status goes through its own command and gates (`raf done`, `drop`, `todo`; refused with the command to use). Entering the `plan.blockedState` remembers the state before in `state_before:`, `--back` returns to it; with no argument it lists the states with their base status, their number of lots and their transitions. Refused without `plan.states`, on a sub-task, on an unknown state, on the state the lot already has |
67
69
  | `raf todo <id> [--reason text]` | put a started lot back to `todo` (`doing` → `todo`, `started:` removed, dated note « remis en attente : reason »): refused when work commits cite the lot (plan-only and version commits do not count, as `raf commits`), or on a sub-task; sub-tasks and other keys are left as they are. **Reopening** (L396): on a `done` or `dropped` lot, `raf todo` is THE command — never the YAML — that reopens it (`→ todo`, `finished:` removed, `started:` kept so its commits stay its own, dated note « rouvert (était done) : reason »); `raf start`/`raf done`/`raf drop` on a closed lot say so (`L3 est done ; le rouvrir si c'est voulu : raf todo L3`). An archived lot reopened this way comes back into the plan file at that write |
68
70
  | `raf migrate [--dry-run]` | move `docs/plan/raf.yaml` to `.cadence/raf.yaml` and rewrite the readers of the old path in the repository, see [Moving the plan: `raf migrate`](#moving-the-plan-raf-migrate) |
69
71
  | `raf note <id> "text"` | dated note — keep decisions next to the work |
70
72
  | `--verbose` on `raf done`, `ux`, `review`, `note`, `move`, `public` · `raf hook post-commit --verbose` (L453) | those commands print no title of the lot they touch (nothing in the lead's context but `L12 → done` and the `plan non commité` command, which is unchanged); `--verbose` adds one line `L12 doing <full title>` (nothing for a sub-task). The post-commit hook warning `raf: L12 (doing) <title>` cuts the title at 60 characters (59 and `…` beyond; a title of 60 stays whole), `--verbose` on the hook gives it whole. `raf show`, `raf list`, `raf now` and the session tables are not concerned |
71
73
  | `raf title <id> "new title"` | replace the title of a lot of any status (`done` included) and add a dated note « titre remplacé : « old title » »; `raf now`, `raf show`, `raf list`, `session start` and the proposals read the new one. Refused on an empty or identical title, an unknown lot or a sub-task |
72
- | `raf archive [--before date] [--dry-run]` | move the `done` and `dropped` lots (those finished strictly before `--before`, when given; a lot with no `finished:` date stays then) out of the FILE `.cadence/raf.yaml` into `.cadence/archive/<year>.yaml`, the year of their end (L396). **The archive is a storage detail, invisible to every reader**: the loaded plan presents all the lots, active and archived, **in the order they had before the archiving** — each archived lot takes its place by number among the lots of the plan file (just before the first active lot with a greater number), the order of the plan file itself never moves — so `raf show`, `raf list`, `raf commits`, `raf check`, `raf now`, `raf gantt`, `cadence news`, `cadence perf`, `session start`, `lead tour`, `cadence ref coverage`, `cadence deliver`, the post-commit hook and `cadence orchestrate` print exactly what they printed before the archiving — nothing has to « also look in the archive », a lot id is never reused, and a commit or a News entry citing an archived lot is not « inconnu ». What changes is the file: the plan the sessions open stays short (the cadence plan weighed 559 KB, ≈ 150 k tokens) and the briefs of the implementation, the sheets, the code review and the pre-check tell the sessions never to open `.cadence/archive/`. **Writing**: every lot goes back to the file it came from — `raf note`, `raf review`, `raf ux`, `raf title`… on an archived lot rewrite its year file, the plan file is untouched; a lot reopened (`raf todo <id>`, or `status: doing` set by hand in a year file) comes back to the end of the plan file at the next write, so the archive only ever holds `done` and `dropped` lots. **Lossless, whatever fails**: the year files are written before the plan file (should the plan then fail to write, a moved lot is at worst duplicated — which the next load refuses by name — never lost), and any exception during the write (`EACCES` on a read-only file, a full disk, a `plan.onWrite` command that fails) puts the plan, the year files and the declared files back as they were — a year file born of that write disappears — and the error says so (`écriture du plan refusée (EACCES, …) — plan et archive inchangés`). **Guards**: a closed lot with an open gap (what `raf check` signals — code review, UX review, docs.sync, News entry…) stays in the plan with the gap as its printed reason (`L1 reste dans le plan : écart ouvert — L1 est visible et terminé sans entrée Nouveautés …`); a lot named in `after:` by another, or counted by a `gate:`, is archived like any other — the readers see the archive, so the dependency and the count read the same. A same id found in two files (plan and archive, or two years) is a named error that stops every command (`identifiant en double : L1 est dans .cadence/archive/2025.yaml et dans .cadence/raf.yaml`) until one copy is removed by hand — never a silent choice of one copy. `--dry-run` lists without writing; `--before` takes `YYYY-MM-DD`; refused on a read-only plan (its tool keeps its own history) and while the plan is still at the legacy `docs/plan/raf.yaml` (the archive would land under `docs/`, published, and `raf migrate` would not move it: `raf migrate` first, the refusal says so). For `cadence orchestrate`, the year files are plan files like `.cadence/raf.yaml`: a session that commits one has « touché le plan ». Like every plan write, it is not committed: the command to commit the plan and the archive files together, at explicit paths, is printed (`plan.commit` template, action `N lot(s) archivé(s)`); replaying moves nothing twice. The archive files are kept with the plan: touching them is not working on a lot. **The published plan**: a generator run by `plan.onWrite` (below) that reads only the file `.cadence/raf.yaml` publishes a plan without the archived lots; `raf archive` says so on stderr when `plan.onWrite` is declared, the generator must also read `.cadence/archive/*.yaml` (key `lots`, same lot format as the plan) |
74
+ | `raf archive [--before date] [--dry-run]` | move the `done` and `dropped` lots (those finished strictly before `--before`, when given; a lot with no `finished:` date stays then) out of the FILE `.cadence/raf.yaml` into `.cadence/archive/<year>.yaml`, the year of their end (L396). **The archive is a storage detail, invisible to every reader**: the loaded plan presents all the lots, active and archived, **in the order they had before the archiving** — each archived lot takes its place by number among the lots of the plan file (just before the first active lot with a greater number), the order of the plan file itself never moves; under `plan.idPattern` (free ids such as `AB-1`, `X3.4`: the final number says nothing of the order) every archived lot, whatever its id (`L7` included), is archived with a `place:` key, the id of the lot that preceded it in the plan as presented, archived lots included (empty: it was first), so lots archived in different runs keep the plan's order, and comes back right after that lot (`place:` is removed when the lot is reopened, and the archived lots whose `place:` named it are re-pointed to the lot that preceded it: only the reopened lot moves, to the end of the plan). `place` is thus a key cadence writes on a lot: `plan.extras.place` is refused — so `raf show`, `raf list`, `raf commits`, `raf check`, `raf now`, `raf gantt`, `cadence news`, `cadence perf`, `session start`, `lead tour`, `cadence ref coverage`, `cadence deliver`, the post-commit hook and `cadence orchestrate` print exactly what they printed before the archiving — nothing has to « also look in the archive », a lot id is never reused, and a commit or a News entry citing an archived lot is not « inconnu ». What changes is the file: the plan the sessions open stays short (the cadence plan weighed 559 KB, ≈ 150 k tokens) and the briefs of the implementation, the sheets, the code review and the pre-check tell the sessions never to open `.cadence/archive/`. **Writing**: every lot goes back to the file it came from — `raf note`, `raf review`, `raf ux`, `raf title`… on an archived lot rewrite its year file, the plan file is untouched; a lot reopened (`raf todo <id>`, or `status: doing` set by hand in a year file) comes back to the end of the plan file at the next write, so the archive only ever holds `done` and `dropped` lots. **Lossless, whatever fails**: the year files are written before the plan file (should the plan then fail to write, a moved lot is at worst duplicated — which the next load refuses by name — never lost), and any exception during the write (`EACCES` on a read-only file, a full disk, a `plan.onWrite` command that fails) puts the plan, the year files and the declared files back as they were — a year file born of that write disappears — and the error says so (`écriture du plan refusée (EACCES, …) — plan et archive inchangés`). **Guards**: a closed lot with an open gap (what `raf check` signals — code review, UX review, docs.sync, News entry…) stays in the plan with the gap as its printed reason (`L1 reste dans le plan : écart ouvert — L1 est visible et terminé sans entrée Nouveautés …`); a lot named in `after:` by another, or counted by a `gate:`, is archived like any other — the readers see the archive, so the dependency and the count read the same. A same id found in two files (plan and archive, or two years) is a named error that stops every command (`identifiant en double : L1 est dans .cadence/archive/2025.yaml et dans .cadence/raf.yaml`) until one copy is removed by hand — never a silent choice of one copy. `--dry-run` lists without writing; `--before` takes `YYYY-MM-DD`; refused on a read-only plan (its tool keeps its own history) and while the plan is still at the legacy `docs/plan/raf.yaml` (the archive would land under `docs/`, published, and `raf migrate` would not move it: `raf migrate` first, the refusal says so). For `cadence orchestrate`, the year files are plan files like `.cadence/raf.yaml`: a session that commits one has « touché le plan ». Like every plan write, it is not committed: the command to commit the plan and the archive files together, at explicit paths, is printed (`plan.commit` template, action `N lot(s) archivé(s)`); replaying moves nothing twice. The archive files are kept with the plan: touching them is not working on a lot. **The published plan**: a generator run by `plan.onWrite` (below) that reads only the file `.cadence/raf.yaml` publishes a plan without the archived lots; `raf archive` says so on stderr when `plan.onWrite` is declared, the generator must also read `.cadence/archive/*.yaml` (key `lots`, same lot format as the plan) |
73
75
  | `raf show <id> [--notes]` | one lot: status, dates, `goal : …` right after the title when the lot has a `goal:` (native key or `plan.fields.goal`, L272: the objective that replaces the title in the `orchestrate` briefs), `after`, public title, then for a visible lot two stable lines — `visible : oui` (followed by `screen : …` when the lot has one) and `ux : <verdict>` or `ux : absent` (the `raf ux` verdict, L439: what the `livreur` agent reads before closing a visible lot; a lot that is not visible prints neither line), `spec`, `uses : banc, passerelle` when the lot has `uses:`, dated notes in order, then the counted commits (as `raf commits`, neighbouring repositories included); `--notes` prints the notes alone |
74
76
  | `raf commits <id>` | the commits counted for a lot (the set the code review gate uses), one `<sha> <subject>` per line, oldest first; a lot that declares `repos:` ([neighbouring repositories](orchestrate.md#a-lot-whose-work-is-in-a-neighbouring-repository)) gets, after them, one `dépôt <path> :` section per neighbour with the commits there that cite the lot and fall within the lot's period (`started` to `finished`) and, when the lot declares a `cite:` for that neighbour, contain that string (`aucun commit du lot`, or `introuvable` for a path that is not there) |
75
77
  | `raf now` | what to do next |
76
- | `raf list [--status s]` | flat list |
78
+ | `raf list [--status s] [--json]` | flat list; `--json` prints the lots as a JSON array (L464, [extension fields](#extension-fields-planextras-l464)) |
77
79
  | `raf docs-ok <lot> --reason text` | acknowledge the `docs.sync` gap of a lot (a document behind its commits, `raf check` red) when the documentation really stays true: a `docs_ok: { date, reason }` key on the lot, **the reason is required** (refused without it, for an unknown lot or for a sub-task); `raf check` and `cadence lead tour` no longer count the lot, `raf show` prints it, and `cadence orchestrate` neither calls the librarian nor holds the lot back for it. Commit the plan with it; on a read-only plan (kept by another tool) the key goes to `.cadence/docs-ok.yaml` instead, and that file is committed (L386) |
78
80
  | `raf ignore <sha> \| "exact subject" [--reason text]` | acknowledge a commit without a lot (tooling chore, a plan commit citing an unknown id) or a commit that cites known lots without working on them (a lead's plan commit creating lots, a setting cited in parentheses): it then counts for none of them — not started, not active, not to review (`raf commits` omits it) — without rewriting history: a dated, reasoned line in the plan's `acknowledged:` section; a sha is exact, a subject covers every commit carrying it; exactly one commit argument, the reason goes through `--reason "text"` (`raf ignore 1a2b3c4 "tooling"` is refused with « un seul commit attendu ; la raison se passe par --reason "texte" », exit 2) |
79
81
  | `raf check --ignored` | list the acknowledged commits with their date and reason |
80
- | `raf check [--since date] [--idle 7]` | since the plan's adoption date by default (a visible lot without a public title is only a `⚠` warning: it never changes the exit code): commits without a lot (commits touching only plan files, or only version fields, `CHANGELOG.md`, the README's « What's new » section and `docs/whats-new.md` are exempt), unknown ids, `todo` lots that already have commits, idle lots (an open lot whose sub-lots, entries carrying `parent:` in a plan kept by another tool, have a recent commit or are in progress is not idle: L321), `done` lots with open sub-tasks, bad or circular dependencies, and an open lot titled « Revue UX — <screen> » without `visible: true` (`ux-review-not-visible`, an error: such a lot goes through precheck → implement → review with no UX step, so the screen is never reviewed — finance L32 on 2026-10-23; L271; the message names the fix, `raf visible <id> on`, L273; on a read-only plan, plan kept by another tool, it never names a `raf` command, which would refuse: with `plan.fields.visible` mapped it says to set `visible:` with the project's tool, without it it says the plan carries no `visible`, to map the field in `cadence.yaml` (`plan.fields.visible`) if the project's tool writes it, and that otherwise the UX review of that screen happens outside orchestrate, L321) |
82
+ | `raf check [--since date] [--idle 7]` | since the plan's adoption date by default (a visible lot without a public title is only a `⚠` warning: it never changes the exit code): commits without a lot (commits touching only plan files, or only version fields, `CHANGELOG.md`, the README's « What's new » section and `docs/whats-new.md` are exempt), unknown ids, `todo` lots that already have commits, idle lots (an open lot whose sub-lots, entries carrying `parent:` (native plan, `raf add --under`, L465, or a plan kept by another tool), have a recent commit or are in progress is not idle: L321), `done` lots with open sub-tasks, bad or circular dependencies, and an open lot titled « Revue UX — <screen> » without `visible: true` (`ux-review-not-visible`, an error: such a lot goes through precheck → implement → review with no UX step, so the screen is never reviewed — finance L32 on 2026-10-23; L271; the message names the fix, `raf visible <id> on`, L273; on a read-only plan, plan kept by another tool, it never names a `raf` command, which would refuse: with `plan.fields.visible` mapped it says to set `visible:` with the project's tool, without it it says the plan carries no `visible`, to map the field in `cadence.yaml` (`plan.fields.visible`) if the project's tool writes it, and that otherwise the UX review of that screen happens outside orchestrate, L321) |
81
83
  | `raf gantt [-o file]` | standalone Gantt page |
82
84
  | `raf hook pre-push` | called by the temporary `pre-push` hook that `cadence orchestrate` installs (not by `raf hook install`): reads git's lines on the standard input and exits 3 when the push carries a commit of a lot of the live wave that is not ready, naming the lot and the safe `git push <remote> <sha>:<remote branch>`, or when the commits of a not-ready lot cannot be read (the guard of `deliver --sha`: the push is then unverifiable, the lot is named); exits 3 as well, with or without a live wave, when the project declares a gate (`orchestrate.test` or `orchestrate.build`) and the local sha of a pushed branch has no green verdict of `cadence verify --gate` (L426; a commit that changes only the plan takes the verdict of its parent, L432: « aucun verdict de la porte » or red, naming `cadence verify --gate --sha <sha>`; `CADENCE_PUSH_UNGATED=1` in the environment of the `git push` lets it through and says so); exits 0 when nothing is to refuse |
83
85
  | `raf hook install` | add the post-commit hook (read-only, never blocks) and the pre-commit hook (does nothing unless `hook.autostart` says so, see below) |
@@ -215,6 +217,42 @@ migrate:
215
217
  keep: [docs/specs/**, test/legacy-plan.test.ts] # cite docs/plan/raf.yaml without reading the plan
216
218
  ```
217
219
 
220
+ ## Detailed states: `plan.states` (L463)
221
+
222
+ A project that tracks more than `todo`, `doing`, `done` and `dropped` (« tested », « delivered », « blocked »…) declares its own states in `cadence.yaml`. The base status stays the four above — every gate of cadence (`raf done`, reviews, UX, `raf now`, the Gantt) reads only it — and each state names the base status it belongs to:
223
+
224
+ ```yaml
225
+ plan:
226
+ states: { a_faire: todo, en_cours: doing, bloque: doing, termine: done, livre: done, abandonne: dropped }
227
+ transitions: # optional: without it nothing is guarded
228
+ a_faire: [en_cours, bloque, abandonne]
229
+ en_cours: [bloque, termine, abandonne]
230
+ bloque: [en_cours, abandonne]
231
+ termine: [livre] # a state with no entry is terminal once `transitions` is declared
232
+ doneState: termine # what `raf done` sets (default: the first done state)
233
+ blockedState: bloque # `raf status <lot> --back` returns from it
234
+ ```
235
+
236
+ `states` is an ordered object, state → base status, and must hold at least one `todo`, one `doing` and one `done` state. The state is written as `state:` right after `status:` (and `state_before:` while blocked). `raf start`, `raf done`, `raf drop` and `raf todo` set the state of their status themselves (`doing` → the first `doing` state, `done` → `doneState`, …) and obey `plan.transitions` too — refused with the allowed states, `--force` passes (`raf todo`, the reopening, is not guarded). A lot with no `state:` (written before the declaration) is read in the default state of its status. `raf check` reports a `state:` that is not declared or whose base status contradicts `status:`. `raf show` prints `état :`. `plan.states` does not go with a plan held by another tool (`lots`, `fields`, `statuses`, `estimates`): its states are its own.
237
+
238
+ ## Extension fields: `plan.extras` (L464)
239
+
240
+ A project that sorts its lots by something cadence does not know (a theme, an owner, the path of a sheet) declares the field in `cadence.yaml`, and cadence then keeps it, checks it and shows it:
241
+
242
+ ```yaml
243
+ plan:
244
+ extras:
245
+ theme: { enum: [infra, ui, data] } # only these values
246
+ owner: { default: claude } # what a lot without the key is read as
247
+ fiche: {} # any non-empty text
248
+ ```
249
+
250
+ - **Declaration.** A name is lowercase letters, digits and `_`, starting with a letter, and is not a key cadence uses on a lot (`status`, `estimate`, `after`, `notes`, `tasks`, `uses`, `repos`, `place`…). `enum` is a non-empty list of distinct texts; `default` is a non-empty text, one of the `enum` values when there is one. Anything else is refused, naming the key (`cadence.yaml : plan.extras.theme.color inconnu`). `plan.extras` is refused together with a plan kept by another tool (`plan.lots`, `plan.fields`…, read-only): cadence writes no field there.
251
+ - **On the lot.** The field is a plain key of the lot, a text (`theme: ui`). A key that is **not** declared is neither read nor checked, and stays in the file as written, as do the declared ones: every `raf` write (start, note, done, title, archive…) edits the lot in place.
252
+ - **`raf check`.** A declared field whose value is not a non-empty text or is outside `enum` is a `bad-field`: `L12 : theme « zzz » hors de enum (infra, ui, data)`. A lot without the key is fine; with a `default` it is read with the default (nothing is written to the file, so changing the `default` changes every lot that does not carry the key).
253
+ - **`raf add "title" --set theme=ui`** writes the key on the new lot (before `created:`); `--set` can be repeated, the value is cut at the first `=` (`--set fiche=docs/a=b.md`). Refused, with nothing written: a field that is not declared (the message lists the declared ones; without `plan.extras`, it says so), a value outside `enum`, `--set theme` or `--set theme=` without a value, the same field twice, and `--set` with `--parent` (a sub-task has no field).
254
+ - **`raf show`** prints one `field : value` line per field the lot carries or receives by default. **`raf list --json`** prints the lots (filtered by `--status`) as one JSON array with the fields of the lot under the names of the plan file (`docs_ok`, not `docsOk`; `problems`, the diagnostics of `raf check`, is not exported), the extension fields under `extras` (absent when the plan declares none or the lot has none). A field is set on an existing lot by editing the file; there is no `raf` command for it yet.
255
+
218
256
  ## Plan file
219
257
 
220
258
  ```yaml
@@ -261,6 +299,23 @@ plan:
261
299
  files: [frontend/public/plan-data/plan.json]
262
300
  ```
263
301
 
302
+ ### Free identifiers and flat sub-lots (`plan.idPattern`, L465)
303
+
304
+ A plan that keeps raf's format can use identifiers of its own (`AB-1.2`, `X3.4`, `E-GL5`) next to the generated `L<n>`.
305
+ The project declares their shape in `cadence.yaml`, as a regular expression **without anchors** (raf anchors it):
306
+
307
+ ```yaml
308
+ plan:
309
+ idPattern: '[A-Z]{1,3}-?\d+(?:\.\d+)*'
310
+ ```
311
+
312
+ - The key is refused at read time when it is not a text, is empty, starts with `^` or ends with `$`, accepts the empty identifier, is not a valid expression, or uses the reserved group names `id` and `sub`; the error names `plan.idPattern`.
313
+ - `raf add "title" --id AB-1.2` writes that identifier. It must match the pattern in full, contain no `/` (reserved to sub-tasks) and not exist yet, archived lots included. Without `--id`, ids stay `<prefix><n+1>`, whatever the free ids in the plan.
314
+ - `raf add "title" --id AB-1.2 --under AB-1` writes `parent: AB-1` on the lot: a sub-lot **laid flat** in `lots:`, whose id does not start with its parent's. It keeps its own dates, notes, estimate and status; `raf check` counts its commits for the idleness of a parent in progress.
315
+ - Commit messages: with the key, the ids cited in a message are `<prefix>\d+` **or** the pattern, point and digits included (`AB-1.2`, not `AB-1`), with an optional sub-id after a slash: `X7/t2` is the sub-task `t2` of `X7`; any other sub-id (`X7/t1-fusion`) cites the lot `X7`. An id is not read inside a word, after a `/`, or when followed by a dot and a word character (`X3.x`); a closing dot (« see X3. ») is fine. A `<prefix>\d+` id keeps the guard it has without the key (`feat(L3-L5)` cites L3 and L5, `release-L3` cites L3); an id that comes from the pattern is stricter and is not read after a `-` or a `.`, nor before a `-` (`AB-1-x`). So `raf commits`, the review gate and `raf check` see the work of lots with free ids. Without the key nothing changes: only `<prefix>\d+` and `/t<n>` are recognised.
316
+ - `raf estimate <id> <days>` is the command that changes the estimate of an existing lot.
317
+ - A `parent:` written by hand that is not a text is ignored and reported among the lot's problems; an unknown parent is not checked.
318
+
264
319
  ### Regenerate the published copy on every write (`plan.onWrite`, L346)
265
320
 
266
321
  Declaring the published file is not enough when it is generated: a hand-regenerated
@@ -312,7 +367,7 @@ plan:
312
367
  fields: # raf field: key in the file (a list = first one present)
313
368
  title: titre
314
369
  public: titre_public # the lot's title for the public; read when it is text, else ignored
315
- screen: ecran # page, component or journey; only on a visible lot (only `page` enters the spec step)
370
+ screen: ecran # page, component or journey; only on a visible lot (only `page` enters the full spec step; the others, if visible and above 0.1 day, the light mockup)
316
371
  spec: fiche # true or false: the lot changes a behaviour
317
372
  status: etat
318
373
  estimate: effort
package/docs/spec.md CHANGED
@@ -47,13 +47,16 @@ error output, nothing on the standard one, and exits 1. The derivation is built
47
47
 
48
48
  ## Spec step (design, first steps delivered)
49
49
 
50
- For a visible lot that adds a page (`screen: page`; a component or a journey follows the ordinary path since L209), `orchestrate` gets a step
50
+ For a visible lot that adds a page (`screen: page`), `orchestrate` gets a step
51
51
  before the code: a static HTML mockup in the project's own style (1440 and 390 px; empty, loading and
52
52
  error states) and a machine-readable screen sheet (fields, numbered rules `R1…` each marked *sourced*
53
53
  or *hypothesis*, actions → API calls). The `ux-reviewer` agent reads the mockup before any code; the
54
54
  acceptance tests are written from the sheet, red, by a session other than the implementer's; the
55
55
  implementation gets the sheet, the code review checks rule → test → green, the hypotheses go into the
56
- lot's news entry, and a human is asked only about a choice that is costly to undo. The design is in
56
+ lot's news entry, and a human is asked only about a choice that is costly to undo. A visible lot above 0.1 day
57
+ with `screen: component`, `journey` or no `screen:` (and no `spec: true`) plays a lighter version since L459: spec → mockup
58
+ of the touched states only (current screen and target), mockup review, then the code, with no `accept` and a budget of
59
+ ordinary plus 450 k (1.05 M for a lot up to half a day), see [The light mockup](orchestrate.md#the-light-mockup-l459). The design is in
57
60
  `docs/superpowers/specs/2026-10-10-etape-spec-design.md` (with an example sheet and the plan of the
58
61
  lots that deliver it). Delivered so far: the sheet templates `templates/fiche.yaml` (screen) and `templates/fiche-back.yaml` (a lot without a screen: `sujet`, `cas`, `regles`, `contrats`, `donnees`), `cadence spec check`
59
62
  (the sheet's invariants) and `cadence spec qa` (the screen's `docs/qa/expectations.md` section, derived
package/docs/whats-new.md CHANGED
@@ -4,6 +4,9 @@
4
4
 
5
5
  ## In two lines
6
6
 
7
+ - **1.42.1**: republishes 1.42.0, whose npm publication failed on two tests of the CI clone (no `main` branch, a draw-order probe that depended on timing); same features.
8
+ - **1.42.0**: free plan identifiers (`plan.idPattern`, `raf add --id`, `raf estimate`); `--integrate` accepted while a wave runs; fair slot sharing between waves; the gate notices code that reads the plan.
9
+ - **1.41.0**: richer plans (detailed states, extension fields); a light mockup step for visible lots that are not pages; `verify --sha` clears a red delivery; the quality ratchet watches its tools' config files.
7
10
  - **1.40.0**: `docs/concepts.md`, the notions of cadence for a human; a proposed sub-task maybe already done is flagged; a warning when the memory index loaded every turn grows too big.
8
11
  - **1.39.0**: `orchestrate --continue` fills free slots by priority, one worktree per lot when the cap allows (issue #21); waves show their cost in euros before and after.
9
12
  - **1.38.1**: `spec green` seals a lot closed at `vert: true` without fingerprints (issue #20); `deliver`, `raf move`, `spec reseal` and `spec green` refuse cleanly during a local task.
@@ -69,6 +72,12 @@ Each is a paragraph in [docs/whats-new.md](whats-new.md) and a full section in [
69
72
 
70
73
  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).
71
74
 
75
+ **1.42.1**: republishes 1.42.0, whose npm publication failed on two tests only (the ratchet test assumed a local `main` branch, the `--priority` probe read a timing-dependent order); no behaviour changes.
76
+
77
+ **1.42.0**: plans can use your own identifiers. `plan.idPattern` accepts free ids (`AB-1.2`) in a writable plan, with `raf add --id`, flat sub-lots under a parent with `raf add --under`, commit references that follow the pattern, and `raf estimate <id> <days>` (L465). `cadence orchestrate --resume --wave <wave> --integrate <project:lot>` is now accepted while the wave still runs: a lot reviewed `conforme` is integrated without waiting for the end of a long `--continue` wave (L532, `docs/orchestrate.md`). Waves sharing the session slots take a freed slot in a common, fair order instead of letting one `--continue` wave starve a review (L531). `cadence verify --gate` replays the gate when code quotes the plan's path while `gate.readsPlan` is absent (L482, `docs/deliver.md`). `src/cli.ts` is split into one module per family of commands, with no behaviour change (L488, L485), and `raf estimate` rejects a non-number cleanly (L535).
78
+
79
+ **1.41.0**: plans can say more without leaving cadence. `plan.statuses` declares the detailed states of a project with their allowed transitions, and `raf status <lot> <state>` writes them; `plan.extras` declares extension fields, validated and kept on every write, set with `raf add --set key=value`; both live together in one plan (L463, L464, `docs/raf.md`). A visible lot that is not a whole page (a component, a touch-up, a UX review of a screen) now gets a light mockup — the current screen and the target, the states it touches — reviewed by the `ux-reviewer` before the code, then checked for conformity after; a lot already entered with a sealed acceptance keeps its full chain (L459, `docs/spec.md`). `cadence verify --sha` green after a red delivery of the same sha records it in the deliveries journal, so the red line goes away without delivering again; it no longer stops on a local task of the lead or an unreadable plan (L435, `docs/deliver.md`). The quality ratchet watches every file its tools read (nested `.gitignore`, `vitest.config.*`, `package.json` entries, `tsconfig.json`), so a configuration change cannot loosen it unnoticed (L479, `docs/qualite.md`).
80
+
72
81
  **1.40.0**: a guide for humans, `docs/concepts.md`, linked at the top of the README, explains each notion of cadence in a few sentences, in the order you meet them: plan and lot, verdicts, session and wave, the steps of a lot and who plays each, the test gate, worktree and integration, « livrable jusqu'à » (L460). In the final table and `--status --detail`, a proposed sub-task whose cited file was changed by a commit of the lot after the review that proposed it is marked `— peut-être déjà traitée (<sha>)`, so a review no longer feeds the next one with work already done (L422). `cadence session close` and `cadence lead tour` warn when the Claude Code `MEMORY.md` index, loaded at every turn, outgrows a size threshold (`memory.indexMaxBytes`), and propose to group its dated entries behind one line; `cadence config set` reads that key back like the others, so a wrong value stops with nothing written (L442). A measure of the earlier change to the passes, read on two windows of `cadence perf`, is recorded (L430).
73
82
 
74
83
  **1.39.0**: free slots no longer stay empty (GitHub issue #21, L527, `docs/orchestrate.md`). With `--continue`, once the order is agreed (`--priority` or `priority:` of the parent `cadence.yaml`), the wave starts the next ready lot in each slot as soon as one frees up — a lot handed back at its pre-check frees its slot in seconds —, in priority order, within the session cap, the shared resources and one session per repository or one worktree per lot, and the journal says so. In a repository with `orchestrate.worktrees: true` and a cap above 1, every lot gets its own worktree, a lot launched alone or brought by `--add` included, so a second lot of the same repository plays in parallel instead of waiting; `--dry-run --continue` now simulates the draws one by one, as the wave plays them. `cadence orchestrate --dry-run` also announces the cost in euros of each lot and of the wave beside its token budget, and the final table and `--status` show the real cost (L529, price grid `perf.prices`). `cadence release` reads the « In two lines » section of `docs/whats-new.md` the way the test does, so a line too long or a duplicate is caught before the tag (L418), and a timing test that turned red under load in a fresh clone has a wide margin (L528).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sylad/cadence",
3
- "version": "1.40.0",
3
+ "version": "1.42.1",
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",
@@ -155,7 +155,7 @@ of the plan itself (section 2b), and the limits of section « Limits that always
155
155
  handed back ready (refused, review not compliant after the correction passes, red delivery, blocking QA finding) is
156
156
  not chained over: it is reported, and the chain goes on with the lots that do not depend on it.
157
157
 
158
- **A lot handed back despite the escalation** (L337). When the project declares `orchestrate.escalation: { model }`, the wave itself plays one correction and one fresh review on that model before handing a lot back for a non-compliant review or red tests: do not take such a lot up by hand on a model of your own choice first, and do not replay the escalation yourself. The table says `escalade <model> : …` under the lot. A lot handed back **despite** the escalation (`rendu malgré l'escalade`) is for the human or for an arbitration (the sheet, the brief or the lot is at fault, not the model): report it with the remaining findings and go on with the other lots. `escalade … non jouée` means the lot's budget did not cover it: the lot is yours, with its findings. **Taking such a lot up** (handed back for its budget or a non-compliant review, L370): fix it in its kept worktree (the final table gives the path; a fix subagent there, under `cadence lead hold`), then run `raf review <lot> "conforme : …"` **in that worktree** and commit its plan there — the review is read from the worktree's plan, not from the main repository's, and it must come after the last work commit of the lot —, then `cadence orchestrate --resume --wave <wave> --integrate <project>:<lot>`: the program rebases, replays the checks, keeps your verdict (or makes a short review of the rebased diff) and advances the repository's branch. Do not integrate it by hand any more (L367, 26-10), and do not record that review in the main repository's plan: `--integrate` would not see it and would keep refusing (« pas rendu à l'étape d'intégration »). `escalade … session escaladée sans résultat` means the escalated session itself failed (often a model the account does not have): the model never judged the lot, fix the key or take the lot up, do not read it as the lot's fault. A line `en cours` is a lot still running; `engagée, lot rendu avant le verdict du modèle` is a lot withdrawn, failed by an error or stopped by an incident during the escalation: the model did not judge it, read the lot line for the reason. Without the key, nothing changes; the model has no default, as the account may not have the strongest one.
158
+ **A lot handed back despite the escalation** (L337). When the project declares `orchestrate.escalation: { model }`, the wave itself plays one correction and one fresh review on that model before handing a lot back for a non-compliant review or red tests: do not take such a lot up by hand on a model of your own choice first, and do not replay the escalation yourself. The table says `escalade <model> : …` under the lot. A lot handed back **despite** the escalation (`rendu malgré l'escalade`) is for the human or for an arbitration (the sheet, the brief or the lot is at fault, not the model): report it with the remaining findings and go on with the other lots. `escalade … non jouée` means the lot's budget did not cover it: the lot is yours, with its findings. **Taking such a lot up** (handed back for its budget or a non-compliant review, L370): fix it in its kept worktree (the final table gives the path; a fix subagent there, under `cadence lead hold`), then run `raf review <lot> "conforme : …"` **in that worktree** and commit its plan there — the review is read from the worktree's plan, not from the main repository's, and it must come after the last work commit of the lot —, then `cadence orchestrate --resume --wave <wave> --integrate <project>:<lot>`: the program rebases, replays the checks, keeps your verdict (or makes a short review of the rebased diff) and advances the repository's branch. The same command works while the wave is still running (L532): it drops the request in the wave's queue (`intégration déposée`), which takes it between two steps, so a long `--continue` wave does not hold the lot back. Do not integrate it by hand any more (L367, 26-10), and do not record that review in the main repository's plan: `--integrate` would not see it and would keep refusing (« pas rendu à l'étape d'intégration »). `escalade … session escaladée sans résultat` means the escalated session itself failed (often a model the account does not have): the model never judged the lot, fix the key or take the lot up, do not read it as the lot's fault. A line `en cours` is a lot still running; `engagée, lot rendu avant le verdict du modèle` is a lot withdrawn, failed by an error or stopped by an incident during the escalation: the model did not judge it, read the lot line for the reason. Without the key, nothing changes; the model has no default, as the account may not have the strongest one.
159
159
 
160
160
  **The threshold.** Before every new wave, read the context of the lead session with `cadence session context`: the
161
161
  `cadence-hud` mod publishes the context of each session, one file per session named after its id, and the command reads the
@@ -5,7 +5,7 @@ Read the lot, its notes and sub-tasks in the plan (`.cadence/raf.yaml`, the lega
5
5
  {{spec}}
6
6
 
7
7
  What you produce, in `<dir>/<écran>/`:
8
- 1. `maquette.html`: static HTML + CSS, to the project's charter (reuse its variables, fonts and components; invent no style when an equivalent exists), no business JavaScript. Every state is an addressable section: `<section id="etat-vide">`, `etat-chargement`, `etat-erreur`, and `etat-charge` when the screen has data. Every field of the sheet carries `data-testid="<id of the field>"`.
8
+ 1. `maquette.html`: static HTML + CSS, to the project's charter (reuse its variables, fonts and components; invent no style when an equivalent exists), no business JavaScript. Every state the sheet covers is an addressable section: `<section id="etat-vide">`, `etat-chargement`, `etat-erreur`, and `etat-charge` when the screen has data (a light mockup covers only the states the lot touches, as said above). Every field of the sheet carries `data-testid="<id of the field>"`.
9
9
  2. The captures described above, one per state and per width, copied from the Playwright output directory of this wave into the folder (give a capture the absolute path of that directory, as the Playwright paragraph says, then copy it).
10
10
  3. `fiche.yaml`, in the format of the template below. Check it with `cadence spec check <fiche>` until it is valid, and derive the QA expectations with `cadence spec qa <fiche>` only if the lot asks for it.
11
11
 
@@ -18,7 +18,7 @@ Sheet rules:
18
18
  - Check every date in the sample data of the mockup before keeping it: compute its weekday (a command such as `date -d 2026-09-03 +%A`, or a script), never write it from memory — a « Wed 03/09 » that is a Thursday sends the mockup back for nothing. The same goes for any figure that must add up (a score and its result, a total and its parts).
19
19
  - Expose the messages exactly as the screen shows them; the message of a rule is visible in the state its `etat` names.
20
20
  - A rule you invent is not a free choice: **a hypothesis whose `si_faux` involves an expensive-to-undo choice is a question, not a hypothesis.** The four expensive categories: a data model or storage (key, migration, user data created once shipped); a public or shared API contract, or an already published route / URL; a destructive or irreversible action (deletion, sending, payment); a rule that contradicts an existing sourced rule. In those cases do not write the hypothesis: stop and put the question under "questions" (the lead answers and the step is resumed). Everything else (wording, order of the fields, error state, spacing) is a written hypothesis, cheap to correct later.
21
- - If, after reading the lot and the code, you find that the lot changes NO screen (no new page), write one line with the reason in `sousSeuil`, create no mockup and no sheet, and finish: the lot then follows the usual path.
21
+ - `sousSeuil` is only for a lot that changes nothing the user can see: if, after reading the lot and the code, you find that it changes no screen, no component, no state, no text and no style (an internal rename, a refactoring with the same rendering), write one line with the reason in `sousSeuil`, create no mockup and no sheet, and finish: the lot then follows the usual path. A change to a component, a state, a text or a style of an existing screen is NOT under the threshold, even when it adds no page: write its mockup (the light one when this brief asks for it).
22
22
 
23
23
  Commit the spec with explicit paths (never `git add -A` or `commit -a`), a message that cites the lot (`spec({{lot}}): …`), the sheet, the mockup, the captures and `contraste.md` together, and leave the working tree clean. Do not implement the screen, do not write application code or tests, do not push, deliver, run `raf done`, `raf ux` or `raf review`.
24
24
  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.