@sylad/cadence 1.0.0 → 1.2.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.
Files changed (47) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +286 -22
  4. package/agents/acceptance-writer.md +21 -0
  5. package/agents/code-reviewer.md +8 -1
  6. package/agents/spec-writer.md +23 -0
  7. package/agents/ux-reviewer.md +20 -1
  8. package/bin/cadence.js +11 -1
  9. package/dist/audit.js +14 -2
  10. package/dist/cli.js +233 -18
  11. package/dist/config.js +46 -5
  12. package/dist/corrections.js +228 -0
  13. package/dist/lead.js +72 -19
  14. package/dist/news.js +54 -7
  15. package/dist/orchestrate/accept.js +389 -0
  16. package/dist/orchestrate/aval.js +65 -0
  17. package/dist/orchestrate/briefs.js +7 -1
  18. package/dist/orchestrate/command.js +70 -20
  19. package/dist/orchestrate/continue.js +1 -1
  20. package/dist/orchestrate/cycle.js +662 -24
  21. package/dist/orchestrate/fiche.js +22 -0
  22. package/dist/orchestrate/launch.js +17 -10
  23. package/dist/orchestrate/maquette.js +27 -0
  24. package/dist/orchestrate/sandbox.js +38 -0
  25. package/dist/orchestrate/schemas.js +17 -1
  26. package/dist/orchestrate/spec.js +197 -0
  27. package/dist/orchestrate/state.js +2 -2
  28. package/dist/orchestrate/table.js +2 -0
  29. package/dist/plan.js +79 -1
  30. package/dist/spec.js +457 -0
  31. package/package.json +4 -3
  32. package/skills/lead/SKILL.md +33 -8
  33. package/templates/acceptation-runner.mjs +61 -0
  34. package/templates/fiche-back.yaml +75 -0
  35. package/templates/fiche.yaml +41 -0
  36. package/templates/orchestrate/accept-back.md +16 -0
  37. package/templates/orchestrate/accept.md +16 -0
  38. package/templates/orchestrate/fiche.md +14 -0
  39. package/templates/orchestrate/fix-minors.md +1 -0
  40. package/templates/orchestrate/fix.md +1 -0
  41. package/templates/orchestrate/implement.md +1 -0
  42. package/templates/orchestrate/maquette.md +12 -0
  43. package/templates/orchestrate/review-small.md +1 -0
  44. package/templates/orchestrate/review.md +1 -0
  45. package/templates/orchestrate/spec-back.md +25 -0
  46. package/templates/orchestrate/spec.md +28 -0
  47. package/templates/orchestrate/ux.md +1 -0
