@sylad/cadence 1.34.1 → 1.35.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/NOTICE +28 -0
- package/README.md +1 -1
- package/agents/qa-reviewer.md +5 -4
- package/agents/spec-writer.md +2 -0
- package/agents/ux-reviewer.md +28 -0
- package/dist/cli.js +13 -29
- package/dist/config.js +8 -21
- package/dist/corrections-sans-code.js +12 -0
- package/dist/deliver.js +4 -4
- package/dist/gate-config.js +47 -0
- package/dist/orchestrate/accept.js +5 -2
- package/dist/orchestrate/baseline.js +57 -0
- package/dist/orchestrate/briefs.js +4 -1
- package/dist/orchestrate/cycle.js +67 -53
- package/dist/orchestrate/gate-notes.js +27 -0
- package/dist/orchestrate/gate-parts.js +135 -0
- package/dist/orchestrate/gate-place.js +66 -0
- package/dist/orchestrate/state.js +1 -1
- package/dist/orchestrate/workers.js +31 -4
- package/dist/plan-commit.js +4 -2
- package/dist/plan-uncommitted.js +26 -0
- package/dist/release.js +9 -7
- package/dist/remote-gate.js +278 -0
- package/dist/verify-gate-remote.js +55 -0
- package/dist/verify-gate.js +37 -28
- package/docs/corrections.md +4 -0
- package/docs/deliver.md +4 -2
- package/docs/news.md +2 -4
- package/docs/orchestrate.md +19 -0
- package/docs/overview.md +1 -0
- package/docs/raf.md +3 -3
- package/docs/releasing.md +16 -7
- package/docs/remote-gate.md +89 -0
- package/docs/skills.md +5 -2
- package/docs/whats-new.md +3 -0
- package/package.json +3 -1
- package/skills/lead/SKILL.md +1 -1
- package/templates/orchestrate/spec.md +3 -1
package/docs/overview.md
CHANGED
|
@@ -70,6 +70,7 @@ The two plugins are independent. `cadence@cadence` carries the rituals, which ca
|
|
|
70
70
|
| [docs/spec.md](spec.md) | the screen and back-end sheets, `cadence spec check\|qa\|reseal\|green` |
|
|
71
71
|
| [docs/lead.md](lead.md) | the lead workflow and `cadence lead tour` |
|
|
72
72
|
| [docs/ref.md](ref.md) | reference documents: `cadence ref add` (rendered pages, positioned text, images, figure index), `cadence ref measure` (colours, WCAG contrast, boxes, OCR, font size), `cadence ref check` (the inventory schema, `templates/inventaire.json`), `cadence ref eval` (recall, precision, false « read », tokens per page against a known inventory), `cadence ref corpus` (the synthetic corpus with a known truth, rendered by Playwright) `cadence ref coverage` (which elements of the inventory no done lot covers, nor a written exclusion), `cadence ref diff` (reconciles two readings of a document by program) and `cadence ref analyse` (one reading by the `reference-analyst` agent; `--double` for two independent readings, `ref diff`, a third look by `reference-verifier` and the reconciled inventory, an option whose measurement showed no gain; 20 pages at most per reading) |
|
|
73
|
+
| [docs/remote-gate.md](remote-gate.md) | `orchestrate.gate.host` and `gate.install`: the gate (`verify --gate`, a wave's lot gate, baseline and replay alone) played by ssh on another machine, dependency cache by lockfile fingerprint, local fallback |
|
|
73
74
|
| [docs/stabilite.md](stabilite.md) | what is guaranteed from 1.0.0 and what is not |
|
|
74
75
|
| [docs/qualite.md](qualite.md) | code-quality guard rails: ESLint (typescript-eslint, sonarjs), knip and jscpd compared to a versioned baseline by a ratchet (`npm run qualite`, `--init`, `--ecrire`, `--migrer`, `--contre`), in the wave's gate and the CI; the recipe for TypeScript, Python, Java and shell |
|
|
75
76
|
|
package/docs/raf.md
CHANGED
|
@@ -62,7 +62,7 @@ raf gantt # .cadence/gantt.html (next to the plan)
|
|
|
62
62
|
| `raf add`, `raf note`, `raf done` during an integration (L425) | while a wave integrates a lot of the repository (the integration lock is held by a live process), these three commands write the plan as usual and print on stderr `avertissement : intégration en cours (vague …, pid …) — …`: the plan is a tracked file of the main tree, and an integration that sees it modified refuses its lot (`arbre du dépôt modifié`, 2026-10-29: a `raf add` of the lead during the integration of L416). Commit the plan right away. Exit code 0; nothing is printed in a lot's worktree (its plan is not the tree the integration checks) nor when the lock belongs to a dead process |
|
|
63
63
|
| `raf add`, `raf note`, `raf done` while a wave works in the main tree (L475) | when the repository's orchestration lock is held by a live wave and one of its lots is in `implementing`, `reviewing` or `fixing` **without a worktree** (a wave without worktrees, or a lot whose worktree folder does not exist), these commands write the plan as usual and print on stderr `avertissement : la vague … travaille dans l'arbre principal de ce dépôt (projet:lot) — …`: a plan commit of the lead then hands the lot back at review (2026-10-30: cadence L458 handed back by a plan commit during its review). Write the plan without committing it, or commit once the step ends. Exit code 0; nothing is printed for lots that are queued, in question, ready, handed back, failed or suspended, for lots playing in their worktree, from a worktree of the repository, from a session of the wave itself (`CADENCE_ORCHESTRATED` set), when the lock belongs to a dead process, or when the wave's state is unreadable |
|
|
64
64
|
| `raf public <id> "title"` · `raf public <id> --clear` | set, replace or remove the public title of a lot |
|
|
65
|
-
| `raf start <id>` · `raf done <id> [--force]` · `raf drop <id> [--reason text]` | dated transitions (`done` refuses open sub-tasks unless `--force`, with the code-review gate active (`raf review enable`) a lot whose commits its review does not cover, **and a lot whose recorded review verdict says `non conforme` / `not compliant` even when it covers every commit** (L476: `non conforme : 1 bloquant` at the last commit no longer closes; `conforme après 1 correction` is compliant; redo the review with `raf review <id> "verdict"` after the fix, or `--force`), and a lot whose `acceptation-<lot>.json` is still `vert: false`, L366: closed like that it would lock every later wave of the repository, see `cadence spec green`; with `--force` it only warns on stderr. Like every `raf` command it only writes the plan file and **never commits** it: when the plan or a file `plan.onWrite` produces is left with changes, `done`
|
|
65
|
+
| `raf start <id>` · `raf done <id> [--force]` · `raf drop <id> [--reason text]` | dated transitions (`done` refuses open sub-tasks unless `--force`, with the code-review gate active (`raf review enable`) a lot whose commits its review does not cover, **and a lot whose recorded review verdict says `non conforme` / `not compliant` even when it covers every commit** (L476: `non conforme : 1 bloquant` at the last commit no longer closes; `conforme après 1 correction` is compliant; redo the review with `raf review <id> "verdict"` after the fix, or `--force`), and a lot whose `acceptation-<lot>.json` is still `vert: false`, L366: closed like that it would lock every later wave of the repository, see `cadence spec green`; with `--force` it only warns on stderr. Like every `raf` command it only writes the plan file and **never commits** it: when the plan or a file `plan.onWrite` produces is left with changes, `done`, `ux <lot>` and `review <lot>` print the `git add` / `git commit` command that takes them, the subject from the `plan.commit` template, L371) |
|
|
66
66
|
| `cadence spec green <lot>` | L366: run the dedicated acceptance command (`orchestrate.accept`) on a lot driven or closed by hand; green, set `vert: true` in its `acceptation-<lot>.json` and commit that file alone (subject `chore(<lot>): acceptation verte, vert: true posé par cadence spec green` or the `plan.commit` template; the resealed tests are listed in the commit body, never in the subject), resealing the fingerprints of the listed tests refined since the red commit (journal `resceaux`) so the lock goes quiet; a listed test changed but not committed is refused. Red: exit 1, nothing changed. Refused for a `todo` lot, during a wave, and while an unfinished wave keeps a lot of the repository open; see [orchestrate](orchestrate.md) |
|
|
67
67
|
| `raf todo <id> [--reason text]` | put a started lot back to `todo` (`doing` → `todo`, `started:` removed, dated note « remis en attente : reason »): refused when work commits cite the lot (plan-only and version commits do not count, as `raf commits`), or on a sub-task; sub-tasks and other keys are left as they are. **Reopening** (L396): on a `done` or `dropped` lot, `raf todo` is THE command — never the YAML — that reopens it (`→ todo`, `finished:` removed, `started:` kept so its commits stay its own, dated note « rouvert (était done) : reason »); `raf start`/`raf done`/`raf drop` on a closed lot say so (`L3 est done ; le rouvrir si c'est voulu : raf todo L3`). An archived lot reopened this way comes back into the plan file at that write |
|
|
68
68
|
| `raf migrate [--dry-run]` | move `docs/plan/raf.yaml` to `.cadence/raf.yaml` and rewrite the readers of the old path in the repository, see [Moving the plan: `raf migrate`](#moving-the-plan-raf-migrate) |
|
|
@@ -169,10 +169,10 @@ plan:
|
|
|
169
169
|
commit: 'chore({lot}): {action} (orchestrate {vague})'
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
-
- `raf done <lot
|
|
172
|
+
- `raf done <lot>`, `raf ux <lot> "verdict"` and `raf review <lot> "verdict"` (L509) do not commit the plan (raf never does, see below) but print the command that would — the plan and the files `plan.onWrite` regenerated, so a published `plan.json` is never left behind — with this template: `{action}` is `terminé` (`verdict UX enregistré` for `ux`, `revue de code enregistrée` for `review`) and, outside a wave, the parenthesised or bracketed group holding `{vague}` is dropped (`chore(L12): terminé`). Without a template: `plan: L12 terminé`.
|
|
173
173
|
- `{lot}` is required (a commit must cite its lot); `{action}` is what was done (`démarré`, `revue de code enregistrée`, `revue de code notée`, `hypothèses de la fiche <sujet> notées`, `mineurs de la revue de <revue> notés`, `règles R1, R2 sourcées par la réponse du lead`, `test d'acceptation rescellé (<test>)`);
|
|
174
174
|
`{vague}` is the wave id. A word between braces that is none of these, an empty template or one on several lines is refused when the config is read.
|
|
175
|
-
- Outside a wave (`spec reseal`) there is no wave: the parenthesised group that holds `{vague}` is dropped, so the template above gives `chore(L17): test d'acceptation rescellé (…)`.
|
|
175
|
+
- Outside a wave (`spec reseal`) there is no wave: the parenthesised or square-bracketed group that holds `{vague}` is dropped, so the template above gives `chore(L17): test d'acceptation rescellé (…)`.
|
|
176
176
|
- Absent, the subject is the one above, unchanged. The key needs `plan:` to be an object (`plan: .cadence/raf.yaml` as a plain path has nowhere to put it: write `plan: { path: …, commit: … }`).
|
|
177
177
|
- `cadence spec green` (L366) commits its `acceptation-<lot>.json` with the template too when there is one (`{action}` = `acceptation verte, vert: true posé par cadence spec green`); without one its subject stays `chore(<lot>): …`. The tests it reseals are listed in the commit body, never in the subject, which therefore does not grow with them.
|
|
178
178
|
- The commit of the fiche sourced by the lead's answer takes the template too (its default, `docs(<lot>): règle R3 sourcée par la réponse du lead (orchestrate <wave>)`, is already Conventional but can exceed `header-max-length` with several rules and a wave id). The `test(<lot>): …` and `chore(<lot>): …` commits of the cycle (acceptation sealed, `vert: true` set) and the work commits are already Conventional and are not templated.
|
package/docs/releasing.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
A version exists in three places and is published in two; a release does all of it, in this order.
|
|
6
6
|
`cadence release patch|minor|major [--dry-run]` (L341) prepares step 1 and prints steps 2 to 6 in order; it publishes nothing.
|
|
7
|
+
Between the version commit and the gate it also prints a **provisional local tag** `v<version>` (L508), see step 2.
|
|
7
8
|
|
|
8
9
|
1. Bump `version` in `package.json` (then `npm install` to refresh `package-lock.json`),
|
|
9
10
|
`.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json`, and write the version's section of
|
|
@@ -16,10 +17,14 @@ A version exists in three places and is published in two; a release does all of
|
|
|
16
17
|
in that commit, not before the review. A commit that touches any other file
|
|
17
18
|
— or another field of a manifest, or a dependency in `package-lock.json` — is work like any other and has
|
|
18
19
|
to be reviewed.
|
|
19
|
-
2.
|
|
20
|
+
2. Put the provisional local tag on that commit, then replay the project's gate on it (L508). Some tests read the latest tag
|
|
21
|
+
(`test/changelog.test.ts` checks that a lot cited under the latest tagged version has a commit in that tag); run before the tag
|
|
22
|
+
exists, they still see the previous version, which is how 1.34.0 was tagged green and failed its publication. The tag is made first, local only, and the gate,
|
|
23
|
+
the fresh-clone replay and the evaluation below each remove it (`git tag -d`, the step stays red) when they fail; nothing is pushed
|
|
24
|
+
until step 4. The gate: `cadence verify --gate --sha HEAD` (L380). The version commit empties
|
|
20
25
|
`## [Unreleased]` of `CHANGELOG.md`, and a test that read only that section would pass before it and fail after — the red
|
|
21
26
|
publish run of 1.14.0 (L368) and the stopped 1.15.2 (L380) — so the suite is run on the commit that will be tagged, before the
|
|
22
|
-
billed evaluation and before the
|
|
27
|
+
billed evaluation and before the push. Red: fix it in a commit of its own and redo the version commit. A test that looks
|
|
23
28
|
for the entry of a lot in the CHANGELOG reads the section that carries it (`[Unreleased]` or the published version) through
|
|
24
29
|
`changelogSectionOf` (`test/changelog-section.ts`); `test/changelog-garde.test.ts` refuses a test that selects `## [Unreleased]`
|
|
25
30
|
of the repository's CHANGELOG itself. The gate runs in the lead's tree or in a copy of it, both full of files git does not track
|
|
@@ -27,11 +32,14 @@ A version exists in three places and is published in two; a release does all of
|
|
|
27
32
|
`hud-*` tests that read those types, present in every local tree and absent from the CI checkout (L446). So the same commit is
|
|
28
33
|
also replayed **in a fresh `git clone`** — the next step the command prints: `git clone --no-hardlinks` of the repository
|
|
29
34
|
(only what is committed), `npm ci`, then `npm run typecheck` and `npm test` (those the package declares; a package with neither gets no
|
|
30
|
-
such step), the clone removed whatever the result. Red: no evaluation
|
|
35
|
+
such step), the clone removed whatever the result. Red: no evaluation, tag removed. `.github/workflows/tests.yml` does the same on every
|
|
31
36
|
push to `main`, from a fresh checkout.
|
|
37
|
+
With `orchestrate.gate.host` ([remote-gate.md](remote-gate.md)) the gate is played on another machine that receives only the commit
|
|
38
|
+
(`refs/cadence-gate/<sha>`), so that host does not see the provisional tag and a test reading the latest tag passes there without checking
|
|
39
|
+
anything; only the local fresh-clone replay, which does receive the tag, catches it, and it is printed only when the package declares `test` or `typecheck`.
|
|
32
40
|
3. Run the plugin evaluation, `npm run eval:plugin` (billed, see [Evaluating the plugin](#evaluating-the-plugin-before-a-release)),
|
|
33
|
-
on that version commit; a case below the threshold stops the release until you have read it in the report.
|
|
34
|
-
4. `git
|
|
41
|
+
on that version commit; a case below the threshold stops the release and removes the tag (step 2) until you have read it in the report; if you judge the case a false negative, run `git tag v<version>` again on the version commit before step 4.
|
|
42
|
+
4. `git push origin main v<version>` (the tag already exists, step 2; `git tag v<version>` is not run twice) — the tag starts `.github/workflows/publish.yml`,
|
|
35
43
|
which publishes to npm through Trusted Publishing (OIDC, no token stored anywhere): it checks the tag
|
|
36
44
|
matches `package.json`, `.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json` and that `CHANGELOG.md` has a `## [x.y.z]` section for it (no section, no publication), then `npm publish --provenance`, where `prepublishOnly` runs the type-check, the quality ratchet (`npm run qualite`, [qualite.md](qualite.md): exit 1 when a measure got worse, 2 when a tool crashed or the baseline is missing) and the
|
|
37
45
|
tests and `prepare` builds `dist/`; a red suite or a measure that got worse stops the publication (fix the code, then `npm run qualite:cliquet` locks the gain); then it creates the GitHub release with that CHANGELOG section as its text. The trusted publisher is declared
|
|
@@ -85,8 +93,9 @@ introduction (the newest version first, as the file is read). Exit code 1 when a
|
|
|
85
93
|
version files are written, the commit is not ready. `--dry-run` reads the forms the same way (nothing is written) and exits 1 on the same findings, so the forms can be checked before the real run.
|
|
86
94
|
|
|
87
95
|
It prints the lead's steps, in order, and runs none: the `git add` of exactly the files of the version commit and the commit,
|
|
88
|
-
|
|
89
|
-
`
|
|
96
|
+
the provisional tag `git tag v<x.y.z>` (L508: made before the gate, removed by `git tag -d` when the gate, the clone replay or the evaluation is red),
|
|
97
|
+
`cadence verify --gate --sha HEAD` (always printed, before the evaluation), the replay in a fresh clone (L446: `git clone --no-hardlinks`, `npm ci`, `npm run typecheck` and `npm test` for the scripts `package.json` declares, none printed when it declares neither),
|
|
98
|
+
`npm run eval:plugin -- --trust-plugin` (only when `package.json` has that script), `git push origin <branch> v<x.y.z>`,
|
|
90
99
|
`gh run watch`, `npm view <package> version` (not for a private package) and, only with a `.claude-plugin/plugin.json`,
|
|
91
100
|
the plugin update: `claude plugin marketplace update <marketplace>` first (without it the installed plugin stays at the old
|
|
92
101
|
version; skipped when the marketplace has no name), then `claude plugin update <plugin>@<marketplace>`, then `/reload-plugins`
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Remote gate: build and tests played on another machine (L403)
|
|
2
|
+
|
|
3
|
+
A project whose build and tests are heavy can play its gate on a second machine through ssh, at the sha
|
|
4
|
+
it pushes there, with a cache of dependencies. It is one optional key of `cadence.yaml`; absent, nothing changes
|
|
5
|
+
(no ssh call, the same output lines as before).
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
# cadence.yaml
|
|
9
|
+
orchestrate:
|
|
10
|
+
build: npm run build
|
|
11
|
+
test: npx vitest run
|
|
12
|
+
gate:
|
|
13
|
+
host: build-box # an ssh destination: `machine`, `user@machine`
|
|
14
|
+
install: npm ci # optional: installs the dependencies on the host to fill a cache
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`host` is a non-empty string without space, not starting with `-` (ssh would read it as an option);
|
|
18
|
+
anything else refuses `cadence.yaml` with `orchestrate.gate.host : destination ssh attendue …`. `install` is a non-empty command.
|
|
19
|
+
`install` without `host` does nothing (the gate stays local). Any other key of `gate` is refused as unknown (`readsPlan`, `host`, `install` are the three). Declaring `host` alone is **not** `readsPlan`:
|
|
20
|
+
the plan-only commits are still crossed (L444) and the `readsPlan` message does not appear.
|
|
21
|
+
Nothing in cadence names a machine: the host comes from this key, and the work folder on it is derived.
|
|
22
|
+
|
|
23
|
+
## What runs where
|
|
24
|
+
|
|
25
|
+
Played on the host, at the sha, in a throwaway worktree: `orchestrate.build` then `orchestrate.test` of `cadence verify --gate`
|
|
26
|
+
(`docs/deliver.md`), and, in a wave (`docs/orchestrate.md`), the program's gate of a lot after a work step, the baseline of the starting sha
|
|
27
|
+
and the replay alone of the red tests (`orchestrate.testReplay`, or the `replay` of each part of a gate declared as a list, L512: each part and its replay run in their `dir` of the host's worktree). The commands are those of `cadence.yaml`, unchanged; the verdict is read as a local one
|
|
28
|
+
(0 green, 1 red with the tests named, baseline, recording of the checks), and the verdict of a sha is noted in the local shared state as before.
|
|
29
|
+
The other commands of a wave (claude sessions, acceptance, start, verdict) stay local.
|
|
30
|
+
|
|
31
|
+
The first line of the gate says where it ran:
|
|
32
|
+
`verify --gate 6b0d9aa : porte jouée sur l'hôte build-box (sha 6b0d9aa, cache utilisé (empreinte 1a2b3c4d))`. In a wave the same line goes to the journal
|
|
33
|
+
(`porte du lot L12 : porte jouée sur l'hôte …`) and the place is kept in the lot's checks (`lieu`).
|
|
34
|
+
|
|
35
|
+
`verify.inPlace: true` wins over the host: the gate runs in the main tree and the output says `l'hôte … est ignoré`.
|
|
36
|
+
`inPlace: false` or absent lets the host come before the main tree and the throwaway copy.
|
|
37
|
+
|
|
38
|
+
A wave plays the gate on the host only when the lot's worktree is **clean and at the commit pushed**: the host would not see uncommitted
|
|
39
|
+
changes. Otherwise the gate is local and the journal says `worktree non validé, jouée en local`.
|
|
40
|
+
|
|
41
|
+
## The work folder on the host
|
|
42
|
+
|
|
43
|
+
Relative to the ssh login directory: `.cadence-gate/<folder name of the local project>/` with `repo.git` (bare repository where the sha is pushed,
|
|
44
|
+
`git push --no-verify`, created at first use), `deps/<fingerprint>` (the dependency caches) and `wt/<unique id>` (the throwaway worktrees).
|
|
45
|
+
The host needs `ssh` access without password (`BatchMode`), `git`, `tar` and the tools of the project. Installing the machine is the lead's job.
|
|
46
|
+
|
|
47
|
+
## The dependency cache
|
|
48
|
+
|
|
49
|
+
The key is the sha256 of the lockfiles of the sha, at any level of the repository: `package-lock.json`, `npm-shrinkwrap.json`, `pnpm-lock.yaml`,
|
|
50
|
+
`yarn.lock`, `poetry.lock`, `uv.lock`, `Pipfile.lock`, `Cargo.lock`, `go.sum`. No lockfile at the sha: no cache, the gate plays without prepared dependencies.
|
|
51
|
+
A known fingerprint is reused without installing; the worktree receives a **copy** of the cache, never a link. An absent cache is filled once:
|
|
52
|
+
|
|
53
|
+
- with `gate.install`: played **on the host**, in a worktree at the sha; the cache folder carries the platform of the host in its key (`<fingerprint>-linux-x64`);
|
|
54
|
+
- without `gate.install`: by copying the local dependencies (`node_modules`, `.venv`, or `orchestrate.worktreeDeps`), but only if the lockfiles of the local tree
|
|
55
|
+
have the fingerprint of the sha **and** the local system and architecture equal the host's (read by the probe). Otherwise the gate falls back to local, with the cause.
|
|
56
|
+
|
|
57
|
+
A cache is written in a unique temporary folder, then published by a rename to `deps/<fingerprint>`; if it already exists (a wave in parallel, a `verify --gate`), the temporary is
|
|
58
|
+
thrown and the existing cache is used. A failed install publishes nothing. cadence **never purges** the caches or the bare repository: freeing the host's disk is up to the lead
|
|
59
|
+
(deleting `.cadence-gate/<project>` only forces a push and a reinstall). Temporary folders and worktrees left more than 6 hours ago are removed at the next call.
|
|
60
|
+
|
|
61
|
+
## When the host does not answer
|
|
62
|
+
|
|
63
|
+
The gate first probes the host (`ssh -o BatchMode=yes`, short connection delay: never a password prompt). It falls back to the **local gate**, never to a red, and says so:
|
|
64
|
+
|
|
65
|
+
- `verify --gate : porte déportée indisponible sur <host> (<cause>) — repli sur la porte locale`: the probe, the work folder or the push failed;
|
|
66
|
+
- `verify --gate : cache de dépendances impossible sur <host> (<cause>) — repli sur la porte locale`: the cache could not be filled or read;
|
|
67
|
+
- in a wave: `porte du lot <lot> : porte déportée indisponible sur <host> (<cause>) — jouée en local` and `… cache de dépendances impossible sur <host> (<cause>) — jouée en local`.
|
|
68
|
+
|
|
69
|
+
**A connection lost during a command (ssh exit code 255).** The command did not give a verdict, so it is never counted red:
|
|
70
|
+
`verify --gate : connexion perdue avec <host> pendant la porte — rejouée en local` (the whole gate is replayed locally), and in a wave
|
|
71
|
+
`porte du lot <lot> : connexion perdue avec <host> pendant la porte — rejouée en local` (the command is replayed locally — the lot's gate, its baseline `(ligne de base <sha>)`
|
|
72
|
+
or the replay alone — and the next commands of that gate stay local), written to the output **and** to the journal of the wave, with no correction pass and no finding. Any other remote exit code
|
|
73
|
+
is the verdict of the command: 1 is a red, as locally.
|
|
74
|
+
|
|
75
|
+
## Timeout, Ctrl-C, signals
|
|
76
|
+
|
|
77
|
+
Remote commands run with a terminal (`ssh -tt`) and their process group id is kept on the host. At the timeout (30 minutes per command), on Ctrl-C or on a signal, cadence kills the local
|
|
78
|
+
ssh and then sends the host a separate command that kills the group and removes the worktree. If that command fails the output says
|
|
79
|
+
`nettoyage de l'hôte <host> en échec (<cause>) — le worktree orphelin y sera retiré au prochain appel`.
|
|
80
|
+
|
|
81
|
+
## Quoting and the sha
|
|
82
|
+
|
|
83
|
+
The sha, the host and the paths put in an ssh command are single-quoted with escaped quotes. A sha that is not hexadecimal (4 to 64 characters) is refused before any ssh command:
|
|
84
|
+
`verify --gate : sha invalide pour la porte déportée (hexadécimal attendu)`, exit 2.
|
|
85
|
+
|
|
86
|
+
## `CADENCE_TEST_WORKERS`
|
|
87
|
+
|
|
88
|
+
The commands receive `CADENCE_TEST_WORKERS` computed with the **host's** cores (`nproc`) divided by the session cap (`CADENCE_MAX_SESSIONS`, 2 by default), unless the caller's environment already
|
|
89
|
+
holds a positive integer (same rule as the local gate, L350).
|
package/docs/skills.md
CHANGED
|
@@ -13,7 +13,9 @@ gives `/cadence:session-start`, `/cadence:session-close`, `/cadence:deliver`,
|
|
|
13
13
|
`/cadence:lead`, `/cadence:orchestrate`, the `ux-reviewer`, `code-reviewer` and `qa-reviewer` agents and the `livreur` delivery agent. Or copy them into the
|
|
14
14
|
repository with `cadence skills install` (to `.claude/skills/cadence-*` and
|
|
15
15
|
`.claude/agents/cadence-*.md`; `--dir` for another `.claude` folder,
|
|
16
|
-
`--force` to overwrite local
|
|
16
|
+
`--force` to overwrite a copy that differs from the package's text, a local edit or an
|
|
17
|
+
earlier version never edited: the command compares the copy to the text it installs, not to the
|
|
18
|
+
version that installed it).
|
|
17
19
|
|
|
18
20
|
- **session-start**: reports the facts briefly, proposes three lots from the
|
|
19
21
|
plan, then waits for your priority — nothing starts before your answer.
|
|
@@ -50,6 +52,7 @@ repository with `cadence skills install` (to `.claude/skills/cadence-*` and
|
|
|
50
52
|
edits code. Read-only for real: its `tools:` list is `Read, Grep, Glob, Bash` and the
|
|
51
53
|
Playwright tools (`mcp__playwright`, and `mcp__plugin_playwright_playwright` when the
|
|
52
54
|
browser comes from the Playwright plugin) — no `Edit`, no `Write`. In a wave it gives its captures the absolute path of the capture directory its brief names (a bare name would land in the repository); outside a wave, a path under `.playwright-mcp/` (e.g. `.playwright-mcp/page-home.png`; the Playwright MCP resolves a bare file name against the repository, where it would land at the root); `qa-reviewer` follows it too.
|
|
55
|
+
**Delivery grid (L513):** on the `ux` step and when reviewing an existing screen (not in mockup or conformity mode) its checklist carries a five-point grid — visible focus, `prefers-reduced-motion`, `cursor: pointer` on clickable elements, no emoji used as an icon, no horizontal scroll at 375, 768, 1024 and 1440 px (a width it could not render goes to `nonVerifie`; a failing point follows the blocking / major / minor scale) — and a static check of AI tics, seven of the 16 rules of `detect.mjs` (Apache-2.0, attribution in `NOTICE`; the other nine are not kept, reasons in the agent) applied by reading the diff without running it. Each tic is a finding `T1`, `T2`… (file, line, named rule, severity); none gives `tics d’IA : 0 constat`, no front file `non applicable`; a tic that is a choice of the product's charter is not a finding. The grid is not repeated in the short reply. Without a `Report file:` line (the orchestrated `ux` step, whose structured report has no checklist and whose schema is unchanged), a point that could not be checked goes to `nonVerifie` and the `verdict` line ends with the tally of the grid and the tics line (`grille 5/5 — tics d’IA : 0 constat`).
|
|
53
56
|
**Short reply (L452):** with a `Report file: <absolute path>` line in the brief it answers in 15 lines at most (`Verdict:`, `Findings:` with
|
|
54
57
|
the rule or measure of each, `Not verified:`, `Sub-tasks:`, `Report:`, `Captures:`) and writes the full report to that file (outside the repository, verdict last).
|
|
55
58
|
- **code-reviewer** (agent): any stack; given a repository and a lot id, it reads
|
|
@@ -95,7 +98,7 @@ repository with `cadence skills install` (to `.claude/skills/cadence-*` and
|
|
|
95
98
|
the project's expectations file in a real browser at 1440 and 390 px and
|
|
96
99
|
measures: expected content present and non-empty, no error or missing-data
|
|
97
100
|
message, every API call answered 2xx with a non-empty body, no console error,
|
|
98
|
-
no broken content image. It reads the page as text first and takes a capture only for a gap. Findings are defects (a line of the expectations
|
|
101
|
+
no broken content image. It reads the page as text first and takes a capture only for a gap. It works in its own browser context (its own profile, named after the app, a suffixed one when that profile is already open elsewhere), launched by a Node script with `launchPersistentContext` rather than through the shared MCP browser tools — the script loads `playwright` from a package already on the machine (`CADENCE_PLAYWRIGHT`, the app's `node_modules`, the package of the wave's Playwright MCP server, else the newest npx cache), falls back on the installed Chrome (`channel: 'chrome'`) when the bundled Chromium is missing, never installs anything, and without a loadable Playwright the pass is reported under « Not verified » rather than done with the shared tools: several QA passes can run together without sharing a browser or reading each other's tabs (L511). Findings are defects (a line of the expectations
|
|
99
102
|
broken, or a universal check failing with a visible effect, with or without an
|
|
100
103
|
expectations file), suspects (it looks like missing or wrong data and no
|
|
101
104
|
expectation settles it) or noise (a console error or a failed request with no
|
package/docs/whats-new.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## In two lines
|
|
6
6
|
|
|
7
|
+
- **1.35.0**: a test already red before a lot, or that only needs more time, no longer costs correction passes, including on a gate declared in parts; QA passes run in browsers of their own; design agents check contrast and AI tics.
|
|
7
8
|
- **1.34.1**: republishes 1.34.0, whose npm publication failed after the tag; same features (edge-case probe, steadier `mise-en-service` tests).
|
|
8
9
|
- **1.34.0**: an optional edge-case probe (`orchestrate.probe: true`) tries to break a lot's diff with tests at the edges before the code review; flaky tests of `mise-en-service` made deterministic.
|
|
9
10
|
- **1.33.0**: the lots panel shows each project's progress bar in its « ordre des projets » section, aligned in the desktop app; a simplification audit of the code, and dead exports removed.
|
|
@@ -62,6 +63,8 @@ Each is a paragraph in [docs/whats-new.md](whats-new.md) and a full section in [
|
|
|
62
63
|
|
|
63
64
|
The long form of « In two lines » above (the README no longer carries a « What's new » section since L326: it links here). The full history, with the date of each version, is in [CHANGELOG.md](../CHANGELOG.md).
|
|
64
65
|
|
|
66
|
+
**1.35.0**: the wave's gate stops paying for reds that need no fix. With `orchestrate.testReplay`, a red that stays red alone in the lot is replayed alone at the start sha, and one already failing there is « déjà rouge »: no correction pass, no escalation; a test that expired in the whole suite and passes alone at 80 % or more of its delay is a « délai trop juste », a warning naming the test with its duration and its delay (L510, `docs/orchestrate.md`). On a gate played in several folders, `orchestrate.test` takes a list of parts `[{ dir, run, replay? }]` and each part plays, replays and attributes its own reds, so a composed gate gets the same two verdicts (L512, `docs/orchestrate.md`, « A gate declared in parts »; evatosorus `node --test` is not covered yet). `cadence corrections` now counts the passes launched on tests that ended without a code change (L510, `docs/corrections.md`). The gate can also run on another machine through `orchestrate.gate.host`, by ssh at the pushed sha, with a local fallback and a lost connection replayed locally, never counted red (L403, `docs/remote-gate.md`). The `qa-reviewer` opens a browser context and a profile of its own, so two QA passes started together no longer share a tab (L511, `docs/skills.md`). The `spec-writer` joins a `contraste.md` (WCAG 2.2 ratios, 4.5:1 at least) to each sheet, and the `ux-reviewer` gets a delivery grid and a static check of AI tics (L513, `docs/orchestrate.md`). Small fixes: `cadence release` prints its local tag before the gate and removes it when red (L508, `docs/releasing.md`), `raf ux` and `raf review` print the commit command for the regenerated plan (L509), and `cadence deliver` outside a wave commits the plan it wrote for the « article à rafraîchir » lot (L420, `docs/news.md`).
|
|
67
|
+
|
|
65
68
|
**1.34.1**: 1.34.0 was tagged but its publication to npm failed (a CHANGELOG entry cited a lot with no commit in the tag); 1.34.1 publishes the same content, with that entry reworded. Install 1.34.1 to get the edge-case probe and the steadier tests of 1.34.0.
|
|
66
69
|
|
|
67
70
|
**1.34.0**: `cadence orchestrate` can play an edge-case probe between the implementation and the code review (L497, `orchestrate.probe: true`, `docs/orchestrate.md`): a fresh Sonnet session reads the lot's diff, and the sheet when there is one, and writes tests at the edges — empty, absent, twice, wrong type, refused, the real shape of the data, the other callers; a red test sends the lot back to the implementation as a finding before the Opus review, which costs more. The probe's findings never block the lot (a failed or timed-out probe is a warning and the review goes on), while the checks common to every writing session — a dirty repository, the acceptance-test lock — apply to it too. Absent, nothing changes. It answers the « bug de code » bottleneck: edge cases were 64 % of the code-bug correction passes after two written instructions in the implementation brief. The test suite also stops blocking a Vitest worker for more than 60 s: `mise-en-service` compiles once per test file instead of five synchronous `tsc` runs (L480).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sylad/cadence",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.35.0",
|
|
4
4
|
"description": "A small, repo-native working method: a versioned plan linked to your commits, a changelog with screenshots, session rituals and deliveries proven by their effect.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sylvain Ladoire",
|
|
@@ -17,9 +17,11 @@
|
|
|
17
17
|
"templates",
|
|
18
18
|
".claude-plugin",
|
|
19
19
|
"README.md",
|
|
20
|
+
"NOTICE",
|
|
20
21
|
"docs/raf.md",
|
|
21
22
|
"docs/orchestrate.md",
|
|
22
23
|
"docs/deliver.md",
|
|
24
|
+
"docs/remote-gate.md",
|
|
23
25
|
"docs/spec.md",
|
|
24
26
|
"docs/lead.md",
|
|
25
27
|
"docs/ref.md",
|
package/skills/lead/SKILL.md
CHANGED
|
@@ -263,7 +263,7 @@ user must find there) and returns measured findings; it reads only, and never lo
|
|
|
263
263
|
blocking findings back to the human — a page whose main content is missing, or that shows an error,
|
|
264
264
|
is a defect even when the delivery checks are green — with its proposed follow-up lines. A project
|
|
265
265
|
without an expectations file gets a draft back: show it to the human, who corrects it and decides
|
|
266
|
-
whether it is committed. It is not a gate: `raf done` does not wait for it, and a finding becomes a
|
|
266
|
+
whether it is committed. Several `qa-reviewer` passes may run together: each opens its own browser context (its own profile), so two apps are walked without sharing a browser. It is not a gate: `raf done` does not wait for it, and a finding becomes a
|
|
267
267
|
new lot, not a reopened one.
|
|
268
268
|
|
|
269
269
|
Give the `qa-reviewer` the same line `Report file: <absolute path>` (outside the repository): it answers in 5 lines
|
|
@@ -11,6 +11,8 @@ What you produce, in `<dir>/<écran>/`:
|
|
|
11
11
|
|
|
12
12
|
Write the texts before the review, with the structure the UX reviewer will check: an error message says what, why, how to fix; an empty or loading state says what it is, why it is empty, how to start; an action label is a verb that names the result, never "OK" or "Validate" alone; the confirmation of a destructive action names the object and the consequence; one word per notion, in the sheet and in the mockup. A word or a message already in the product is kept as it is.
|
|
13
13
|
|
|
14
|
+
Colours the screen adds: for each one, a semantic token named by its role and its text token `on-<role>` (a colour without its `on-*` is a defect of the spec), with values from a ramp drawn from the brand colour of the charter, never an external palette; a role the charter already covers keeps its token (no duplicate, the existing pair is only measured). Write `contraste.md` in the same folder: one line per token / on-token pair, the two values, the ratio (WCAG 2.2, relative luminance) and `ok` or `non`, every pair at least 4.5:1 (fix by changing the step of the ramp, not the text size). A product with no CSS variable and no brand colour: invent no ramp, measure the existing values and write the absence of a coloured charter in the sheet. Never propose a generic catalogue style on a product that has a charter.
|
|
15
|
+
|
|
14
16
|
Sheet rules:
|
|
15
17
|
- Every rule is `sourcee` (it says where it comes from: a line of the lot, a note, `expectations.md`, a rule already coded, an API contract) or `hypothese` (you chose it for lack of a source; `si_faux` says what would change if it were wrong). Never present a guess as sourced.
|
|
16
18
|
- Check every date in the sample data of the mockup before keeping it: compute its weekday (a command such as `date -d 2026-09-03 +%A`, or a script), never write it from memory — a « Wed 03/09 » that is a Thursday sends the mockup back for nothing. The same goes for any figure that must add up (a score and its result, a total and its parts).
|
|
@@ -18,7 +20,7 @@ Sheet rules:
|
|
|
18
20
|
- A rule you invent is not a free choice: **a hypothesis whose `si_faux` involves an expensive-to-undo choice is a question, not a hypothesis.** The four expensive categories: a data model or storage (key, migration, user data created once shipped); a public or shared API contract, or an already published route / URL; a destructive or irreversible action (deletion, sending, payment); a rule that contradicts an existing sourced rule. In those cases do not write the hypothesis: stop and put the question under "questions" (the lead answers and the step is resumed). Everything else (wording, order of the fields, error state, spacing) is a written hypothesis, cheap to correct later.
|
|
19
21
|
- If, after reading the lot and the code, you find that the lot changes NO screen (no new page), write one line with the reason in `sousSeuil`, create no mockup and no sheet, and finish: the lot then follows the usual path.
|
|
20
22
|
|
|
21
|
-
Commit the spec with explicit paths (never `git add -A` or `commit -a`), a message that cites the lot (`spec({{lot}}): …`), the sheet, the mockup
|
|
23
|
+
Commit the spec with explicit paths (never `git add -A` or `commit -a`), a message that cites the lot (`spec({{lot}}): …`), the sheet, the mockup, the captures and `contraste.md` together, and leave the working tree clean. Do not implement the screen, do not write application code or tests, do not push, deliver, run `raf done`, `raf ux` or `raf review`.
|
|
22
24
|
Never run `git checkout` or `git switch` to another commit or branch in this repository: the orchestrator watches it and a moved HEAD breaks the other sessions of the wave. To look at another sha, use a throwaway `git worktree add --detach <tmp> <sha>`, removed afterwards.
|
|
23
25
|
Decide minor interpretation questions yourself and list each one under "choix" with the alternative you did not take. Leave "questions" empty rather than writing a placeholder such as "no question".
|
|
24
26
|
{{commits}}
|