@sylad/cadence 1.1.0 → 1.3.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +134 -36
- package/agents/acceptance-writer.md +5 -2
- package/agents/code-reviewer.md +6 -0
- package/agents/spec-writer.md +3 -1
- package/bin/cadence.js +6 -1
- package/dist/cli.js +163 -18
- package/dist/config.js +16 -4
- package/dist/corrections.js +10 -1
- package/dist/lead.js +72 -19
- package/dist/orchestrate/accept.js +92 -4
- package/dist/orchestrate/aval.js +25 -6
- package/dist/orchestrate/briefs.js +3 -0
- package/dist/orchestrate/command.js +100 -38
- package/dist/orchestrate/continue.js +10 -2
- package/dist/orchestrate/cycle.js +272 -55
- package/dist/orchestrate/fiche.js +22 -0
- package/dist/orchestrate/launch.js +8 -8
- package/dist/orchestrate/spec.js +85 -14
- package/dist/orchestrate/state.js +2 -2
- package/dist/orchestrate/table.js +2 -0
- package/dist/orchestrate/waits.js +120 -0
- package/dist/plan.js +58 -1
- package/dist/spec.js +304 -77
- package/package.json +4 -3
- package/skills/lead/SKILL.md +43 -15
- package/templates/acceptation-runner.mjs +28 -8
- package/templates/fiche-back.yaml +75 -0
- package/templates/orchestrate/accept-back.md +16 -0
- package/templates/orchestrate/fiche.md +14 -0
- package/templates/orchestrate/spec-back.md +25 -0
- package/templates/orchestrate/spec.md +1 -1
|
@@ -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.
|
|
11
|
+
"version": "1.3.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.
|
|
4
|
+
"version": "1.3.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
|
@@ -24,7 +24,7 @@ Code prompt that shows the session's context, quota, cost and the orchestrate wa
|
|
|
24
24
|
|
|
25
25
|
### Spec step (design, first steps delivered)
|
|
26
26
|
|
|
27
|
-
For a visible lot that adds a page
|
|
27
|
+
For a visible lot that adds a page (`screen: page`; a component or a journey follows the ordinary path since L209), `orchestrate` gets a step
|
|
28
28
|
before the code: a static HTML mockup in the project's own style (1440 and 390 px; empty, loading and
|
|
29
29
|
error states) and a machine-readable screen sheet (fields, numbered rules `R1…` each marked *sourced*
|
|
30
30
|
or *hypothesis*, actions → API calls). The `ux-reviewer` agent reads the mockup before any code; the
|
|
@@ -32,7 +32,7 @@ acceptance tests are written from the sheet, red, by a session other than the im
|
|
|
32
32
|
implementation gets the sheet, the code review checks rule → test → green, the hypotheses go into the
|
|
33
33
|
lot's news entry, and a human is asked only about a choice that is costly to undo. The design is in
|
|
34
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
|
|
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
36
|
(the sheet's invariants) and `cadence spec qa` (the screen's `docs/qa/expectations.md` section, derived
|
|
37
37
|
from the sheet), see [spec](#spec) below, and the `spec` step of `orchestrate` itself (the `spec-writer` agent, the
|
|
38
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
|
|
@@ -40,7 +40,7 @@ the mockup (the `ux-reviewer` agent in mockup mode), see [The mockup review](#th
|
|
|
40
40
|
|
|
41
41
|
## What's new
|
|
42
42
|
|
|
43
|
-
**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
|
|
43
|
+
**1.3.0**: the spec step's threshold is narrowed to `screen: page` after the measure of 2026-10-12 (no row of the success table reached, about 570 k tokens per lot): `component` and `journey` lots follow the ordinary path again (L176, L209, L210); `cadence spec reseal … --porteur <lot>` re-seals the unstable sealed test of a delivered lot whose contract does not change (L212); the session cap shown and followed is the human's (`CADENCE_MAX_SESSIONS`, L208); `cadence orchestrate --waits` measures slot waits (L206); a third correction pass when the review converges (L205); `"e2e": true` acceptations stay out of the unit runner (L203); a dropped lot fully reverted no longer blocks `npm run service` (L207). **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
|
|
44
44
|
stops with the wave) and the lead skill that names the wave and follows its journal; lot ids with `/`
|
|
45
45
|
(sub-tasks of a read-only plan) accepted by `orchestrate`; `cadence-hud`'s first line measured in
|
|
46
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),
|
|
@@ -102,8 +102,10 @@ raf gantt # docs/plan/gantt.html
|
|
|
102
102
|
| Command | Effect |
|
|
103
103
|
|---|---|
|
|
104
104
|
| `raf init [--project name] [--prefix L] [--no-hook]` | create the plan, install the hook, add `.playwright-mcp/` to `.gitignore` |
|
|
105
|
-
| `raf add "title" [--estimate d] [--quickwin] [--visible [--screen page\|component\|journey]] [--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.
|
|
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. Only `page` triggers the spec step of `orchestrate` (L209), never inferred from the title; `--spec`: the lot changes a behaviour (something a user, an API client or another service can observe), written as `spec: true` right after `screen:`, `visible:`, `quickwin:` or `estimate:` (whichever comes last), shown by `raf show`, refused on a sub-task. Also set by the lead at planning time, never inferred from the title) |
|
|
106
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 (only `page` adopts the [spec step](#the-spec-step-of-a-lot-with-screen); `component` and `journey` do not); refused on a lot without `visible:` (like `raf add --screen`) and on a sub-task; `none` removes the key and leaves `visible:` alone |
|
|
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: page` (the page implies the spec: remove `screen:` first) and `on` there only says so and changes nothing; on `component` and `journey` (ordinary path since L209) both work and set or remove the back-end `spec:`. `raf spec` only takes `on`/`off`: `cadence spec check\|qa <fiche.yaml>` keeps its own subcommands. `raf check` reports a `spec:` that is neither `true` nor `false` (`spec : true ou false attendu`) |
|
|
107
109
|
| `raf public <id> "title"` · `raf public <id> --clear` | set, replace or remove the public title of a lot |
|
|
108
110
|
| `raf start <id>` · `raf done <id> [--force]` · `raf drop <id> [--reason text]` | dated transitions (`done` refuses open sub-tasks unless `--force`) |
|
|
109
111
|
| `raf note <id> "text"` | dated note — keep decisions next to the work |
|
|
@@ -205,7 +207,8 @@ plan:
|
|
|
205
207
|
fields: # raf field: key in the file (a list = first one present)
|
|
206
208
|
title: titre
|
|
207
209
|
public: titre_public # the lot's title for the public; read when it is text, else ignored
|
|
208
|
-
screen: ecran # page, component or journey; only on a visible lot
|
|
210
|
+
screen: ecran # page, component or journey; only on a visible lot (only `page` enters the spec step)
|
|
211
|
+
spec: fiche # true or false: the lot changes a behaviour
|
|
209
212
|
status: etat
|
|
210
213
|
estimate: effort
|
|
211
214
|
created: cree_le
|
|
@@ -222,9 +225,10 @@ plan:
|
|
|
222
225
|
estimates: { S: 0.5, M: 1, L: 3 } # their effort labels, in working days
|
|
223
226
|
```
|
|
224
227
|
|
|
225
|
-
- Fields: `id`, `title`, `status`, `estimate`, `quickwin`, `visible`, `screen`, `public`, `every`, `last`, `after`, `created`, `started`,
|
|
228
|
+
- Fields: `id`, `title`, `status`, `estimate`, `quickwin`, `visible`, `screen`, `spec`, `public`, `every`, `last`, `after`, `created`, `started`,
|
|
226
229
|
`finished`, `notes`, `repos`, `parent`; one left out is read under its own name. A timestamp counts for
|
|
227
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).
|
|
228
232
|
- `parent`: an entry `B33/t1-fusion` whose parent is `B33` becomes the sub-task `t1-fusion` of `B33`.
|
|
229
233
|
- Ids need no prefix: a commit belongs to a lot when its message cites one of the plan's ids as a
|
|
230
234
|
whole word (`E-A2`, `NC2.4`, `B33/t1-fusion`).
|
|
@@ -522,7 +526,7 @@ them without running `session start` again.
|
|
|
522
526
|
to look for another. `--since` and `--idle` go to every project; an error in one
|
|
523
527
|
project is printed in its section and the others still run. It replaces the shell
|
|
524
528
|
loop over the sub-folders. A project that is not the root of its own git repository gets a `✗` line
|
|
525
|
-
(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`),
|
|
526
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`.
|
|
527
531
|
|
|
528
532
|
`cadence session next` without a line refuses (exit 2) and leaves the notes of the
|
|
@@ -591,7 +595,7 @@ the exit code nor the verdict.
|
|
|
591
595
|
|
|
592
596
|
## lead tour
|
|
593
597
|
|
|
594
|
-
`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
|
|
595
599
|
the loop. From a parent folder (default: the current one) it takes every direct sub-folder that
|
|
596
600
|
holds `docs/plan/raf.yaml`, or a `cadence.yaml` with a `plan:` key (a plan kept by another tool
|
|
597
601
|
included), and for each one reads the same facts as `cadence session start` — in-process, no
|
|
@@ -610,7 +614,7 @@ beta · en cours rien · dérive aucune · notes : aucune · prochain T2 Second
|
|
|
610
614
|
| `prochain` | the first ready lot (quick wins first) — id and title cut at 60 characters |
|
|
611
615
|
| `dépôt` | `non commité` (modified or untracked files), `non poussé` (commits ahead of the upstream), `livraison en cours` (live delivery lock); `propre` otherwise |
|
|
612
616
|
|
|
613
|
-
When an orchestrated wave is live, one more line closes the tour (not part of `--json`): `vagues en cours : 1 · sessions en cours : 0 · créneaux libres : 1 sur 2` — the lead reads the free slots there instead of computing them (L141).
|
|
617
|
+
When an orchestrated wave is live, one more line closes the tour (not part of `--json`): `vagues en cours : 1 · sessions en cours : 0 · créneaux libres : 1 sur 2` — the lead reads the free slots there instead of computing them (L141). The `sur M` is the cap the human set (`CADENCE_MAX_SESSIONS`, 2 by default), not a fixed 2 (L208); an invalid value falls back to 2 in this display.
|
|
614
618
|
|
|
615
619
|
`--json` prints the same content as an array of objects (`project`, `doing`, `drift`, `notes`,
|
|
616
620
|
`next`, `repo`, and `error` when the project could not be read), plus `progress` — `{ done, doing, todo, added7 }`,
|
|
@@ -618,6 +622,10 @@ the lots done / in progress / to do (dropped and recurring lots left out) and th
|
|
|
618
622
|
[`cadence-hud`](plugins/cadence-hud/README.md) draws as one progress bar per project. Projects come in the order of the
|
|
619
623
|
`priority:` key of the folder's `cadence.yaml` (the one `orchestrate --continue` reads), the others after, alphabetically; an unreadable `cadence.yaml` or
|
|
620
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.
|
|
621
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
|
|
622
630
|
(this is what `cadence-hud` asks from a session opened inside a project). The tour is read-only: it changes
|
|
623
631
|
no plan. It exits 0 even when a project is in error — that project's line reads
|
|
@@ -631,7 +639,7 @@ has to correct itself. From the folder a wave was launched from (default: the cu
|
|
|
631
639
|
|
|
632
640
|
- the **lots with a correction**: of the lots that went through a successful write session, the share with at least one
|
|
633
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);
|
|
634
|
-
- the **passes by cause**, in total and per
|
|
642
|
+
- the **passes by cause**, in total, per project and **per visibility** (visible lots apart from the others, with the share of `spec-floue`, `regle-inventee` and `test-manquant` among each one's passes — the reference an evolution aimed at screens is compared to is that of the visible lots, not « all lots »: 16 % of 45 passes against 31 % overall in the 10-10 baseline). The cause of a pass is read from the findings of the review that
|
|
635
643
|
precedes it, among: unclear spec or missing criterion (`spec-floue`), invented business rule (`regle-inventee`),
|
|
636
644
|
architecture drift (`derive-architecture`), data / SQL (`donnees-sql`), code bug (`bug-code`), missing test
|
|
637
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.
|
|
@@ -644,11 +652,11 @@ new passes, and a pass the model could not answer stays out of the cache. `--sam
|
|
|
644
652
|
evenly over the sorted keys, with their findings and the model's cause, to be read by hand; a `manual` field written
|
|
645
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
|
|
646
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.
|
|
647
|
-
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).
|
|
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). The measure of the screen-sheet step against the visible lots of this baseline (L176: 8 lots with a sheet, verdict per row of the success table, token cost beside the passes avoided) is in [docs/mesures/etape-spec-2026-10-12.md](docs/mesures/etape-spec-2026-10-12.md); the target of its third row is ≤ 8 %, half the 16 % reference.
|
|
648
656
|
|
|
649
657
|
## spec
|
|
650
658
|
|
|
651
|
-
`cadence spec check <fiche.yaml>` checks a **
|
|
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
|
|
652
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
|
|
653
661
|
[`templates/fiche.yaml`](templates/fiche.yaml) (it passes the check as is), a worked example sits next to the design. It prints one
|
|
654
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:
|
|
@@ -660,6 +668,20 @@ The first baseline is in [docs/mesures/corrections-2026-10-10.md](docs/mesures/c
|
|
|
660
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`;
|
|
661
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.
|
|
662
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 (of a delivered lot: add `--porteur <lot in progress>`), see [The accept step](#the-accept-step-red-acceptance-tests-and-their-lock).
|
|
684
|
+
|
|
663
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
|
|
664
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
|
|
665
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:
|
|
@@ -671,6 +693,8 @@ error output, nothing on the standard one, and exits 1. The derivation is built
|
|
|
671
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.
|
|
672
694
|
Actions triggered by a field stay with the acceptance tests.
|
|
673
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
|
+
|
|
674
698
|
|
|
675
699
|
## deliver
|
|
676
700
|
|
|
@@ -891,6 +915,7 @@ cadence orchestrate … --budget 1.5M # 1500000, 1.5M, 800k; default 2M
|
|
|
891
915
|
cadence orchestrate … --max-sessions 3 # sessions running at the same moment, all waves together; default 2
|
|
892
916
|
cadence orchestrate … --dry-run # preconditions + the plan of the wave; nothing is started
|
|
893
917
|
cadence orchestrate --continue [--until 18:00] [--priority cadence,maritime] # the wave draws the next ready lot itself (below)
|
|
918
|
+
cadence orchestrate --waits [--since 2026-10-12] # time spent waiting for a session slot, per day and per wave (below)
|
|
894
919
|
cadence orchestrate --status [<wave>] # the live waves and the repositories they hold, then the table (default: the last wave of this folder)
|
|
895
920
|
cadence orchestrate --status [<wave>] --watch [--interval 10] # the same, redrawn every 10 s (--interval in seconds); stops by itself when no wave is running (with an explicit `<wave>`: when that wave is no longer running)
|
|
896
921
|
cadence orchestrate --resume [<wave>] [--budget 1M] [--answer ol-companion:L22 "reply"] [--drop ccc:L29]
|
|
@@ -921,7 +946,7 @@ command warns `ne lit pas les demandes de contrôle` on the error output.
|
|
|
921
946
|
plan too); then, each time the lots in play are finished, the wave **draws the next ready lots of the plan** — up to the
|
|
922
947
|
session cap — and plays them in the same wave (same budget, same state folder, journal line `continue : tire …`). A lot
|
|
923
948
|
is drawn when it is `todo`, its `after` is lifted, it is not recurring, neither its title nor a note says « à décider »
|
|
924
|
-
(« à 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)
|
|
949
|
+
(« à 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: page` is worth 1.3 M whatever its estimate (`component` and `journey` have their ordinary budget), 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)
|
|
925
950
|
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
|
|
926
951
|
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
|
|
927
952
|
repository** while other repositories have ready lots — the pool plays the lots of one repository one after the other, so a
|
|
@@ -946,6 +971,20 @@ limit. Before each new wave it reads the context of its own session with `cadenc
|
|
|
946
971
|
time (`cadence session next`). Stays with the human: the first choice and the order, the questions a session raised, the UX
|
|
947
972
|
reservations; a lot that is not ready, a red delivery or a blocking QA finding is reported and not chained over.
|
|
948
973
|
|
|
974
|
+
**Who gives the UX verdict (L197)**: by default the human looks at the `ux-reviewer`'s captures and gives the verdict of a `visible`
|
|
975
|
+
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:
|
|
976
|
+
|
|
977
|
+
```yaml
|
|
978
|
+
lead:
|
|
979
|
+
ux: lead # lead | human — default human, nothing changes without the key
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
With `lead.ux: lead` the lead forms the verdict itself, from the reviewer's report and its own look at the captures, records
|
|
983
|
+
`raf ux` and goes on; the human is consulted only at the slightest doubt (a reservation it cannot settle, a capture it
|
|
984
|
+
cannot read, a matter of taste), and the chain goes on with the other lots meanwhile. `cadence lead tour` prints
|
|
985
|
+
`verdict UX : lead …` as a last line when the setting is on (not part of `--json`), and `cadence.yaml · ✗ erreur : lead.ux doit
|
|
986
|
+
ê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.
|
|
987
|
+
|
|
949
988
|
**Lot ids containing `/` (L120)**: the first `:` separates the project from the lot, a final `@` the model, and the lot
|
|
950
989
|
keeps its `/` (`maritime-atlas:Q4/accueil-4-ux12@haiku`); this holds for `--dry-run`, `--status`, `--resume` and
|
|
951
990
|
`--answer` too. In `.cadence/runs/<wave>/` the `/` of the lot becomes `__` (`maritime-atlas--Q4__accueil-4-ux12.json`,
|
|
@@ -968,7 +1007,8 @@ The Claude Code status band is the `cadence-hud` plugin.
|
|
|
968
1007
|
declared → **code review**, which always comes last (a UX fix changes code) → compliant (no blocking, no
|
|
969
1008
|
major finding) → `raf review` is recorded by the orchestrator with the sha the review read, then
|
|
970
1009
|
"ready to deliver". Not compliant → a correction in a new session, then a new review (the UX review of a
|
|
971
|
-
visible lot is replayed too, the code having changed), **two passes at most
|
|
1010
|
+
visible lot is replayed too, the code having changed), **two passes at most** (a third when the review converges: the count of blocking + major findings dropped
|
|
1011
|
+
since the previous review and exactly one is left; the lot budget still applies), then the lot goes back to
|
|
972
1012
|
you with the findings. A small lot (`estimate` ≤ 0.5 or `quickwin`) gets one single Opus pass for code and
|
|
973
1013
|
usability (code only when the lot is not `visible`). Failing tests (reported red, or red when
|
|
974
1014
|
`orchestrate.test` is run) go straight to a correction.
|
|
@@ -976,7 +1016,7 @@ usability (code only when the lot is not `visible`). Failing tests (reported red
|
|
|
976
1016
|
**Review sized to the lot (L108)**: a lot whose `estimate` is ≤ `orchestrate.review.threshold` (0.25 day by default)
|
|
977
1017
|
is *light*: one single review (Sonnet by default, `code-reviewer` agent, same criteria), no minors pass — the minors are
|
|
978
1018
|
returned to the lead as notes (proposals). A blocking or major finding on a light lot still triggers a correction, and
|
|
979
|
-
the review that follows is the full one (Opus); the cap of two correction passes is unchanged. A bigger lot keeps the
|
|
1019
|
+
the review that follows is the full one (Opus); the cap of two correction passes is unchanged (except the convergence pass above). A bigger lot keeps the
|
|
980
1020
|
chain described above (Opus, two corrections, minors pass). `--dry-run` shows « revue légère » on a light lot.
|
|
981
1021
|
|
|
982
1022
|
```yaml
|
|
@@ -996,7 +1036,7 @@ without `--effort` (see below), so `effort.precheck` has no effect on it and the
|
|
|
996
1036
|
|
|
997
1037
|
```yaml
|
|
998
1038
|
orchestrate:
|
|
999
|
-
effort: { precheck: low, spec: medium, maquette: high, accept: medium, implement: medium, fix: medium, review: high, ux: high } # defaults
|
|
1039
|
+
effort: { precheck: low, spec: medium, maquette: high, fiche: medium, accept: medium, implement: medium, fix: medium, review: high, ux: high } # defaults
|
|
1000
1040
|
```
|
|
1001
1041
|
|
|
1002
1042
|
To measure what a level costs, run the same kind of wave before and after changing the key: each step of
|
|
@@ -1013,10 +1053,11 @@ lot that already has commits is never pre-checked (resuming it is legitimate). `
|
|
|
1013
1053
|
|
|
1014
1054
|
### The spec step of a lot with `screen:`
|
|
1015
1055
|
|
|
1016
|
-
A lot that declares `screen:` (`raf add … --visible --screen page|component|journey`, see [raf](#raf)) gets one more session, `spec`, **after** the pre-check and **before**
|
|
1017
|
-
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:` follows the usual path, unchanged. `--dry-run` lists the step
|
|
1056
|
+
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, when it is `page`, one more session, `spec`, **after** the pre-check and **before**
|
|
1057
|
+
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
|
|
1018
1058
|
(`spec (sonnet)`), its command line and its brief `templates/orchestrate/spec.md`.
|
|
1019
1059
|
|
|
1060
|
+
- **Threshold** (L209): only `screen: page` enters this chain. The measure of 2026-10-12 (no row of the success table reached, about 570 k tokens per lot, 4.5 correction passes per journey lot) narrowed it: `component` and `journey` stay valid values of `screen:` (no existing plan breaks, `raf screen` still sets them) but a lot that carries one follows the ordinary path and gets the ordinary budget, without the 1.3 M flat rate. A lot already in the chain (its sheet, or its `acceptation-<lot>.json`, exists) keeps its sheet and its lock. The `spec: true` step and the back part of a mixed lot do not change. The next measure covers 8 `page` lots.
|
|
1020
1061
|
- **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,
|
|
1021
1062
|
the project's CLAUDE.md and its charter (CSS, neighbouring components, `docs/qa/expectations.md`, existing routes and API contracts), then writes in
|
|
1022
1063
|
`<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`,
|
|
@@ -1034,6 +1075,28 @@ the first implementation: `precheck → spec → maquette → accept → impleme
|
|
|
1034
1075
|
- **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
|
|
1035
1076
|
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).
|
|
1036
1077
|
|
|
1078
|
+
### The spec step of a lot with `spec: true`
|
|
1079
|
+
|
|
1080
|
+
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:
|
|
1081
|
+
`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
|
|
1082
|
+
`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).
|
|
1083
|
+
|
|
1084
|
+
- **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
|
|
1085
|
+
`<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.
|
|
1086
|
+
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).
|
|
1087
|
+
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.
|
|
1088
|
+
- **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 : …`).
|
|
1089
|
+
On a resume the step is skipped when a sheet of the lot (`sujet.lot`) already passes these checks and has no costly hypothesis.
|
|
1090
|
+
- **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,
|
|
1091
|
+
(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.
|
|
1092
|
+
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 : …`).
|
|
1093
|
+
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.
|
|
1094
|
+
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.
|
|
1095
|
+
- **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: page` (`raf spec <id> on` only says so on such a lot and changes nothing; on `component` or `journey`, which follow the ordinary path since L209, `spec: true` makes a back-end spec lot, ordinary budget plus 350 k). 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,
|
|
1096
|
+
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).
|
|
1097
|
+
- **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).
|
|
1098
|
+
- **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.
|
|
1099
|
+
|
|
1037
1100
|
### The mockup review: before any code
|
|
1038
1101
|
|
|
1039
1102
|
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`.
|
|
@@ -1044,27 +1107,39 @@ After a valid spec, a lot with a sheet gets a UX review of its mockup, `maquette
|
|
|
1044
1107
|
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
|
|
1045
1108
|
`#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.
|
|
1046
1109
|
- **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
|
|
1047
|
-
still not conforming, the lot is handed back with what remains (`maquette non conforme après 2 revues : …`) and nothing is implemented. 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`.
|
|
1110
|
+
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`.
|
|
1048
1111
|
- **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.
|
|
1049
1112
|
- **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.
|
|
1050
1113
|
- **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`.
|
|
1051
1114
|
|
|
1052
1115
|
### The accept step: red acceptance tests and their lock
|
|
1053
1116
|
|
|
1054
|
-
After a valid spec, and only when `cadence.yaml` declares `orchestrate.accept` (the project's **dedicated command**, which
|
|
1117
|
+
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
|
|
1055
1118
|
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.
|
|
1056
1119
|
`--dry-run` lists the step (`accept (sonnet)`) and its brief `templates/orchestrate/accept.md`.
|
|
1057
1120
|
|
|
1058
1121
|
- **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
|
|
1059
1122
|
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[]`,
|
|
1060
1123
|
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.
|
|
1124
|
+
- **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/`):
|
|
1125
|
+
|
|
1126
|
+
```yaml
|
|
1127
|
+
orchestrate:
|
|
1128
|
+
accept:
|
|
1129
|
+
- cd frontend && npx vitest run -c vitest.acceptation.config.ts
|
|
1130
|
+
- cd backend && npx jest -c jest.acceptation.config.js
|
|
1131
|
+
```
|
|
1132
|
+
|
|
1133
|
+
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.
|
|
1134
|
+
|
|
1135
|
+
**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.
|
|
1061
1136
|
- **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
|
|
1062
|
-
runner configuration shared by `orchestrate.test` and the CI excludes the files listed in every acceptation file (`acceptation-<lot>.json`) whose `vert` is `false
|
|
1137
|
+
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, always, red or green, those of an acceptation with `"e2e": true` (a browser test needing the build, L203: `acceptationE2e()` lists them for the e2e suite run after the build) — and only the dedicated command runs them. `templates/acceptation-runner.mjs` is the helper the session copies
|
|
1063
1138
|
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`:
|
|
1064
1139
|
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
|
|
1065
1140
|
(paths hard-coded), the session must not commit red tests and puts the question in its report.
|
|
1066
1141
|
**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:
|
|
1067
|
-
`CADENCE_ACCEPTATION=<path of the acceptation file> <command>` (with a `{acceptation}` in the command, write the path there too). 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.
|
|
1142
|
+
`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 — **except an `"e2e": true` acceptation**, which never joins them: wire its `acceptationE2e()` files into the e2e suite run after the build (`npm run build && npx playwright test`). The dedicated `orchestrate.accept` command still runs those files for the red check and the return to green, so it must build and start what the browser needs.
|
|
1068
1143
|
- **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
|
|
1069
1144
|
**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
|
|
1070
1145
|
(`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).
|
|
@@ -1073,8 +1148,9 @@ session, `accept` (L173): `precheck → spec → maquette → accept → impleme
|
|
|
1073
1148
|
- **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
|
|
1074
1149
|
(`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
|
|
1075
1150
|
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).
|
|
1151
|
+
- **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; for a delivered lot, see the end of this item), 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`; for a delivered lot, see the end of this item), 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 neither in progress nor delivered with a green acceptation. 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. **A delivered lot (L212):** a lot whose acceptation is green (`vert: true`) and whose sealed test turns out unstable while the contract does not change (seen: a tab read as « blank » in CI) had no way out but the « sheet modified in the same lot » exception. `cadence spec reseal <lot> <test> --reason "why" --porteur <lot in progress>` now covers it, with the same guards (sheet unchanged since the red commit, no other listed test touched, no wave, `--reason`) and three differences: `--porteur` is required and names the lot in progress that carries the fix (refused if it is the delivered lot itself, unknown or not `doing`); the commit cites the **carrier** (`test(L113): acceptation rescellée du lot livré L47, <test> : <reason>`) and so does the plan note and its commit, the delivered lot being closed; the dated `resceaux` entry also records `porteur`, and `vert` stays `true`. `--porteur` on a lot in progress, or `spec reseal` on a delivered lot without `--porteur`, is refused.
|
|
1076
1152
|
- **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 …`;
|
|
1077
|
-
`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.
|
|
1153
|
+
`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 (an `"e2e": true` acceptation excepted: its files stay in the e2e suite after the build); 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.
|
|
1078
1154
|
- **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).
|
|
1079
1155
|
|
|
1080
1156
|
### The downstream briefs: sheet, rule → test → green, conformity, Hypothèses
|
|
@@ -1164,6 +1240,25 @@ The sessions of the wave also get `.cadence/runs/<wave>/tool/bin` (the `raf` and
|
|
|
1164
1240
|
`PATH`**, ahead of the per-project Node below and of the usual `PATH`: the `raf` a reviewer runs (`raf commits`…) is the
|
|
1165
1241
|
snapshot's, not the installed one. A wave without a snapshot leaves the `PATH` as it is.
|
|
1166
1242
|
|
|
1243
|
+
**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
|
|
1244
|
+
`PATH` used to be whatever the working repository last built. The snapshot protects the wave running, not that installed tool, and a wave's
|
|
1245
|
+
sessions run `npm run build`, `npm install`… The code in service now lives in a **separate copy**: a detached git worktree built there,
|
|
1246
|
+
`<root>/releases/<sha12>`, with `<root>/service` pointing at the current one (`<root>` is `~/.local/share/cadence`), and `~/.local/bin/raf` and
|
|
1247
|
+
`~/.local/bin/cadence` linked to `<root>/service/bin/`. Nothing in the working repository (`npm run build`, `prepare`, `npm install`, `npm ci`,
|
|
1248
|
+
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.
|
|
1249
|
+
|
|
1250
|
+
The lead updates the copy after the review, once the lot is accepted (`raf done`):
|
|
1251
|
+
|
|
1252
|
+
```
|
|
1253
|
+
npm run service -- <sha> # [--root dir] [--bin-dir dir] [--repo dir]
|
|
1254
|
+
```
|
|
1255
|
+
|
|
1256
|
+
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)
|
|
1257
|
+
cite a lot whose status is not `done` (`plan:` commits are ignored); a lot `dropped` is let through when every one of its commits is undone by a `git revert` present under the sha (L207), and still blocks when one is not. It builds the new copy aside (`npm ci --ignore-scripts`, then `tsc`) and switches
|
|
1258
|
+
`service` and the two links only once the build succeeded (atomic renames): a failed install changes nothing. The previous copy is kept for a
|
|
1259
|
+
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
|
|
1260
|
+
(bin, dist, package.json).
|
|
1261
|
+
|
|
1167
1262
|
### A lot whose work is in a neighbouring repository
|
|
1168
1263
|
|
|
1169
1264
|
Some lots are done in another repository that is not a cadence project (B64 of `maritime-atlas` lives in
|
|
@@ -1235,11 +1330,12 @@ every wave the same value: each wave counts ALL live sessions, whatever their sl
|
|
|
1235
1330
|
count has reached ITS OWN cap, so with different caps the highest one can push the total past the lowest
|
|
1236
1331
|
(which then waits). A session that finds no free slot **waits** (the wave is not refused; the journal says
|
|
1237
1332
|
`en attente d'un créneau de session depuis …`, repeated every minute, then `créneau de session obtenu après …`).
|
|
1333
|
+
`cadence orchestrate --waits [--since YYYY-MM-DD]` adds those waits up from the journals of `.cadence/runs/` of the launch folder — per day (cumulated wait, number of waits, waves, quota stops — one per "→ suspended — quota atteint" line of the journals, counted on the day of that line, so a wave resumed and stopped again on another day counts once on each day, not once as a wave, tokens) and per wave that waited (the longest wait, a wait that never got its slot) — to decide the cap from figures; each wait is paired with its lot (the journal line carries `project:lot`), so two lots of one wave waiting at the same time (one per repository) are each counted once, and only a wait that never got its slot is reported as such; journals from before this carry no lot and are paired per wave. it reads only, and refuses any other action in the same call. The figures of 2026-10-12 and the cost of a third slot are in `docs/mesures/attente-creneaux-2026-10-12.md`.
|
|
1238
1334
|
A slot or a registry entry is owned by a pid **and** its start time: a reused pid is a dead owner. Wave
|
|
1239
1335
|
identifiers are reserved atomically (`-2`, `-3` suffix when two waves start in the same minute; an existing
|
|
1240
1336
|
`--wave` is refused). The registry of live waves and the slots live under `~/.cadence/orchestrate/` (`CADENCE_HOME`
|
|
1241
1337
|
to move it): `cadence orchestrate --status` lists, from any folder, the live waves, the repositories each
|
|
1242
|
-
still holds (those not yet released), the cap of each wave, the slots in use and the **free slots** (`créneaux libres : N sur
|
|
1338
|
+
still holds (those not yet released), the cap of each wave, the slots in use and the **free slots** (`créneaux libres : N sur M`: M — the cap set with `--max-sessions` or `CADENCE_MAX_SESSIONS`, 2 by default — minus, for each live wave, the smaller of its cap and the repositories it still holds — the figure the `lead` skill reads before starting a subagent; the lead never raises the cap itself, that is the human's decision, L208). Without an identifier it then prints the table of the wave launched most recently from this folder (by launch time, not by alphabetical order of the identifier).
|
|
1243
1339
|
|
|
1244
1340
|
**Guards, imposed by the code**: a global cap of simultaneous sessions, one wave per repository at
|
|
1245
1341
|
a time (above); `Agent`, `git push`, `cadence deliver`, `raf done|review|ux` are denied to the sessions; a
|
|
@@ -1250,8 +1346,8 @@ upstream ref and `git ls-remote` are compared with the "before", and a read-only
|
|
|
1250
1346
|
`CADENCE_ORCHESTRATED` is set.
|
|
1251
1347
|
|
|
1252
1348
|
**Budget**: the wave counts input + cache writes + output tokens (default 2 M); cache reads are kept and
|
|
1253
|
-
shown apart. Each lot also has its own budget
|
|
1254
|
-
`--dry-run`): it bounds the *writing* passes, never the reviews. A lot that spent it gets no further implementation or
|
|
1349
|
+
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: page` gets 1.3 M whatever its estimate (`component` and `journey` keep the ordinary budget; 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
|
|
1350
|
+
`--dry-run` with its basis): it bounds the *writing* passes, never the reviews. A lot that spent it gets no further implementation or
|
|
1255
1351
|
fix and is handed back to the lead, but its review (and UX review) is played first; a fix pass starts only if
|
|
1256
1352
|
the remaining budget can also pay the review that follows it (65 k tokens reserved: a fixed amount close to the 90th
|
|
1257
1353
|
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
|
|
@@ -1262,7 +1358,7 @@ the red tests: the pass it names is the one whose tests were red, counted by its
|
|
|
1262
1358
|
finish, the wave is *suspended* (exit code 3) and `--resume --budget …` continues. A session that returns
|
|
1263
1359
|
nothing readable, times out (45 min for work, 25 for a review) or fails is not retried; the lot is handed
|
|
1264
1360
|
back with the cause. Exit codes: 0 every lot ready · 1 at least one lot handed back (question, failure,
|
|
1265
|
-
review still not compliant after two passes) · 2 refused before acting · 3 wave suspended.
|
|
1361
|
+
review still not compliant after two passes, or three when it converges) · 2 refused before acting · 3 wave suspended.
|
|
1266
1362
|
|
|
1267
1363
|
**Stacked lots** (L76): lots of one repository commit on top of each other on `main`. When a ready lot sits under a lot that
|
|
1268
1364
|
is not ready (handed back, failed…), the final table adds a line `<project>:<lot> — livrable jusqu'à <sha> … : git push origin <sha>:main && cadence deliver --sha <sha>`:
|
|
@@ -1317,9 +1413,10 @@ orchestrate:
|
|
|
1317
1413
|
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
|
|
1318
1414
|
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)
|
|
1319
1415
|
maquette: true # default: UX review of the mockup between spec and accept (see « The mockup review »); false skips it
|
|
1416
|
+
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
|
|
1320
1417
|
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)
|
|
1321
1418
|
prodAccess: false # default: wave sessions get no access to production (see « Production access of the sessions »); true lifts it for this project
|
|
1322
|
-
effort: { review: xhigh } # effort level per pass (see « Effort level per pass »): precheck, spec, maquette, accept, implement, fix, review, ux
|
|
1419
|
+
effort: { review: xhigh } # effort level per pass (see « Effort level per pass »): precheck, spec, maquette, fiche, accept, implement, fix, review, ux
|
|
1323
1420
|
ux: http://localhost:4200 # a URL, a launch command, or { command, url, timeout? } — for the UX review (see below)
|
|
1324
1421
|
permissionMode: auto # default
|
|
1325
1422
|
addDirs: [/home/me/projects/tmp] # extra directories the sessions may use
|
|
@@ -1441,12 +1538,13 @@ repository with `cadence skills install` (to `.claude/skills/cadence-*` and
|
|
|
1441
1538
|
no model: see [lead tour](#lead-tour)) prints one line of facts per project, you choose the priorities, the lots are delegated with
|
|
1442
1539
|
`cadence orchestrate` (fresh short sessions with a standard brief — test first,
|
|
1443
1540
|
README and usage documentation updated with the change, commits citing the lot, no push — reviewed by the `code-reviewer` agent, see
|
|
1444
|
-
[orchestrate](#orchestrate); a lot with
|
|
1541
|
+
[orchestrate](#orchestrate); a lot with `screen: page` 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
|
|
1445
1542
|
one project at a time; a delivery that changes what a page shows or what it is
|
|
1446
1543
|
served is then checked in the running app by the `qa-reviewer` agent, whose
|
|
1447
|
-
blocking findings come back to you.
|
|
1448
|
-
subagents at most, never two in the same repository. The whole flow is drawn in
|
|
1449
|
-
[docs/lead.md](docs/lead.md)
|
|
1544
|
+
blocking findings come back to you. As many
|
|
1545
|
+
subagents as the session cap at most (2 by default, `CADENCE_MAX_SESSIONS`), never two in the same repository. The whole flow is drawn in
|
|
1546
|
+
[docs/lead.md](docs/lead.md); how a lot, a wave, the lead and the service of cadence itself fit together, in four figures, is in
|
|
1547
|
+
[docs/fonctionnement.md](docs/fonctionnement.md).
|
|
1450
1548
|
- **ux-reviewer** (agent): captures at 1440 and 390 px, findings grounded in a
|
|
1451
1549
|
named rule (Nielsen, WCAG 2.2 AA) or a measurement, ranked, turned into
|
|
1452
1550
|
`raf add --parent` sub-tasks, and a one-line verdict for `raf ux`. It never
|
|
@@ -1592,11 +1690,11 @@ From 1.0.0 cadence follows [semantic versioning](https://semver.org): what is li
|
|
|
1592
1690
|
**Guaranteed**
|
|
1593
1691
|
|
|
1594
1692
|
- **Commands and options** of `raf` and `cadence` (`cadence raf …` is `raf …`): `init`, `add`, `start`, `done`, `drop`,
|
|
1595
|
-
`note`, `did`, `public`, `ux`, `review`, `commits`, `show`, `list`, `now`, `ignore`, `check`, `gantt`, `hook`;
|
|
1693
|
+
`note`, `did`, `public`, `screen`, `spec`, `ux`, `review`, `commits`, `show`, `list`, `now`, `ignore`, `check`, `gantt`, `hook`;
|
|
1596
1694
|
`cadence news`, `session` (`start`, `close`, `next`, `context`), `lead tour`, `corrections`, `deliver`, `verify`, `orchestrate`,
|
|
1597
|
-
`skills`, `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);
|
|
1695
|
+
`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);
|
|
1598
1696
|
their options and exit codes as this README documents them. A new command or option is a minor change.
|
|
1599
|
-
- **The keys of `cadence.yaml`**: `plan`, `news`, `hook`, `session`, `deliver`, `orchestrate`, `docs`, `qa`, `priority`
|
|
1697
|
+
- **The keys of `cadence.yaml`**: `plan`, `news`, `hook`, `session`, `deliver`, `orchestrate`, `docs`, `qa`, `priority`, `depth`, `lead` (`lead.ux`)
|
|
1600
1698
|
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.
|
|
1601
1699
|
- **The plan file** (`docs/plan/raf.yaml`): `project`, `prefix`, `since`, `ignore`, `lots` (with their
|
|
1602
1700
|
fields, `tasks`, `notes`, `repos`) and `acknowledged`, and the plan formats `plan:` in `cadence.yaml` can read.
|
|
@@ -1613,7 +1711,7 @@ From 1.0.0 cadence follows [semantic versioning](https://semver.org): what is li
|
|
|
1613
1711
|
- The **`cadence-hud` band**: its segments, colours and layout; it is versioned on its own.
|
|
1614
1712
|
- The **wave journals** under `.cadence/runs` and the files `cadence orchestrate` keeps there.
|
|
1615
1713
|
- The wording of the briefs and of the instructions inside the skills and the agents.
|
|
1616
|
-
- The **format of the screen sheet
|
|
1714
|
+
- 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.
|
|
1617
1715
|
|
|
1618
1716
|
There is no schema version and no migration: a file written by an earlier release keeps working, and a key a
|
|
1619
1717
|
release adds is optional.
|
|
@@ -10,10 +10,13 @@ Follow the brief you are given. The method:
|
|
|
10
10
|
|
|
11
11
|
1. **Read the sheet and the mockup, then the project's way of testing.** `fiche.yaml` (fields, rules, actions), `maquette.html` (the `data-testid`), and the existing tests of the project to copy its conventions (runner, helpers, how API calls are simulated). Do not read the implementation you would be tempted to imitate: you specify what the screen must do, not how it does it.
|
|
12
12
|
2. **One test per planned name.** Each rule has `tests[]` names (`R3 — …`): write exactly those cases, with exactly those names, selectors = `data-testid` = field ids, API calls simulated from `actions[]`.
|
|
13
|
-
3. **Wire the runner.** Copy the runner template of the brief, make the project's ordinary test config (shared by the project's test command and its CI) exclude the files of the the lot's acceptation file (`acceptation-<lot>.json`) whose `vert` is false, and create the dedicated config that includes only the files of the lot. If the project's CI or test command do not use that config (hard-coded paths), do not commit red tests: stop and put the question in the report.
|
|
14
|
-
|
|
13
|
+
3. **Wire the runner.** Copy the runner template of the brief, make the project's ordinary test config (shared by the project's test command and its CI) exclude the files of the the lot's acceptation file (`acceptation-<lot>.json`) whose `vert` is false, and always those of an acceptation with `"e2e": true` (see below), and create the dedicated config that includes only the files of the lot. If the project's CI or test command do not use that config (hard-coded paths), do not commit red tests: stop and put the question in the report.
|
|
14
|
+
If the tests drive a browser and need the build (Playwright…), set `"e2e": true` in the acceptation file (`{ "lot", "fiche", "fichiers", "vert": false, "e2e": true }`): `acceptationIgnored()` then excludes them even once green, and `acceptationE2e()` lists them for the project's e2e suite, run after the build (`npm run build && npx playwright test`, in the CI after the build step). Wire that suite; the ordinary runner and the unit CI must never run them.
|
|
15
|
+
4. **Red for the right reason.** Run the dedicated command (by hand, outside the cycle, with `CADENCE_ACCEPTATION=<path of the acceptation file>`; for a command of a list, also `CADENCE_ACCEPTATION_ROOT=<root of the command>`, the folder of its leading `cd <folder> &&`, else the repository `.`): every test must fail because the feature is missing. A test that passes before the code proves nothing; a test that fails on a typo proves nothing either. Run the project's ordinary tests: they must stay green.
|
|
15
16
|
5. **One commit**, test files + the lot's acceptation file (`acceptation-<lot>.json`) (`lot`, `fiche`, `fichiers`, `vert: false`) + runner config, explicit paths, a message that cites the lot, a clean tree.
|
|
16
17
|
|
|
18
|
+
For a back sheet (`sujet`, `cas`, `contrats[]`, no mockup), the cases call the contracts of `contrats[]` as close as possible — the controller or the service for an HTTP call, the method of the job for a `job` — and simulate the external sources from `entree`; there are no `data-testid`.
|
|
19
|
+
|
|
17
20
|
- You edit only tests, the runner config and the lot's acceptation file (`acceptation-<lot>.json`): never application code, the sheet, the mockup or the plan. Do not push, deliver, run `raf start|done|note|review|ux`, or launch subagents.
|
|
18
21
|
- Never write `vert: true` or the fingerprints: the program seals the file and the cycle turns it green.
|
|
19
22
|
- Give the report in the structured output the brief asks for.
|