@@ -8,7 +8,7 @@
8
8
  {
9
9
  "name": "cadence",
10
10
  "description": "Session start and close rituals driven by a versioned plan (raf), and deliveries proven by their effect. Needs the cadence CLI (npm i -g @sylad/cadence).",
11
- "version": "1.0.0",
11
+ "version": "1.2.0",
12
12
  "source": "./",
13
13
  "author": {
14
14
  "name": "Sylvain Ladoire"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cadence",
3
3
  "description": "A repo-native working method: session start and close rituals driven by a versioned plan (raf), deliveries proven by their effect, and three reviewer agents (UX, code, QA).",
4
- "version": "1.0.0",
4
+ "version": "1.2.0",
5
5
  "author": { "name": "Sylvain Ladoire" },
6
6
  "homepage": "https://github.com/Sylad/cadence",
7
7
  "repository": "https://github.com/Sylad/cadence",
package/README.md CHANGED
@@ -22,9 +22,25 @@ reports a page left empty or in error.
22
22
  And a second plugin, [`cadence-hud`](#cadence-hud): a status band above the Claude
23
23
  Code prompt that shows the session's context, quota, cost and the orchestrate waves running.
24
24
 
25
+ ### Spec step (design, first steps delivered)
26
+
27
+ For a visible lot that adds a page, a component or changes a journey, `orchestrate` gets a step
28
+ before the code: a static HTML mockup in the project's own style (1440 and 390 px; empty, loading and
29
+ error states) and a machine-readable screen sheet (fields, numbered rules `R1…` each marked *sourced*
30
+ or *hypothesis*, actions → API calls). The `ux-reviewer` agent reads the mockup before any code; the
31
+ acceptance tests are written from the sheet, red, by a session other than the implementer's; the
32
+ implementation gets the sheet, the code review checks rule → test → green, the hypotheses go into the
33
+ lot's news entry, and a human is asked only about a choice that is costly to undo. The design is in
34
+ `docs/superpowers/specs/2026-10-10-etape-spec-design.md` (with an example sheet and the plan of the
35
+ 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`
36
+ (the sheet's invariants) and `cadence spec qa` (the screen's `docs/qa/expectations.md` section, derived
37
+ from the sheet), see [spec](#spec) below, and the `spec` step of `orchestrate` itself (the `spec-writer` agent, the
38
+ render at 1440 and 390 px, the commit of the spec), see [The spec step](#the-spec-step-of-a-lot-with-screen) in `orchestrate`; the `accept` step (red acceptance tests and the lock that protects them), see [The accept step](#the-accept-step-red-acceptance-tests-and-their-lock); the UX review of
39
+ the mockup (the `ux-reviewer` agent in mockup mode), see [The mockup review](#the-mockup-review-before-any-code); and the downstream briefs (the sheet given to `implement`, rule → test → green in the code review, a light UX conformity pass, the `## Hypothèses` section of the news entry), see [The downstream briefs](#the-downstream-briefs-sheet-rule--test--green-conformity-hypothèses).
40
+
25
41
  ## What's new
26
42
 
27
- **1.0.0**: the first major release, a stable contract: the commands and options, the keys of `cadence.yaml`, the plan file and the names of the skills and agents follow semantic versioning, and the README's *Stability* section lists what is guaranteed and what is not (L164). **0.28.0**: `orchestrate.precheck: local` runs the « deliverable already present? » pre-check of `cadence orchestrate` on the local model (`claude-local`, Ollama), off the Anthropic quota, Sonnet staying the default and the fallback (L146); the `qa-reviewer` agent walks only the pages a lot touched, with a **Scope** line in its report (L123); the sub-tasks a review closes are also read in a lot's neighbouring repositories (L156) and a commit's sub-task list is read with the plan's left guard (L155); an unstable test is fixed (L90). **0.27.1**: `cadence orchestrate` no longer leaves a session's child processes alive: a dev server started in its own process group, or orphaned by a shell that exits (`nohup srv &`), is killed with the session through its process tree and its `CADENCE_SESSION` mark, a tmux server, `screen`, `gpg-agent` or `dirmngr` started on demand being spared; a session that exits with code 0 while a descendant holds its output open is no longer reported as « délai dépassé » (L83); the `ux-reviewer` and `qa-reviewer` agents carry the briefs' Playwright rule outside `cadence orchestrate` (L84). **0.27.0**: a compliant review of `cadence orchestrate` settles the open sub-tasks that commits of the lot cite (`feat(L3/t2): …`, comma lists included), closed in the same plan commit as the verdict or, on a read-only plan, returned as `[sous-tâche clore]` proposals, so `raf done` no longer refuses a lot over sub-tasks whose work is done; on a foreign-format plan the ids are read as the plan reads them (L82); the test suite stays green with two full suites running in parallel (L150). **0.26.0**: `cadence orchestrate` raises the floor of a lot's budget from 200 k to 450 k tokens, enough to pay a write pass, its review, one fix pass and the short review that follows, so a lot of 0.5 or 1 day is no longer handed back at its second or third pass; a `--continue` wave draws fewer lots as a result (L128). **0.25.0**: the project line of the plans' progress in the `cadence-hud` band names the lots in progress after their count, three at most then `…` (L153, `cadence-hud` 0.4.2); the progress follows the folder the session was launched from, so a `cd` into a sub-project no longer shrinks the band, and the session context keeps the `session.start` folder (L154). **0.24.0**: `cadence orchestrate --drop <project:lot>` and `--stop-after-current` steer a live wave from another terminal, `--resume --drop` removes a lot before replaying a stopped wave (L79); the final table of a wave says « livrable jusqu'à <sha> » for a ready lot stacked under a lot handed back, with `git push origin <sha>:main && cadence deliver --sha <sha>` (L76); a version commit (version fields, `CHANGELOG.md`, the README's « What's new ») no longer asks for a new code review (L72). **0.23.0**: the progress bar of each project in the `cadence-hud` band is coloured by the share of lots done, red below 33 %, orange below 66 %, green beyond (L152, `cadence-hud` 0.4.1); `cadence deliver` under a wave lock refuses only when a lot of the wave still works in that very repository, a linked worktree included (L127). **0.22.0**: `cadence orchestrate --continue` draws the next ready lot of the plan itself, in the declared priority, until the budget, the time window or a question stops it (L147); `cadence session context` prints the context of the session, which the `cadence-hud` band publishes, and the `lead` skill chains lots without the human while it stays under 60 % (L148); the band shows the progress of each project's plan, and `cadence lead tour --json` gains `progress` (L149, `cadence-hud` 0.4.0); the final review of a lot is always played, the lot's own budget bounding the writing passes only, with 65 k tokens reserved for it (L145); the cause « tests rouges après … » names the pass whose tests were red (L151). **0.21.0**: `cadence orchestrate --status` and `cadence lead tour` print the free session slots, which the `lead` skill reads (L141); `orchestrate.effort` sets the effort level of each pass of a wave (L137); `docs.sync` makes `raf check`, `lead tour` and the review brief report a document that does not follow the code (L143); `docs.articles` opens, after a green `cadence deliver`, a lot `Article <project> à rafraîchir` in the neighbouring repository (L144). **0.20.0**: `cadence-hud` no longer misleads once the work is over: `/hud cmd` lists the background commands it counts (id, tool, origin, age, name), any other argument answers `argument inconnu` instead of hiding the band, commands with no end seen for an hour or no record go to a grey `N cmd sans fin vue`, a finished subagent takes its commands with it, two races that left a `1 cmd` counted forever are closed, and a finished wave shows grey without its budget then disappears after 30 minutes (L142); the `qa-reviewer` and `ux-reviewer` agents are read-only for real, their frontmatter listing Read, Grep, Glob, Bash and the Playwright tools (L140). **0.19.1**: `cadence-hud`'s `N cmd` counter goes back down when a Monitor expires, when the background commands a subagent started end with it, and at session start or plugin reload (L135); its `tool.call` and `prompt.submit` guard hooks carry a `.catch` on registration, which clears the `claude plugin validate` warning (L136). **0.19.0**: `cadence orchestrate` lifts a repository's lock and `pre-push` guard as soon as every lot of the wave that touches it is finished, so `cadence deliver` works there while the wave continues elsewhere (L132); a review that leaves a repository dirty hands back that lot only, suspends the lots still queued in that repository and keeps the other repositories running, its verdict reported instead of lost (L133); `cadence session close` re-run without a `session start` keeps the window since the last opening (L131); `cadence-hud` draws the lot rows of a wave in aligned columns on every surface (L134). **0.18.0**: `cadence session next` prints what it records (issue #6); `cadence session close` covers the period since the last `session start` (or the last close) and says so in its title, `--since` still wins (issue #7). **0.17.0**: `cadence-hud` shows an `N cmd` segment next to the agents, the background commands of the session (Bash run in the background and Monitor, subagents' included), tracked from the tool results and ended by the task's notification or `TaskStop`. **0.16.0**: a lot can declare **neighbouring repositories** (`repos:` key of the lot, `{ path, cite }` for a repository shared between projects): `cadence orchestrate` refuses, locks and guards them, gives them to every session as `--add-dir`, and `raf commits`, `raf show` and the review verdict read the commits that cite the lot there too. **0.15.0**: `hook.autostart` in `cadence.yaml` (`warn` by default, `refuse` or `start`): a pre-commit hook that refuses, or starts in the same commit, a lot still todo that the commit cites; `cadence session start|close --all [--depth n]`, one section per project under a folder. **0.14.0**: `cadence lead tour`, the lead's morning table of every project in a folder, printed by a program (one line per project: lots in progress, gaps, last notes, next ready lot, repository) in place of one subagent per project; the `lead` skill calls it. **0.13.1**: `cadence-hud` takes back the segments that fit once a big one has dropped (reset times, then the per-model consumption, now short: `opus 1.2M sonnet 800k`); `CADENCE_HUD_AMBIGUOUS=1` for a terminal that draws `▰ ▱ ⚙ │ ↻` in one cell. **0.13.0**: `cadence orchestrate --status --watch` (a wave's table redrawn in the terminal, which
43
+ **1.2.0**: the spec step reaches lots without a screen: a lot that declares `spec: true` (`raf add --spec`, `raf spec`) gets a back-end sheet of cases, rules, contracts and data (`cadence spec check`), reviewed before any code, then acceptance tests locked before the implementation, and `raf screen` lets a plan already written adopt the step; `orchestrate.accept` may be a list of runners (front and back), each run under its own root; `cadence spec reseal <lot> <test> --reason` is the lead's way out when a sealed test contradicts its unchanged sheet; `lead.ux: lead` lets the lead form the UX verdict itself; `cadence lead tour --depth n` looks for projects deeper in the folder; the budgets of a wave are recalibrated on the measured runs (750 k for an ordinary lot of 0.5 to 1 day, 1.3 M for a lot with a screen); the code in service on the cadence repository is a separate worktree, updated only by `npm run service`, so a wave can no longer put unreviewed code in service (L185–L189, L191, L192, L194–L198, L200, L201). **1.1.0**: the spec step of `cadence orchestrate`: a lot that declares `screen:` gets a machine-readable screen sheet (`cadence spec check|qa`), a mockup reviewed against it, acceptance tests committed red and locked before the implementation, and briefs that carry the sheet and rule → test → green to `implement`, `fix` and the code review; the news entry gains a *Hypothèses* section (L166, L169–L174, L177–L184). **1.0.0**: the first major release, a stable contract: the commands and options, the keys of `cadence.yaml`, the plan file and the names of the skills and agents follow semantic versioning, and the README's *Stability* section lists what is guaranteed and what is not (L164). **0.28.0**: `orchestrate.precheck: local` runs the « deliverable already present? » pre-check of `cadence orchestrate` on the local model (`claude-local`, Ollama), off the Anthropic quota, Sonnet staying the default and the fallback (L146); the `qa-reviewer` agent walks only the pages a lot touched, with a **Scope** line in its report (L123); the sub-tasks a review closes are also read in a lot's neighbouring repositories (L156) and a commit's sub-task list is read with the plan's left guard (L155); an unstable test is fixed (L90). **0.27.1**: `cadence orchestrate` no longer leaves a session's child processes alive: a dev server started in its own process group, or orphaned by a shell that exits (`nohup srv &`), is killed with the session through its process tree and its `CADENCE_SESSION` mark, a tmux server, `screen`, `gpg-agent` or `dirmngr` started on demand being spared; a session that exits with code 0 while a descendant holds its output open is no longer reported as « délai dépassé » (L83); the `ux-reviewer` and `qa-reviewer` agents carry the briefs' Playwright rule outside `cadence orchestrate` (L84). **0.27.0**: a compliant review of `cadence orchestrate` settles the open sub-tasks that commits of the lot cite (`feat(L3/t2): …`, comma lists included), closed in the same plan commit as the verdict or, on a read-only plan, returned as `[sous-tâche clore]` proposals, so `raf done` no longer refuses a lot over sub-tasks whose work is done; on a foreign-format plan the ids are read as the plan reads them (L82); the test suite stays green with two full suites running in parallel (L150). **0.26.0**: `cadence orchestrate` raises the floor of a lot's budget from 200 k to 450 k tokens, enough to pay a write pass, its review, one fix pass and the short review that follows, so a lot of 0.5 or 1 day is no longer handed back at its second or third pass; a `--continue` wave draws fewer lots as a result (L128). **0.25.0**: the project line of the plans' progress in the `cadence-hud` band names the lots in progress after their count, three at most then `…` (L153, `cadence-hud` 0.4.2); the progress follows the folder the session was launched from, so a `cd` into a sub-project no longer shrinks the band, and the session context keeps the `session.start` folder (L154). **0.24.0**: `cadence orchestrate --drop <project:lot>` and `--stop-after-current` steer a live wave from another terminal, `--resume --drop` removes a lot before replaying a stopped wave (L79); the final table of a wave says « livrable jusqu'à <sha> » for a ready lot stacked under a lot handed back, with `git push origin <sha>:main && cadence deliver --sha <sha>` (L76); a version commit (version fields, `CHANGELOG.md`, the README's « What's new ») no longer asks for a new code review (L72). **0.23.0**: the progress bar of each project in the `cadence-hud` band is coloured by the share of lots done, red below 33 %, orange below 66 %, green beyond (L152, `cadence-hud` 0.4.1); `cadence deliver` under a wave lock refuses only when a lot of the wave still works in that very repository, a linked worktree included (L127). **0.22.0**: `cadence orchestrate --continue` draws the next ready lot of the plan itself, in the declared priority, until the budget, the time window or a question stops it (L147); `cadence session context` prints the context of the session, which the `cadence-hud` band publishes, and the `lead` skill chains lots without the human while it stays under 60 % (L148); the band shows the progress of each project's plan, and `cadence lead tour --json` gains `progress` (L149, `cadence-hud` 0.4.0); the final review of a lot is always played, the lot's own budget bounding the writing passes only, with 65 k tokens reserved for it (L145); the cause « tests rouges après … » names the pass whose tests were red (L151). **0.21.0**: `cadence orchestrate --status` and `cadence lead tour` print the free session slots, which the `lead` skill reads (L141); `orchestrate.effort` sets the effort level of each pass of a wave (L137); `docs.sync` makes `raf check`, `lead tour` and the review brief report a document that does not follow the code (L143); `docs.articles` opens, after a green `cadence deliver`, a lot `Article <project> à rafraîchir` in the neighbouring repository (L144). **0.20.0**: `cadence-hud` no longer misleads once the work is over: `/hud cmd` lists the background commands it counts (id, tool, origin, age, name), any other argument answers `argument inconnu` instead of hiding the band, commands with no end seen for an hour or no record go to a grey `N cmd sans fin vue`, a finished subagent takes its commands with it, two races that left a `1 cmd` counted forever are closed, and a finished wave shows grey without its budget then disappears after 30 minutes (L142); the `qa-reviewer` and `ux-reviewer` agents are read-only for real, their frontmatter listing Read, Grep, Glob, Bash and the Playwright tools (L140). **0.19.1**: `cadence-hud`'s `N cmd` counter goes back down when a Monitor expires, when the background commands a subagent started end with it, and at session start or plugin reload (L135); its `tool.call` and `prompt.submit` guard hooks carry a `.catch` on registration, which clears the `claude plugin validate` warning (L136). **0.19.0**: `cadence orchestrate` lifts a repository's lock and `pre-push` guard as soon as every lot of the wave that touches it is finished, so `cadence deliver` works there while the wave continues elsewhere (L132); a review that leaves a repository dirty hands back that lot only, suspends the lots still queued in that repository and keeps the other repositories running, its verdict reported instead of lost (L133); `cadence session close` re-run without a `session start` keeps the window since the last opening (L131); `cadence-hud` draws the lot rows of a wave in aligned columns on every surface (L134). **0.18.0**: `cadence session next` prints what it records (issue #6); `cadence session close` covers the period since the last `session start` (or the last close) and says so in its title, `--since` still wins (issue #7). **0.17.0**: `cadence-hud` shows an `N cmd` segment next to the agents, the background commands of the session (Bash run in the background and Monitor, subagents' included), tracked from the tool results and ended by the task's notification or `TaskStop`. **0.16.0**: a lot can declare **neighbouring repositories** (`repos:` key of the lot, `{ path, cite }` for a repository shared between projects): `cadence orchestrate` refuses, locks and guards them, gives them to every session as `--add-dir`, and `raf commits`, `raf show` and the review verdict read the commits that cite the lot there too. **0.15.0**: `hook.autostart` in `cadence.yaml` (`warn` by default, `refuse` or `start`): a pre-commit hook that refuses, or starts in the same commit, a lot still todo that the commit cites; `cadence session start|close --all [--depth n]`, one section per project under a folder. **0.14.0**: `cadence lead tour`, the lead's morning table of every project in a folder, printed by a program (one line per project: lots in progress, gaps, last notes, next ready lot, repository) in place of one subagent per project; the `lead` skill calls it. **0.13.1**: `cadence-hud` takes back the segments that fit once a big one has dropped (reset times, then the per-model consumption, now short: `opus 1.2M sonnet 800k`); `CADENCE_HUD_AMBIGUOUS=1` for a terminal that draws `▰ ▱ ⚙ │ ↻` in one cell. **0.13.0**: `cadence orchestrate --status --watch` (a wave's table redrawn in the terminal, which
28
44
  stops with the wave) and the lead skill that names the wave and follows its journal; lot ids with `/`
29
45
  (sub-tasks of a read-only plan) accepted by `orchestrate`; `cadence-hud`'s first line measured in
30
46
  terminal cells and kept to ASCII; `publish.yml` on the v5 actions. **0.12.0**: the `cadence-hud` plugin (a status band above the Claude Code prompt),
@@ -86,8 +102,10 @@ raf gantt # docs/plan/gantt.html
86
102
  | Command | Effect |
87
103
  |---|---|
88
104
  | `raf init [--project name] [--prefix L] [--no-hook]` | create the plan, install the hook, add `.playwright-mcp/` to `.gitignore` |
89
- | `raf add "title" [--estimate d] [--quickwin] [--visible] [--public "title"] [--after L2,L4] [--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:`) |
105
+ | `raf add "title" [--estimate d] [--quickwin] [--visible [--screen page\|component\|journey]] [--spec] [--public "title"] [--after L2,L4] [--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. It is what will trigger the spec step of `orchestrate`, 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) |
90
106
  | `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`) |
107
+ | `raf screen <id> page\|component\|journey\|none` | set, replace or remove `screen:` on an existing lot, to adopt the [spec step](#the-spec-step-of-a-lot-with-screen) on a plan already written; refused on a lot without `visible:` (like `raf add --screen`) and on a sub-task; `none` removes the key and leaves `visible:` alone |
108
+ | `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`](#the-spec-step-of-a-lot-with-spec-true)); refused on a sub-task; `off` is refused on a lot that has `screen:` (the screen implies the spec: remove `screen:` first) and `on` there only says so and changes nothing. `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`) |
91
109
  | `raf public <id> "title"` · `raf public <id> --clear` | set, replace or remove the public title of a lot |
92
110
  | `raf start <id>` · `raf done <id> [--force]` · `raf drop <id> [--reason text]` | dated transitions (`done` refuses open sub-tasks unless `--force`) |
93
111
  | `raf note <id> "text"` | dated note — keep decisions next to the work |
@@ -189,6 +207,8 @@ plan:
189
207
  fields: # raf field: key in the file (a list = first one present)
190
208
  title: titre
191
209
  public: titre_public # the lot's title for the public; read when it is text, else ignored
210
+ screen: ecran # page, component or journey; only on a visible lot
211
+ spec: fiche # true or false: the lot changes a behaviour
192
212
  status: etat
193
213
  estimate: effort
194
214
  created: cree_le
@@ -205,9 +225,10 @@ plan:
205
225
  estimates: { S: 0.5, M: 1, L: 3 } # their effort labels, in working days
206
226
  ```
207
227
 
208
- - Fields: `id`, `title`, `status`, `estimate`, `quickwin`, `visible`, `public`, `every`, `last`, `after`, `created`, `started`,
228
+ - Fields: `id`, `title`, `status`, `estimate`, `quickwin`, `visible`, `screen`, `spec`, `public`, `every`, `last`, `after`, `created`, `started`,
209
229
  `finished`, `notes`, `repos`, `parent`; one left out is read under its own name. A timestamp counts for
210
230
  its day; a note written as plain text is one note.
231
+ - `spec` is the exception to « a left-out field is read under its own name »: a read-only plan's `spec:` is often the path of a spec document, so it is read only when `plan.fields.spec` maps it, and then only `true` counts (any other value is neither an error nor a spec step). Natively, `spec:` stays `true` or `false` (L198).
211
232
  - `parent`: an entry `B33/t1-fusion` whose parent is `B33` becomes the sub-task `t1-fusion` of `B33`.
212
233
  - Ids need no prefix: a commit belongs to a lot when its message cites one of the plan's ids as a
213
234
  whole word (`E-A2`, `NC2.4`, `B33/t1-fusion`).
@@ -268,12 +289,12 @@ captures:
268
289
  |---|---|
269
290
  | `cadence news new <lot…> [--title t]` | entry skeleton, dated and timed now (`date`, `created`), titled after the lot's public title (`public`), else its title; `--title` wins |
270
291
  | `cadence news list` | entries, newest first (see *Order* below) |
271
- | `cadence news check` | visible lots done without entry, unknown lots, missing or undeclared screenshots, entries without creation time, bad headers |
292
+ | `cadence news check` | visible lots done without entry, unknown lots, missing or undeclared screenshots, entries without creation time, bad headers, a lot whose screen sheet has hypotheses and whose entry lacks the `## Hypothèses` section (or a line for one of them) |
272
293
  | `cadence news stamp` | migration: writes `created:` into entries without one (or with an empty one), from the author date of the commit that added the file under its current name (now if not committed yet) |
273
294
  | `cadence news build [-o dir]` | `nouveautes.json` + `index.html` + screenshots (default `docs/nouveautes/site`) |
274
295
 
275
296
  `--dir` changes the entries folder (default `docs/nouveautes` at the git root).
276
- The Markdown is deliberately small: paragraphs, `-` lists, `**bold**`,
297
+ The Markdown is deliberately small: headings (`#` to `######`, rendered one level lower, `<h2>` to `<h6>`; a heading takes its own line and cuts the paragraph or list around it), paragraphs, `-` lists (a bullet may continue on the next lines, indented), `**bold**`,
277
298
  `` `code` ``, `[links](url)`; everything else is escaped text. The JSON holds
278
299
  `{ project, generated, entries: [{ slug, title, date, lots, captures, html }] }`,
279
300
  with screenshot paths relative to the JSON file. `captures` is always a list of
@@ -505,7 +526,7 @@ them without running `session start` again.
505
526
  to look for another. `--since` and `--idle` go to every project; an error in one
506
527
  project is printed in its section and the others still run. It replaces the shell
507
528
  loop over the sub-folders. A project that is not the root of its own git repository gets a `✗` line
508
- (and exit 2) instead of the parent repository's plan. `--all` and `--depth` are refused outside `session`,
529
+ (and exit 2) instead of the parent repository's plan. `--all` and `--depth` are refused outside `session` (`--depth` is also read by `cadence lead tour`),
509
530
  and `--all` refuses `--file`, `--config` and `RAF_FILE`: each project reads its own plan. For a one-line-per-project overview, `cadence lead tour`.
510
531
 
511
532
  `cadence session next` without a line refuses (exit 2) and leaves the notes of the
@@ -574,7 +595,7 @@ the exit code nor the verdict.
574
595
 
575
596
  ## lead tour
576
597
 
577
- `cadence lead tour [folder] [--idle 3] [--json]` is the lead's morning table, with no model in
598
+ `cadence lead tour [folder] [--idle 3] [--depth n] [--json]` is the lead's morning table, with no model in
578
599
  the loop. From a parent folder (default: the current one) it takes every direct sub-folder that
579
600
  holds `docs/plan/raf.yaml`, or a `cadence.yaml` with a `plan:` key (a plan kept by another tool
580
601
  included), and for each one reads the same facts as `cadence session start` — in-process, no
@@ -601,11 +622,80 @@ the lots done / in progress / to do (dropped and recurring lots left out) and th
601
622
  [`cadence-hud`](plugins/cadence-hud/README.md) draws as one progress bar per project. Projects come in the order of the
602
623
  `priority:` key of the folder's `cadence.yaml` (the one `orchestrate --continue` reads), the others after, alphabetically; an unreadable `cadence.yaml` or
603
624
  a `priority:` that is not a list of names (`priority: ol`, `priority: []`) keeps the alphabetical order and adds a first row `cadence.yaml · ✗ erreur : <cause>` (`project: "cadence.yaml"` with `error` in `--json`).
625
+ Sub-projects are looked for one level down by default. `--depth n` goes `n` levels down (same meaning as in `cadence session start --all --depth n`:
626
+ a folder that is a project is not entered; an integer ≥ 1, otherwise refused), and the `depth:` key of the folder's `cadence.yaml`, next to `priority:`, sets it once for all
627
+ (`depth: 2`); `--depth` wins over the key, and a `depth:` that is not an integer ≥ 1 adds the same first row `cadence.yaml · ✗ erreur : …` and leaves one level read.
628
+ `cadence-hud` asks the tour from the folder of the session, so it follows the key with no change. A project is named by its folder's name; one found below the first level is named by its path from the folder (`groupe/gamma`), unique and ready for `cadence orchestrate groupe/gamma:L1` run from there, while `priority:` and the alphabetical order read the folder's own name.
604
629
  "Created in the last 7 days" means today and the six days before. When the folder has no sub-project but is itself a project, the tour is that project's single line
605
630
  (this is what `cadence-hud` asks from a session opened inside a project). The tour is read-only: it changes
606
631
  no plan. It exits 0 even when a project is in error — that project's line reads
607
632
  `beta · ✗ erreur : <cause>`. The `lead` skill runs it instead of one subagent per project.
608
633
 
634
+ ## corrections
635
+
636
+ `cadence corrections [folder] [--classify [--model m]] [--cache file] [--sample n] [--until date] [--json]` measures how often a wave
637
+ has to correct itself. From the folder a wave was launched from (default: the current one) it reads the journals
638
+ `<folder>/.cadence/runs/<wave>/<project>--<lot>.json` of **every project** and prints:
639
+
640
+ - the **lots with a correction**: of the lots that went through a successful write session, the share with at least one
641
+ and at least two `fix` passes, per project and for visible versus non-visible lots (`61 %` and `29 %` of 263 lots in the 10-10 baseline);
642
+ - the **passes by cause**, in total and per project. The cause of a pass is read from the findings of the review that
643
+ precedes it, among: unclear spec or missing criterion (`spec-floue`), invented business rule (`regle-inventee`),
644
+ architecture drift (`derive-architecture`), data / SQL (`donnees-sql`), code bug (`bug-code`), missing test
645
+ (`test-manquant`), false review finding (`faux-constat`). One cause per pass: the root of what forced the fix. A pass with no review finding to read (triggered by red tests right after the write session) is counted apart as `sans-constat` and never sent to the model.
646
+
647
+ Without `--classify` the command calls no model: the passes not yet classified count as `non classé`. With `--classify`
648
+ each pass is classified by a **local model served by Ollama** (`OLLAMA_HOST`, default `http://localhost:11434`;
649
+ `--model`, default `mistral-small3.2:24b`; temperature 0, output constrained to the seven causes), off the Anthropic quota.
650
+ The classification is cached in `<folder>/.cadence/corrections.json` (or `--cache file`): a re-run classifies only the
651
+ new passes, and a pass the model could not answer stays out of the cache. `--sample n` prints `n` passes with findings spread
652
+ evenly over the sorted keys, with their findings and the model's cause, to be read by hand; a `manual` field written
653
+ beside a pass in the cache file (one of the seven causes, else the command refuses the file) overrides the model's cause in every table and gives the **agreement rate** of the model
654
+ on the reviewed sample. `--until date` (ISO, e.g. `2026-10-10T18:31Z`) reads only the waves created up to then (`created` in the wave's `wave.json`) and, in them, only the steps ended by then (`ended`), so that neither later waves nor a wave still running at that time change a published baseline; a wave or a step with no readable date is left out. `--json` prints the measure as data. The command reads the journals and writes nothing but the cache.
655
+ The first baseline is in [docs/mesures/corrections-2026-10-10.md](docs/mesures/corrections-2026-10-10.md); `test/corrections-mesure.test.ts` replays its command on the journals and checks the document's results word for word (skipped when the journals are not there).
656
+
657
+ ## spec
658
+
659
+ `cadence spec check <fiche.yaml>` checks a **sheet** (`fiche.yaml`, the machine-readable output of the spec step): a **screen sheet** (a lot with `screen:`), a **back-end sheet** (a lot that changes a behaviour without a screen) or a **mixed sheet** with both parts. The screen part is designed in
660
+ [docs/superpowers/specs/2026-10-10-etape-spec-design.md](docs/superpowers/specs/2026-10-10-etape-spec-design.md)). Start from the template
661
+ [`templates/fiche.yaml`](templates/fiche.yaml) (it passes the check as is), a worked example sits next to the design. It prints one
662
+ `✗ …` line per violation and exits **0** when the sheet is valid, **1** with violations, **2** when the file is missing, is not YAML or the usage is wrong. The invariants:
663
+
664
+ - `ecran` has `id`, `titre`, `route` (starts with `/`), `lot`, `maquette`, and `largeurs: [1440, 390]`; `etats` holds at least `vide`, `chargement`, `erreur`, none twice;
665
+ - `champs[]`: a unique kebab-case `id` (it is also the mockup's `data-testid`), `libelle`, `type`, `source`, and a boolean `obligatoire`;
666
+ - `regles[]` are numbered `R1`, `R2`… in order with no gap; each has an `etat` that is one of `etats`, an `enonce`, a `message` (the exact text on screen, or `null`),
667
+ a `statut` — `sourcee` with the `source` it comes from, or `hypothese` with the `si_faux` that says what would change — and at least one planned test, named `Rn — …`;
668
+ - `masque` (optional, only on a rule of state `vide`) lists the fields the rule makes disappear: every id must be a field of the sheet and none may be one the rule shows in `champs`;
669
+ - `actions[]` are numbered `A1`… in order, their `declencheur` is a field id (or `null` for the page load), their `appel` reads `VERB /path`, and the `regles` they carry exist.
670
+
671
+ **Back-end sheet** (L187; design: [docs/superpowers/specs/2026-10-11-etape-spec-back-design.md](docs/superpowers/specs/2026-10-11-etape-spec-back-design.md)). Start from [`templates/fiche-back.yaml`](templates/fiche-back.yaml) (it passes the check as is); a worked example, a real lot of ol-companion, sits next to the design. The sheet has `sujet` instead of `ecran` (no `etats`, `champs`, mockup), and the same `regles`. The back-end invariants, one `✗ …` line each:
672
+
673
+ - `sujet` has `id` (kebab-case, the folder name `docs/specs/<id>/`), `titre`, `lot`, and a `perimetre` with `modules`, `endpoints` and `jobs` (lists of texts, at least one entry in the three) and an optional `hors_perimetre`;
674
+ - `cas[]` are numbered `C1`, `C2`… with no gap, each with `titre`, `acteur`, `declencheur`, `preconditions`, `nominal` (a non-empty list of steps), `resultat`, and `alternatives` — a list of `{ si, alors, regles }`, each citing at least one existing rule — or `alternatives: []` with its reason in `sans_alternative`; every case is cited by at least one rule;
675
+ - a back-end rule has `cas` (at least one existing case id) instead of `etat`, plus the screen rule's `enonce`, `statut` (`sourcee` + `source`, or `hypothese` + `si_faux`) and tests named `Rn — …`; `message`, `champs` and `masque` only make sense on a rule attached to a state;
676
+ - `contrats[]` are numbered `A1`… with no gap, each with an `appel` (`VERB /path`, `job <name>` or `commande <name>`), `entree`, `sortie`, `erreurs` — a list of `{ code, message }` where `code` is `HTTP <n>` or `log debug|log|warn|warning|error|info|critical|fatal|verbose` and `message` the exact text — or `erreurs: []` with its reason in `sans_erreur`, and the `regles` it carries exist;
677
+ - `donnees[]` are numbered `D1`…, each with `objet`, `note`, a boolean `existant` and a `modification` (`aucune`, `ajout` or `changement`); an existing object that is modified carries the `decision` of the lead (the answer to the targeted question). The list may be empty (`[]`: the lot touches no data).
678
+
679
+ **Mixed sheet** (a lot with `screen:` and a back-end part): `sujet` **and** `ecran` side by side, with the same `id` (the folder name) and the same `lot`. A rule is attached to a state (`etat`, a screen rule) or to cases (`cas`), at least one of the two. The `A` ids are shared: the actions of the screen and the `contrats` are numbered `A1…An` with no gap over the whole, and an action that calls an API already listed in `contrats` points to it with `contrat: Ax` instead of repeating its `appel`. An action that has its own `appel` equal to the `appel` of a contract is reported (it must point to the contract). A sheet without `ecran` refuses `actions`, `etats` and `champs` (they only make sense with a screen part), and a rule with `etat` there gets that single report. A sheet that only has `ecran` stays valid as it is (no migration); `sujet` is required as soon as the lot is back-end or mixed.
680
+
681
+ `cadence spec check` prints the same summary line for each kind (`N cas, N règles (N hypothèses), N contrats, N données` for a back-end sheet) and keeps its exit codes: 0 valid, 1 violations, 2 usage.
682
+
683
+ `cadence spec reseal <lot> <test> --reason texte` is the lead's way to correct one sealed acceptance test of the lot in progress that contradicts its (unchanged) sheet, see [The accept step](#the-accept-step-red-acceptance-tests-and-their-lock).
684
+
685
+ `cadence spec qa <fiche.yaml>` derives from a valid sheet the section of `docs/qa/expectations.md` for its screen and prints it on the standard output
686
+ (it never writes the file: you paste the section, and the lead commits it like the rest of the plan files). A sheet with violations prints them on the
687
+ error output, nothing on the standard one, and exits 1. The derivation is built so that the planned empty and error states are never reported as defects:
688
+
689
+ - `## <route>` is the screen's route;
690
+ - `shows:` — one line per mandatory field (its `libelle`), **except** the fields that belong to a state (listed in `champs` of a rule of state `vide` or `erreur`, like the empty-state message);
691
+ the line of a field listed in the `masque` of a `sourcee` rule of state `vide` ends with `— unless <the rule's statement>`; the other fields (a static title) never get one;
692
+ - `never:` — the messages of the rules of state `erreur`, on one line; the message of a rule of state `vide` is a planned display and never goes there;
693
+ - `api:` — the load actions only (`declencheur: null`) in `GET` (the QA pass never sends a POST); the line ends with `may be empty when <the rule's statement>` when a `sourcee` rule of state `vide` carries the action.
694
+ Actions triggered by a field stay with the acceptance tests.
695
+
696
+ `spec qa` only derives the **screen** part: a back-end sheet, which has no `ecran`, is refused (exit 2, « la fiche n'a pas de partie écran »); on a mixed sheet it reads the actions' calls through their `contrat`.
697
+
698
+
609
699
  ## deliver
610
700
 
611
701
  A delivery is done when its checks pass, not when a tool says "success".
@@ -855,7 +945,7 @@ command warns `ne lit pas les demandes de contrôle` on the error output.
855
945
  plan too); then, each time the lots in play are finished, the wave **draws the next ready lots of the plan** — up to the
856
946
  session cap — and plays them in the same wave (same budget, same state folder, journal line `continue : tire …`). A lot
857
947
  is drawn when it is `todo`, its `after` is lifted, it is not recurring, neither its title nor a note says « à décider »
858
- (« à décider avec … », « (à décider) »: a lot waiting for a human decision), it is not already in the wave, and its own budget (derived from its estimate)
948
+ (« à décider avec … », « (à décider) »: a lot waiting for a human decision), it is not already in the wave, and its own budget (derived from its estimate; a lot with `screen:` is worth 1.3 M whatever its estimate, or its ordinary budget plus the 350 k spec-stage allocation if that is more, and a lot with `spec: true` gets that allocation on top of its ordinary budget)
859
949
  fits in the budget left — otherwise the next one that fits is taken (a lot that does not fit in what is left of the current
860
950
  round is not dropped: it is tried again at the next round, once the budget allows it). A round takes at most **one lot per
861
951
  repository** while other repositories have ready lots — the pool plays the lots of one repository one after the other, so a
@@ -880,6 +970,20 @@ limit. Before each new wave it reads the context of its own session with `cadenc
880
970
  time (`cadence session next`). Stays with the human: the first choice and the order, the questions a session raised, the UX
881
971
  reservations; a lot that is not ready, a red delivery or a blocking QA finding is reported and not chained over.
882
972
 
973
+ **Who gives the UX verdict (L197)**: by default the human looks at the `ux-reviewer`'s captures and gives the verdict of a `visible`
974
+ lot (`raf ux`). A human who is not a UX judge can set, in the `cadence.yaml` of the folder the `lead` skill works from:
975
+
976
+ ```yaml
977
+ lead:
978
+ ux: lead # lead | human — default human, nothing changes without the key
979
+ ```
980
+
981
+ With `lead.ux: lead` the lead forms the verdict itself, from the reviewer's report and its own look at the captures, records
982
+ `raf ux` and goes on; the human is consulted only at the slightest doubt (a reservation it cannot settle, a capture it
983
+ cannot read, a matter of taste), and the chain goes on with the other lots meanwhile. `cadence lead tour` prints
984
+ `verdict UX : lead …` as a last line when the setting is on (not part of `--json`), and `cadence.yaml · ✗ erreur : lead.ux doit
985
+ être « lead » ou « human »` for any other value. The setting is read from the parent folder only: a project's own `cadence.yaml` ignores it.
986
+
883
987
  **Lot ids containing `/` (L120)**: the first `:` separates the project from the lot, a final `@` the model, and the lot
884
988
  keeps its `/` (`maritime-atlas:Q4/accueil-4-ux12@haiku`); this holds for `--dry-run`, `--status`, `--resume` and
885
989
  `--answer` too. In `.cadence/runs/<wave>/` the `/` of the lot becomes `__` (`maritime-atlas--Q4__accueil-4-ux12.json`,
@@ -930,7 +1034,7 @@ without `--effort` (see below), so `effort.precheck` has no effect on it and the
930
1034
 
931
1035
  ```yaml
932
1036
  orchestrate:
933
- effort: { precheck: low, implement: medium, fix: medium, review: high, ux: high } # defaults
1037
+ effort: { precheck: low, spec: medium, maquette: high, fiche: medium, accept: medium, implement: medium, fix: medium, review: high, ux: high } # defaults
934
1038
  ```
935
1039
 
936
1040
  To measure what a level costs, run the same kind of wave before and after changing the key: each step of
@@ -945,6 +1049,138 @@ with proofs), `partiel` or `non`: on `oui` no implementation session is opened a
945
1049
  implementation brief and a warning; on `non` — or an unreadable report, which only adds a warning — the wave goes on. A
946
1050
  lot that already has commits is never pre-checked (resuming it is legitimate). `orchestrate.precheck: false` turns it off.
947
1051
 
1052
+ ### The spec step of a lot with `screen:`
1053
+
1054
+ A lot that declares `screen:` (`raf add … --visible --screen page|component|journey`, or `raf screen <id> page|component|journey` on a lot that already exists, see [raf](#raf)) gets one more session, `spec`, **after** the pre-check and **before**
1055
+ the first implementation: `precheck → spec → maquette → accept → implement → ux → review` (`maquette` unless `orchestrate.maquette: false`, see [The mockup review](#the-mockup-review-before-any-code); `accept` only when the project declares `orchestrate.accept`, see below). A lot without `screen:` or `spec: true` follows the usual path, unchanged (a lot with `spec: true` and no screen has its own chain, see [The spec step of a lot with `spec: true`](#the-spec-step-of-a-lot-with-spec-true)). `--dry-run` lists the step
1056
+ (`spec (sonnet)`), its command line and its brief `templates/orchestrate/spec.md`.
1057
+
1058
+ - **The session** (L171): Sonnet, the `spec-writer` agent (it writes only the spec folder, never application code), Playwright loaded like for `implement`. It reads the lot,
1059
+ the project's CLAUDE.md and its charter (CSS, neighbouring components, `docs/qa/expectations.md`, existing routes and API contracts), then writes in
1060
+ `<orchestrate.spec.dir>/<écran>/` (`docs/specs` by default): `maquette.html` (static HTML + CSS to the project's own style; one section `#etat-vide`, `#etat-chargement`,
1061
+ `#etat-erreur` and `#etat-charge` per state; every field of the sheet carries `data-testid="<field id>"`), one capture per state and per width
1062
+ `maquette-<état>-<largeur>.png` (1440 and 390), and `fiche.yaml` (the template `templates/fiche.yaml` is part of its brief). The mockup is rendered by
1063
+ `orchestrate.spec.render` when the project declares it (the session runs that command), otherwise with Playwright; the captures land in the wave's output directory and the session copies the
1064
+ kept ones into the folder. `effort.spec` (default `medium`) sets its effort level. It commits the whole spec in one commit that cites the lot (`spec(L7): …`).
1065
+ - **What the program checks** afterwards, with no model: the sheet passes `cadence spec check`, is the lot's (`ecran.lot`) and sits in the folder named by `ecran.id`; `maquette.html` exists with a
1066
+ `#etat-<état>` section per state and a `data-testid` per field; every state has its capture at both widths; everything is committed and the tree is clean. Anything missing is listed back to **one second
1067
+ `spec` session** (a fresh session whose brief names the points); if the second spec is still not valid the lot is handed back (`spec non conforme après 2 passes : …`).
1068
+ - **A costly choice is a question, not a hypothesis.** A rule marked `hypothese` whose `si_faux` involves a data model or storage, a public or shared API contract or an already published route,
1069
+ a destructive or irreversible action, or a contradiction with a sourced rule, puts the lot in `question` (the program recognises these by keywords as a safety net behind the agent's own
1070
+ judgement; a keyword right after a negation — « rien d'irréversible », « sans suppression », « pas de paiement » — does not count); `--resume --answer <lot> "…"` gives the answer to the resumed `spec` session. Every other hypothesis (wording, order of fields, error state, spacing) stays written in the sheet.
1071
+ The agent can also ask a question itself in its report.
1072
+ - **Under the threshold**: if the session finds that the lot changes no screen, it gives the reason in one line (`sousSeuil`), writes no mockup, and the lot goes on to `implement` as before; the reason is
1073
+ kept as a warning of the lot. On resume the spec step is skipped only when a sheet of the lot (`ecran.lot` is the lot) already passes the program's checks (`cadence spec check`, mockup, captures) and carries no costly hypothesis; otherwise the spec is played again. The sheet path in the report is relative to the repository (an absolute or `./` path is normalised, a path outside the repository is a finding).
1074
+
1075
+ ### The spec step of a lot with `spec: true`
1076
+
1077
+ A lot that changes a behaviour but has no screen (`raf add … --spec`, or `raf spec <id> on`, see [raf](#raf); L188, design: [docs/superpowers/specs/2026-10-11-etape-spec-back-design.md](docs/superpowers/specs/2026-10-11-etape-spec-back-design.md)) is specified **before** it is coded, on a sheet, like a screen:
1078
+ `precheck → spec → fiche → accept → implement → review` (`fiche` unless `orchestrate.fiche: false`; `accept` only when the project declares `orchestrate.accept`). A lot with neither `screen:` nor `spec: true` keeps its path. `--dry-run` lists
1079
+ `spec (sonnet)`, `fiche (sonnet)` and `accept (sonnet)` with their command lines and briefs `templates/orchestrate/spec-back.md`, `fiche.md` and `accept-back.md`; the lot's budget gets a 350 k allocation on top of its estimate-derived budget (the worst case measured on a screen lot's steps: the back chain has not been measured yet).
1080
+
1081
+ - **The spec session**: Sonnet, the `spec-writer` agent, no Playwright. It reads the lot, the project's CLAUDE.md and the code and tests of the modules the lot touches (a rule already coded is a source, cited `file:line`), then writes only
1082
+ `<orchestrate.spec.dir>/<sujet>/fiche.yaml` in the format of [`templates/fiche-back.yaml`](templates/fiche-back.yaml) (`sujet`, `cas`, `regles`, `contrats`, `donnees`; no mockup, no capture, no state) and commits it with a message that cites the lot.
1083
+ The same rules as for a screen: a rule is `sourcee` or `hypothese` with its `si_faux`, and a hypothesis that hides a costly choice is a question (a stored model, a published contract or route, an irreversible action, a contradiction with a sourced or coded rule — the program's keyword safety net applies as is).
1084
+ An optional field added to an existing response is not a break when a rule of the sheet proves the old response unchanged. A lot that changes no behaviour is reported under the threshold (`sousSeuil`, warning `étape spec : sous le seuil, aucune fiche — …`) and follows the usual path.
1085
+ - **What the program checks**: the sheet passes `cadence spec check`, has a `sujet` block, is the lot's (`sujet.lot`), sits in the folder named by `sujet.id`, and is committed with a clean tree. Anything missing goes back to **one second `spec` session**; still invalid, the lot is handed back (`spec non conforme après 2 passes : …`).
1086
+ On a resume the step is skipped when a sheet of the lot (`sujet.lot`) already passes these checks and has no costly hypothesis.
1087
+ - **The sheet review** (`fiche`): a fresh session of the `code-reviewer` agent in **sheet mode** (Sonnet, read-only, no Playwright; `effort.fiche`, default `medium`). It reads the sheet, then the code, tests and sources of the perimeter, and checks (1) every `sourcee` rule cites a source that exists (it opens the file:line) and no `hypothese` hides a costly choice,
1088
+ (2) no contradiction with a rule already coded or an existing contract, (3) every contract has its empty / absent / expired / oversized / duplicate inputs and the failures of its external sources covered by a rule or a motivated `sans_alternative` / `sans_erreur`, (4) every rule has a planned test whose name says what could fail.
1089
+ Findings are ranked blocking / major / minor, each with its measurement. A blocking or major one sends the sheet back for a **second `spec` session** (its brief carries the findings), then the sheet is reviewed again; still not conforming, the lot is handed back with what remains (`fiche non conforme après 2 revues : …`).
1090
+ The `spec` session has **one budget of two sessions**, shared by the program's check and the reviews: if the check already used the second one, a non-conforming review hands the lot back at once (`fiche non conforme et la spec a déjà joué 2 sessions`), with no second review. A question to the lead (the session's own, or a costly hypothesis) and its answer open a new budget.
1091
+ Minor findings become notes of the lot (`Revue de la fiche — mineur : …`, one per finding, committed with the plan; on a read-only plan they become `[note à poser]` proposals), not lines of the final table. This verdict is **not** `raf review`: the review of the code keeps that role. `orchestrate.fiche: false` skips the step.
1092
+ - **A lot with a screen and a behaviour**: it is a lot with `screen:` whose **sheet** has a back part (a `sujet` block next to `ecran`, same folder), never a `spec: true` beside `screen:` (`raf spec <id> on` has no effect on a lot with a screen). The program reads the sheet, not the plan: as soon as the sheet has a `sujet` block (the contracts), the `code-reviewer` also reviews it,
1093
+ the chain is `spec → fiche → maquette → accept`, and the findings of the two reviews go together to a single second `spec` session. The brief of the spec of a lot with a screen offers the back part (and joins its template) without making it compulsory; a lot whose sheet has no `sujet` keeps its chain, without `fiche`. `--dry-run` cannot list `fiche` for a lot with a screen (the sheet does not exist yet).
1094
+ - **Acceptance and code**: `accept` is the screen's step, with a back brief (`accept-back.md`: cases call the contracts of `contrats[]` as close as possible, external sources simulated from `entree`; no `data-testid`). `implement`, `fix` and `review` receive the sheet (cases, rules, contracts) as for a screen, without mockup; the review also checks that each contract is held (output, exact codes and messages of the errors).
1095
+ - **Hypotheses**: a lot without a screen has no News entry. Once the sheet is final — after its review and the second `spec` session if there was one, just before `accept` or `implement`, and also for a sheet already present on a resume — the program writes **one note of the lot per hypothesis** (`Hypothèses (fiche <sujet>) — R3 : … ; si faux : …`, not duplicated on a resume) and commits it with the plan; on a plan kept by another tool the lines become proposals (`[note à poser] …`). The end-of-wave table lists them under each lot (`hypothèse de la fiche : …`) for the lead to relay.
1096
+
1097
+ ### The mockup review: before any code
1098
+
1099
+ After a valid spec, a lot with a sheet gets a UX review of its mockup, `maquette` (L172), unless `cadence.yaml` sets `orchestrate.maquette: false` (default `true`): `precheck → spec → maquette → accept → implement → ux → review`.
1100
+ `--dry-run` lists the step (`maquette (opus)`, the `review.full` model), its `ux-reviewer` command line and its brief `templates/orchestrate/maquette.md`.
1101
+
1102
+ - **The session**: the `ux-reviewer` agent in **mockup mode**, read-only, Playwright loaded, a fresh session. It opens `maquette.html` as a local file (no application, no server), looks at the captures
1103
+ `maquette-<état>-<largeur>.png` (1440 and 390 px) of every state, reads `fiche.yaml`, and reports findings ranked blocking / major / minor, each grounded in a rule (Nielsen, WCAG 2.2 AA) or a measurement. On top of
1104
+ that it checks the **consistency mockup ↔ sheet**: every field of the sheet in the mockup with its `data-testid`, every rule message visible, word for word, in the state its `etat` names, every state with its
1105
+ `#etat-<état>` section, the `masque` of an empty-state rule really hiding the fields it names. `effort.maquette` (default `high`) sets its effort level. Its verdict is **not** `raf ux`: the conformity pass after the code keeps that role.
1106
+ - **The loop, two reviews at most.** A blocking or major finding sends the mockup back to the spec writer: a **second `spec` session** (fresh, its brief carries the findings), then the mockup is reviewed again. If the second review is
1107
+ still not conforming, the lot is handed back with what remains (`maquette non conforme après 2 revues : …`) and nothing is implemented. The same budget of two `spec` sessions applies as for the sheet review: if the program's check already used the second one, a non-conforming review hands the lot back at once (`maquette non conforme et la spec a déjà joué 2 sessions`); an answer to a question of the lead opens a new budget. A conforming review goes on to `accept` (or `implement`). On a resume, a **sealed** `acceptation.json` (its `empreintes` set by the program), still red or already green (`vert: true`), proves the review was done and is not replayed; an unsealed one proves nothing. A `maquette` step with no sheet warns (`revue de la maquette ignorée : aucune fiche …`) and goes to `implement`.
1108
+ - **Sample data** (L181): the spec brief asks the writer to compute the weekday of every date of the mockup (not to write it from memory), and the review recomputes them. A wrong sample datum (weekday, date, figure that does not add up) is a **minor** finding, never a major one, so it cannot by itself send the mockup back for a second review.
1109
+ - **Minor findings** are not sent back: they are kept as proposals of the lot (`[mineur maquette] …`), like the minors of the other reviews. A report whose totals announce a major finding is not taken for conforming.
1110
+ - **On resume**, a sheet already committed is reviewed before the next step, unless the lot already has a sealed, conforming `acceptation.json` (it can only have been written after the review), or already has code committed after the sheet (a commit citing the lot that touches a file outside the sheet's folder: `implement` only started once the review was done), including without `orchestrate.accept`.
1111
+
1112
+ ### The accept step: red acceptance tests and their lock
1113
+
1114
+ After a valid spec, and only when `cadence.yaml` declares `orchestrate.accept` (the project's **dedicated command**, or a list of them, which run *only* the acceptance tests of one lot), a lot with a sheet gets one more
1115
+ session, `accept` (L173): `precheck → spec → maquette → accept → implement → ux → review`. Without `orchestrate.accept` the step is skipped, with a warning on the lot (`étape accept ignorée …`), and the lot goes from `spec` to `implement` as before.
1116
+ `--dry-run` lists the step (`accept (sonnet)`) and its brief `templates/orchestrate/accept.md`.
1117
+
1118
+ - **The session**: Sonnet, the `acceptance-writer` agent, a session other than the implementer's. Its brief gives it the sheet, the mockup and how to run the project's tests (the dedicated command, and the runner template below) — not the lot's objective, notes or
1119
+ sub-tasks, and no implementation. It writes one or more cases per rule, **named as the sheet plans them** (`regles[].tests`, e.g. `R3 — erreur : message et bouton Réessayer`), selectors = the `data-testid` of the fields, API calls simulated from `actions[]`,
1120
+ and commits them **red** in one commit (`test(L7): acceptation R1–Rn (rouge)`) with `<spec.dir>/<écran>/acceptation-<lot>.json` (**one file per lot**: two lots on the same screen never share a lock or a file; the id is reduced to `A-Za-z0-9._-`, so `app/L7` gives `acceptation-app-L7.json`; an older `acceptation.json` is still read, by its `lot` key) — `{ "lot", "fiche", "fichiers": [...], "vert": false }` — and the runner configuration. A second lot's tests that rewrite the first lot's test files hand the lot back, with the file named (the lock below). `effort.accept` (default `medium`) sets its effort.
1121
+ - **One command or a list of runners** (L189). `orchestrate.accept` is a string or a **list** of commands, for a project with a front and a back runner (Vitest in `frontend/`, Jest in `backend/`):
1122
+
1123
+ ```yaml
1124
+ orchestrate:
1125
+ accept:
1126
+ - cd frontend && npx vitest run -c vitest.acceptation.config.ts
1127
+ - cd backend && npx jest -c jest.acceptation.config.js
1128
+ ```
1129
+
1130
+ The program runs **each** command from the repository root with `CADENCE_ACCEPTATION` (and `{acceptation}` substituted) and `CADENCE_ACCEPTATION_ROOT`, the command's **root**: the folder of its leading `cd <folder> &&`, else the repository (`.`). A command takes **only the files listed under its root**: `acceptationOnly()` of the runner template returns them relative to that root, where the runner starts. A command with **no listed file under its root is not run**; a listed file under **no root** is a deviation of the step (`fichiers listés … sous la racine d'aucune commande de orchestrate.accept`, one second pass, then `accept non conforme après 2 passes`). **Red check**: every command that is run must fail (the deviation names the one that passes); **green**: `vert: true` is set only when all of them pass, and a lot sent back to `fix` is told which commands are still red. A string keeps its behaviour: **it ignores its `cd` for the root** — the whole repository is its root and `CADENCE_ACCEPTATION_ROOT` is `.`, so `acceptationOnly()` returns paths relative to the repository; only a list derives a root from each command's leading `cd`. One lot per app wires its back runner (dedicated config, `exclude` in the ordinary one, a line in `cadence.yaml`): that is the app's plan, not cadence's.
1131
+
1132
+ **Moving from a string to a list.** The two forms are not interchangeable: a string keeps the repository as its root, a list (even of **one** element) derives each root from the command's leading `cd <folder> &&` and sets `CADENCE_ACCEPTATION_ROOT` to it. The brief of the step and the cycle decide by the same test (a YAML list or not), so they always agree. To switch: (1) write the entries as `cd <folder> && <runner>`; (2) make the runner's config resolve from its own root (its `include` and `rootDir` relative to `<folder>`, since the runner starts there and `acceptationOnly()` returns the paths relative to that root); (3) **copy the runner template again** into the project (`templates/acceptation-runner.mjs` reads `CADENCE_ACCEPTATION_ROOT`; an older copy lists the repository-relative paths and matches nothing from a folder). A project that has not migrated stays on its string, unchanged.
1133
+ - **Out of the ordinary test run and the CI while the lot is not green.** Red tests committed would fail `orchestrate.test` (after every `implement`/`fix`) and the project's CI (which `cadence deliver` waits for), for lots that are not theirs. So the
1134
+ runner configuration shared by `orchestrate.test` and the CI excludes the files listed in every acceptation file (`acceptation-<lot>.json`) whose `vert` is `false`, and only the dedicated command runs them. `templates/acceptation-runner.mjs` is the helper the session copies
1135
+ into the project: `acceptationIgnored()` (Vitest `exclude`; `acceptationIgnored(root, dir, 'regex')` for Jest `testPathIgnorePatterns`) and `acceptationOnly()` (the `include` of the dedicated config, which reads the environment variable `CADENCE_ACCEPTATION`:
1136
+ the program sets it to the absolute path of the lot's acceptation file when it runs `orchestrate.accept`, and also replaces `{acceptation}` in the command with that path — quote it if the path may hold spaces). If the CI or the test command do not use that config
1137
+ (paths hard-coded), the session must not commit red tests and puts the question in its report.
1138
+ **Run by hand, outside a wave**, the dedicated command fails: `acceptationOnly()` requires `CADENCE_ACCEPTATION`, which only the program sets. Set it yourself, to the path of the lot's acceptation file:
1139
+ `CADENCE_ACCEPTATION=<path of the acceptation file> <command>` (with a `{acceptation}` in the command, write the path there too). For a command of an `orchestrate.accept` **list**, also set its root, which `acceptationOnly()` uses to return the files relative to where the runner starts: `CADENCE_ACCEPTATION=<path of the acceptation file> CADENCE_ACCEPTATION_ROOT=<root of the command> <command>` (the folder of its leading `cd <folder> &&`; without the variable the root is the repository `.`, and the paths are relative to it, which no runner started in a folder will match). A single string needs no root. Once the lot's tests are green (`vert: true`), they join the ordinary runner and the CI, so the usual test command runs them without that variable.
1140
+ - **What the program checks** afterwards, with no model: `acceptation.json` is the lot's (`lot`, `fiche`, listed files committed, `vert: false`), every test name planned in the sheet appears in the listed files, **each listed test file is new** (absent from the head before the first `accept` session: tests written into an existing test file would leave the ordinary run and the CI while the lot is red, so the check refuses `existait avant la session accept`), the other lots' acceptation tests are untouched, the dedicated command
1141
+ **fails** (a test green before the code proves nothing), `orchestrate.test` stays **green** with the red tests committed (proof that they are excluded; without `orchestrate.test` nothing proves it, and the step passes with a lot warning only), and the tree is clean. Anything missing goes to **one second `accept` session**; still not valid, the lot is handed back
1142
+ (`accept non conforme après 2 passes : …`). A question in the report puts the lot in `question`, like the other steps. The check that each listed test *individually* fails is not made: only the dedicated command's exit code is (it fails if any of them fails).
1143
+ - **The seal.** Once the checks pass, **the program** (not the session) adds to `acceptation.json` the git fingerprint of each listed file (`empreintes`) and commits it (`test(L7): acceptation scellée …`): that commit is the **red commit**. Its sha is written nowhere in the file (a session could rewrite it): it is
1144
+ the latest commit in git history that changed the file otherwise than by its `vert` key, and the wave keeps it in the lot's state (`accept.rouge`) too.
1145
+ - **The lock, for every session of the repository.** At the end of each `implement` and `fix` the cycle compares, for the acceptation files of **all** lots found under `orchestrate.spec.dir` (a repository has one queue: the next lot runs on the same branch), the listed test files with the red commit
1146
+ (`git diff <red commit> -- <files>`, empty expected, working tree included, and the fingerprints), and each `acceptation.json` with its version before the session. The only difference tolerated on `acceptation.json` is the `vert` key, and only **the cycle** sets it: a session that changes it, rewrites the
1147
+ file, deletes it, creates one outside the accept step, or modifies a locked test hands the lot back (`verrou des tests d'acceptation : …`) — a useful change is a question to the lead or a review finding, never a silent gesture. The lock does not depend on `orchestrate.accept` being declared. **Exception — a delivered lot (`vert: true`):** a later lot that makes the rule evolve may modify the listed tests of that acceptation when **the sheet of the screen changes in the commits of the same lot** (compared with the head before the lot's first session, working tree included, or in a commit that cites the lot, even made before the wave): the sheet is what evolves the rules, and tests and sheet change together. The exception never covers the acceptation of the lot in progress (its `vert: true` is set right after the implement): that one keeps the whole lock. Without a sheet change the difference is still a deviation — except one narrow case (L184): a listed file whose content is identical to what it was at the head before the lot's first **work** commit (commits found by the plan's refs) is not a deviation, the lot having taken its own addition back (a lot handed back for writing in a locked file and resumed in a new wave, which then removes that addition). This applies to every acceptation, `vert: false` included, but only to a file that **exists** at that head and now: a file absent at that head (e.g. created by the lot's own red commit) or deleted since is never exempted, so deleting a locked test stays a deviation; nor when the sheet of the screen has changed since that head (an evolution admitted for another lot: going back to the old content would cancel it, not the lot's addition); apart from that, with `vert: false` the whole lock applies, sheet change or not; `acceptation.json` itself stays locked (only its `vert` key moves).
1148
+ - **A sealed test that contradicts the sheet: `cadence spec reseal` (L200).** The lock is total for the lot in progress (the delivered-lot exception above never covers it), so a test that is wrong against an unchanged sheet — e.g. the regex `/\d{1,2} /` of an acceptance test rejecting « T3 2027 annoncée », which the sheet allows — would leave the lot handed back with no way out. The way out is the lead's, outside any wave: correct the test in the working tree (**the sheet unchanged**), then `cadence spec reseal <lot> <test> --reason "why the test contradicts the sheet"`. The program checks that the lot is in progress (`doing`), that the test is listed in the lot's sealed `acceptation-<lot>.json`, that the sheet is unchanged since the red commit, that **no other listed test** changed (the lock keeps everything else) and that the test did change; it then redoes the fingerprint of that one test, appends `{ test, raison, date, avant, apres }` to the `resceaux` key of `acceptation.json`, commits the test and `acceptation.json` (`test(L35): acceptation rescellée, <test> : <reason>`, the new red commit) and the lot's note with the reason (`plan: …`). It is refused during an orchestrated wave (`CADENCE_ORCHESTRATED`, or the repository's wave lock while one of its lots still works, like `cadence deliver`), with no `--reason`, and on a lot that is not in progress. Then, depending on how the lot stands: a lot waiting on a `question` is continued by `--resume --answer` (the cycle moves its red-commit anchor to the resealed commit, a rewrite of `acceptation.json` without a `resceaux` entry still being a violation); a lot handed back with `verrou des tests d'acceptation` is finished for `--resume`, so it is replayed by a new wave `cadence orchestrate <project>:<lot>`, which starts again from the red commit. A session never does it, three guards: (1) `cadence spec reseal` is in the sessions' `--disallowedTools` (like `raf done`/`review`/`ux`); (2) a resealed commit is adopted as the new red commit only if it belongs to **no session of the wave** (commits listed in each `steps[].commits`, or in `headBefore..headAfter` of any session of any lot of the wave) — otherwise it stays a violation of the lock; (3) the lock is checked at the end of **every** work session, a session that ends with a question included, so a session that replaces the test, forges the fingerprint, commits and asks a question is handed back with `verrou des tests d'acceptation` without waiting for the lead's `--answer`. The reseal is atomic: if the commit fails (a `pre-commit` hook exiting 1, say) `acceptation.json` and the test are put back as they were before the command (the lead's correction in the working tree is kept, nothing staged) and a readable error says nothing was resealed. With a plan kept read-only by another tool, the reseal itself succeeds but the plan is not touched: the note of the lot is left to the lead (the reason stays in `acceptation.json` and in the commit message; the command only says a note is to be added). With a plan outside the repository or untracked, the note **is** written in the plan file but not committed (the command says `plan à commiter`); do not add it a second time. If the commit of the note is refused (a hook), the reseal stays done: the error gives its commit and says the note, already written, is to be committed by hand.
1149
+ - **Back to green, set by the cycle.** At the end of each `implement`/`fix`, once the session reports green, the cycle runs the dedicated command. Red: the findings go to a `fix` pass (the tests are made green without editing the locked files). Green: the cycle sets `vert: true` and commits it (`chore(L7): acceptation verte …`;
1150
+ `commitPlan` may commit the `acceptation.json` files, otherwise the dirty tree would stop the lot). The files then join `orchestrate.test` and the CI, which keep the lot green from then on; the following lot, running with `vert: true`, is compared with the head before its own work, not with the red commit, only once the sheet has changed between the red commit and that head: after an admitted evolution (tests changed along with the sheet) it sees no difference either; only a test changed *during* that lot without the sheet is a deviation.
1151
+ - **When the lot is handed back** (question, budget, passes exhausted) its tests stay red but excluded from the project's runner and CI: the next lots and `cadence deliver` do not see them; `--resume` continues with the same lock. On resume, the step is skipped when the lot already has a valid committed **and sealed** `acceptation.json` (its `empreintes` set by the program); a conforming file without them proves nothing and `accept` runs again. The fingerprints are keyed by normalised path, so a listed `./test/x.ts` is recognised like `test/x.ts`, on resume and by the lock (which compares it to its fingerprint).
1152
+
1153
+ ### The downstream briefs: sheet, rule → test → green, conformity, Hypothèses
1154
+
1155
+ Once the sheet exists, the steps after it all read it (L174, `src/orchestrate/aval.ts`, the `{{fiche}}` marker of the templates `implement.md`, `fix.md`, `fix-minors.md`, `review.md`, `review-small.md` and `ux.md`). A lot without a sheet (no `screen:`, or under the threshold) keeps exactly the briefs it had.
1156
+
1157
+ - **`implement` and `fix`** get the path of the sheet and of the mockup, and **one line per rule** (`- R3 [erreur, hypothese] statement. Message: « … ». Tests: « R3 — … »`). The session makes the acceptance tests green **without modifying them** (they are named when the `accept` step ran; the lock above hands the lot back otherwise), **the tests it writes in addition cite the rule** in their name (`R2 — …`), and it **does not invent a rule**: a case the sheet does not cover is written in the report (`nonVerifie` or `choix`), not coded. In a `fix` the sheet stays the reference: a finding that contradicts it is contested under `choix`.
1158
+ - **The code review (`review`, `review-small`) checks rule → test → green** (`règle → test → vert`). For each `Rn` of the sheet the reviewer checks that its test exists (named after the rule), that it is green, and that the behaviour is in the diff; when an acceptance file is named, that each listed test is unchanged since the red commit (`git diff <red commit> -- <file>` empty; the brief gives the red commit). A rule without a test, an acceptance test modified since the red commit, a rule coded that is not in the sheet, and a test that is green without exercising its rule are **major** findings. The reviewer no longer rebuilds the cases from the code.
1159
+ - **The UX pass becomes a conformity pass.** For a lot with a sheet, the `ux` session (the `ux-reviewer` agent, **conformity mode**) no longer audits the whole screen: it compares the running app to the mockup and to its captures `maquette-<état>-<largeur>.png`, state by state, at 1440 and 390 px, and reports the differences of rendering and ergonomics the tests do not cover, each tied to a rule or a measure. The rules of the sheet are the tests' job. Its verdict feeds `raf ux`, which stays the lead's, decided on the captures. A small visible lot (single `review-small` pass) gets the conformity instruction in that pass.
1160
+ - **The `## Hypothèses` section of the news entry.** The `implement` brief asks for an entry that ends with `## Hypothèses`: one line `- Rn — …` per rule whose status is `hypothese`, with what changes if it is wrong (its `si_faux`) — it is what the lead shows for the `raf ux` decision, the choices nobody validated.
1161
+
1162
+ ```markdown
1163
+ ## Hypothèses
1164
+ - R3 — erreur de chargement : message « Impossible de charger le prochain match. » et bouton Réessayer. À confirmer ; sinon seul ce bloc change.
1165
+ ```
1166
+
1167
+ **`cadence news check`** (not `build`) flags a lot whose sheet has hypotheses — found under `orchestrate.spec.dir` (default `docs/specs`), by `ecran.lot` — when none of its entries has the section, or when the section lacks a `- Rn` line for one of the rules (`L7 : la fiche a des hypothèses (R3, R4) mais l'entrée … n'a pas la section « ## Hypothèses »`). A lot without hypothesis needs no section.
1168
+
1169
+ **Production access of the sessions** (L168): a session of a wave (`implement`, `fix`, `precheck`, `spec`, `review`, `ux`) is
1170
+ started with no *default* access to the production cluster (a guard against the ordinary path, not a barrier). What a session inherits was measured on the dev machine: `KUBECONFIG` (pointing at
1171
+ `~/.kube/config`, the production cluster), the `kubectl` of the `PATH` (a link to `k3s`, which without `KUBECONFIG`
1172
+ falls back on `/etc/rancher/k3s/k3s.yaml`) and the cloud and GitHub tokens of the environment. `cadence orchestrate` now
1173
+ starts every session with `KUBECONFIG=/dev/null` (`kubectl get pods` answers « connection refused » on `localhost:8080`)
1174
+ and without `KUBERNETES_SERVICE_HOST`, `KUBERNETES_SERVICE_PORT`, `KUBE_TOKEN`, `ARGOCD_SERVER`, `ARGOCD_AUTH_TOKEN`, `ARGOCD_OPTS`, `CLOUDFLARE_API_TOKEN`, `CLOUDFLARE_API_KEY`, `CF_API_TOKEN`, `CF_API_KEY`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN` (exactly these names: `AWS_PROFILE` or `AWS_WEB_IDENTITY_TOKEN_FILE` are kept), `GOOGLE_APPLICATION_CREDENTIALS`,
1175
+ `AZURE_CLIENT_SECRET`, `GH_TOKEN`, `GITHUB_TOKEN`, `GH_ENTERPRISE_TOKEN` (idea taken from the sandbox of docker/docker-agent,
1176
+ closed by default). `HOME` is left alone, so the credential files `gh` keeps under `~/.config` stay readable (a session
1177
+ can neither push nor deliver anyway) and so does `~/.kube/config`: a session that deliberately runs
1178
+ `kubectl --kubeconfig ~/.kube/config …` or `KUBECONFIG=~/.kube/config kubectl …` still reaches the cluster. The restriction
1179
+ stops the accidental access, not a deliberate workaround; making the file unreadable needs a filesystem sandbox
1180
+ (a mount namespace, or the file sandbox of Claude Code), which cadence does not set up. `cadence deliver` and `cadence verify` are the lead's and keep their access; so do
1181
+ the project's own `test`, `build` and `ux.command`, which the program launches. A lot that really needs the cluster is run in a
1182
+ project with `orchestrate.prodAccess: true`: the restriction is lifted for all its sessions (default `false`).
1183
+
948
1184
  `orchestrate.precheck: local` (L146) runs the pre-check on the local model of the dev machine instead of Sonnet: the
949
1185
  orchestrator launches `claude-local` with the same brief, the `precheck-reader` prompt and tools, no quota used and nothing counted in the
950
1186
  lot's budget (the step shows `local` as its model). `claude-local` is **not shipped with cadence**: it is a personal wrapper (a script on the `PATH`, `qwen3-coder:30b` by default) around
@@ -1001,6 +1237,25 @@ The sessions of the wave also get `.cadence/runs/<wave>/tool/bin` (the `raf` and
1001
1237
  `PATH`**, ahead of the per-project Node below and of the usual `PATH`: the `raf` a reviewer runs (`raf commits`…) is the
1002
1238
  snapshot's, not the installed one. A wave without a snapshot leaves the `PATH` as it is.
1003
1239
 
1240
+ **The code in service (L195)**: on cadence's own repository, `bin/raf.js` and `bin/cadence.js` load `dist/`, so the `raf` and `cadence` of your
1241
+ `PATH` used to be whatever the working repository last built. The snapshot protects the wave running, not that installed tool, and a wave's
1242
+ sessions run `npm run build`, `npm install`… The code in service now lives in a **separate copy**: a detached git worktree built there,
1243
+ `<root>/releases/<sha12>`, with `<root>/service` pointing at the current one (`<root>` is `~/.local/share/cadence`), and `~/.local/bin/raf` and
1244
+ `~/.local/bin/cadence` linked to `<root>/service/bin/`. Nothing in the working repository (`npm run build`, `prepare`, `npm install`, `npm ci`,
1245
+ an uncommitted `src/` file) touches it. `npm run build` only type-checks, which is what a session of a wave runs, with the tests, before its report.
1246
+
1247
+ The lead updates the copy after the review, once the lot is accepted (`raf done`):
1248
+
1249
+ ```
1250
+ npm run service -- <sha> # [--root dir] [--bin-dir dir] [--repo dir]
1251
+ ```
1252
+
1253
+ The script refuses a sha that is not an ancestor of HEAD, and a sha whose commits (since the one in service; only the sha itself the first time)
1254
+ cite a lot whose status is not `done` (`plan:` commits are ignored). It builds the new copy aside (`npm ci --ignore-scripts`, then `tsc`) and switches
1255
+ `service` and the two links only once the build succeeded (atomic renames): a failed install changes nothing. The previous copy is kept for a
1256
+ rollback, the older ones are removed only once they are more than 7 days old, counted from the day they left service (a wave's snapshot links its `node_modules` to the copy that launched it). The first run is also what installs the links in `~/.local/bin`. It prints the fingerprint of the copy
1257
+ (bin, dist, package.json).
1258
+
1004
1259
  ### A lot whose work is in a neighbouring repository
1005
1260
 
1006
1261
  Some lots are done in another repository that is not a cadence project (B64 of `maritime-atlas` lives in
@@ -1087,8 +1342,8 @@ upstream ref and `git ls-remote` are compared with the "before", and a read-only
1087
1342
  `CADENCE_ORCHESTRATED` is set.
1088
1343
 
1089
1344
  **Budget**: the wave counts input + cache writes + output tokens (default 2 M); cache reads are kept and
1090
- shown apart. Each lot also has its own budget derived from its estimate (400 k tokens per day, floor 450 k — a write pass, its review, one fix pass and the short review after it —, shown by
1091
- `--dry-run`): it bounds the *writing* passes, never the reviews. A lot that spent it gets no further implementation or
1345
+ shown apart. Each lot also has its own budget, the 90th percentile of the *total* measured per lot on `.cadence/runs` (all the waves a lot went through, 250 lots) for its category (L194): an ordinary lot of up to 0.5 day gets 450 k (floor: a write pass, its review, one fix pass and the short review after it; measured p90 374 k), 0.5 to 1 day 750 k (p90 732 k), then 570 k per day of estimate, 750 k staying the floor until that exceeds it, i.e. up to 1.3 day (p90 1.14 M for 2 days); a lot with `screen:` gets 1.3 M whatever its estimate (p90 1.28 M: spec, mockup, accept, conformity UX and passes), or its ordinary budget plus 350 k beyond that; a lot with `spec: true` gets its ordinary budget plus 350 k (no such lot measured yet); shown by
1346
+ `--dry-run` with its basis): it bounds the *writing* passes, never the reviews. A lot that spent it gets no further implementation or
1092
1347
  fix and is handed back to the lead, but its review (and UX review) is played first; a fix pass starts only if
1093
1348
  the remaining budget can also pay the review that follows it (65 k tokens reserved: a fixed amount close to the 90th
1094
1349
  percentile of the full reviews, 62.7 k over 187 reviews; the short review after the minors pass has a higher p90, 67.6 k
@@ -1152,7 +1407,12 @@ orchestrate:
1152
1407
  test: npm test # run by the orchestrator after a work step (optional)
1153
1408
  build: npm run build # run after the tests; both results go to the reviewer, who does not redo them (optional)
1154
1409
  precheck: true # default: before the first implementation of a lot with no commit, a read-only Sonnet session checks whether the deliverable is already in the repository (see below); false skips it, local runs it on claude-local (Ollama) with Sonnet as fallback
1155
- effort: { review: xhigh } # effort level per pass (see « Effort level per pass »): precheck, implement, fix, review, ux
1410
+ accept: npx vitest run -c vitest.acceptation.config.ts # accept step (see « The accept step »): the dedicated command that runs ONLY the acceptance tests of the lot (optional; without it the step is skipped with a warning)
1411
+ maquette: true # default: UX review of the mockup between spec and accept (see « The mockup review »); false skips it
1412
+ fiche: true # default: review of the back-end sheet of a lot with spec: true between spec and accept (see « The spec step of a lot with spec: true »); false skips it
1413
+ spec: { dir: docs/specs } # spec step (see « The spec step of a lot with screen: »): folder of the screen specs, relative to the repository (default docs/specs); render: the command the spec session runs to render the mockups at 1440 and 390 px (optional, Playwright otherwise)
1414
+ prodAccess: false # default: wave sessions get no access to production (see « Production access of the sessions »); true lifts it for this project
1415
+ effort: { review: xhigh } # effort level per pass (see « Effort level per pass »): precheck, spec, maquette, fiche, accept, implement, fix, review, ux
1156
1416
  ux: http://localhost:4200 # a URL, a launch command, or { command, url, timeout? } — for the UX review (see below)
1157
1417
  permissionMode: auto # default
1158
1418
  addDirs: [/home/me/projects/tmp] # extra directories the sessions may use
@@ -1222,12 +1482,13 @@ version and the folder searched — there is no silent fallback to the default N
1222
1482
  source (user, project, plugin servers: Serena, context7, Cloudflare…), so a session no longer starts a handful of
1223
1483
  `npx`/`uvx` servers it does not use. `review` and `review-recheck` always get an empty set
1224
1484
  (`{"mcpServers":{}}`); so do `implement`, `fix` and `fix-minors` on a lot without a screen. Playwright, launched as
1225
- `npx -y @playwright/mcp@latest --output-dir <wave>/<project>--<lot>/playwright`, is loaded for the `ux` step and, on a
1226
- `visible` lot, for `implement` and `fix` (`fix-minors` included) and, on a small `visible` lot, for `review-small` (its only
1485
+ `npx -y @playwright/mcp@latest --output-dir <wave>/<project>--<lot>/playwright`, is loaded for the `ux` and `maquette` steps and, on a
1486
+ `visible` lot, for `spec`, `implement` and `fix` (`fix-minors` included) and, on a small `visible` lot, for `review-small` (its only
1227
1487
  usability review; `review-small` of a small lot without a screen loads nothing), so the screenshots and snapshots of the work and of
1228
1488
  the review stay with the wave, outside the repository, where the lead can look at them; the final table prints that
1229
1489
  folder whenever Playwright was loaded for the lot, even if no `ux` step ran
1230
- (`<project>:<lot> — captures Playwright : <dir>`; `uxCaptures` in the wave state). The `implement`, `fix`,
1490
+ (`<project>:<lot> — captures Playwright : <dir>`; `uxCaptures` in the wave state). For `maquette` and `spec` the server also gets
1491
+ `--allow-unrestricted-file-access`: the mockup is a local file, and by default the server blocks every `file://` URL. The `implement`, `fix`,
1231
1492
  `fix-minors`, `review-small` and `ux` briefs tell the session to give relative file names if a Playwright server is available, and
1232
1493
  otherwise to keep any Playwright CLI output outside the repository.
1233
1494
  `--dry-run` prints, under each step, `mcp : aucun` or `mcp : playwright (…)`. There is no per-project override in
@@ -1273,11 +1534,12 @@ repository with `cadence skills install` (to `.claude/skills/cadence-*` and
1273
1534
  no model: see [lead tour](#lead-tour)) prints one line of facts per project, you choose the priorities, the lots are delegated with
1274
1535
  `cadence orchestrate` (fresh short sessions with a standard brief — test first,
1275
1536
  README and usage documentation updated with the change, commits citing the lot, no push — reviewed by the `code-reviewer` agent, see
1276
- [orchestrate](#orchestrate)), re-verified by the lead, then delivered
1537
+ [orchestrate](#orchestrate); a lot with a `screen:` first goes through the [spec, mockup review and accept steps](#the-spec-step-of-a-lot-with-screen)), re-verified by the lead, then delivered
1277
1538
  one project at a time; a delivery that changes what a page shows or what it is
1278
1539
  served is then checked in the running app by the `qa-reviewer` agent, whose
1279
1540
  blocking findings come back to you. Two
1280
- subagents at most, never two in the same repository.
1541
+ subagents at most, never two in the same repository. The whole flow is drawn in
1542
+ [docs/lead.md](docs/lead.md).
1281
1543
  - **ux-reviewer** (agent): captures at 1440 and 390 px, findings grounded in a
1282
1544
  named rule (Nielsen, WCAG 2.2 AA) or a measurement, ranked, turned into
1283
1545
  `raf add --parent` sub-tasks, and a one-line verdict for `raf ux`. It never
@@ -1423,10 +1685,11 @@ From 1.0.0 cadence follows [semantic versioning](https://semver.org): what is li
1423
1685
  **Guaranteed**
1424
1686
 
1425
1687
  - **Commands and options** of `raf` and `cadence` (`cadence raf …` is `raf …`): `init`, `add`, `start`, `done`, `drop`,
1426
- `note`, `did`, `public`, `ux`, `review`, `commits`, `show`, `list`, `now`, `ignore`, `check`, `gantt`, `hook`;
1427
- `cadence news`, `session` (`start`, `close`, `next`, `context`), `lead tour`, `deliver`, `verify`, `orchestrate`,
1428
- `skills`; their options and exit codes as this README documents them. A new command or option is a minor change.
1429
- - **The keys of `cadence.yaml`**: `plan`, `news`, `hook`, `session`, `deliver`, `orchestrate`, `docs`, `qa`, `priority`
1688
+ `note`, `did`, `public`, `screen`, `spec`, `ux`, `review`, `commits`, `show`, `list`, `now`, `ignore`, `check`, `gantt`, `hook`;
1689
+ `cadence news`, `session` (`start`, `close`, `next`, `context`), `lead tour`, `corrections`, `deliver`, `verify`, `orchestrate`,
1690
+ `skills`, `spec` (`cadence spec <lot> on|off` is `raf spec`; `check`, `qa`: exit **0** when the sheet is valid and the section is printed, **1** with violations, **2** on a missing or unreadable file or a wrong usage);
1691
+ their options and exit codes as this README documents them. A new command or option is a minor change.
1692
+ - **The keys of `cadence.yaml`**: `plan`, `news`, `hook`, `session`, `deliver`, `orchestrate`, `docs`, `qa`, `priority`, `depth`, `lead` (`lead.ux`)
1430
1693
  and the keys each of them takes. A key is not renamed nor removed, nor does its meaning change; a new key is a minor change.
1431
1694
  - **The plan file** (`docs/plan/raf.yaml`): `project`, `prefix`, `since`, `ignore`, `lots` (with their
1432
1695
  fields, `tasks`, `notes`, `repos`) and `acknowledged`, and the plan formats `plan:` in `cadence.yaml` can read.
@@ -1439,10 +1702,11 @@ From 1.0.0 cadence follows [semantic versioning](https://semver.org): what is li
1439
1702
  - The **text of the outputs**: wording, layout, order of the lines and columns of every report, table and message
1440
1703
  (the `--json` outputs and the exit codes are part of the commands above). In a `--json` output a new field is a
1441
1704
  minor change, so consumers must tolerate unknown fields; removing or renaming a field is a major change.
1442
- - The **`precheck-reader`** agent: internal to `cadence orchestrate`, not meant to be called by hand.
1705
+ - The **`precheck-reader`**, **`spec-writer`** and **`acceptance-writer`** agents, and the mockup and conformity modes of **`ux-reviewer`**: internal to `cadence orchestrate`, not meant to be called by hand.
1443
1706
  - The **`cadence-hud` band**: its segments, colours and layout; it is versioned on its own.
1444
1707
  - The **wave journals** under `.cadence/runs` and the files `cadence orchestrate` keeps there.
1445
1708
  - The wording of the briefs and of the instructions inside the skills and the agents.
1709
+ - The **format of the sheets** (`fiche.yaml`: the screen sheet `templates/fiche.yaml`, the back-end sheet `templates/fiche-back.yaml`, the mixed sheet) and so the invariants `cadence spec check` enforces: experimental while the next bricks of the spec step (S3–S6) still reshape it, a sheet that passes today may be refused by a later release. The `spec` commands and their exit codes are guaranteed, the keys they read are not yet.
1446
1710
 
1447
1711
  There is no schema version and no migration: a file written by an earlier release keeps working, and a key a
1448
1712
  release adds is optional.