@sylad/cadence 1.32.0 → 1.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/dist/articles.js +1 -1
- package/dist/audit.js +6 -6
- package/dist/config.js +8 -9
- package/dist/corrections.js +9 -10
- package/dist/dates.js +1 -1
- package/dist/deliver.js +2 -2
- package/dist/hud-context.js +5 -5
- package/dist/lead.js +5 -5
- package/dist/link.js +1 -1
- package/dist/news.js +1 -1
- package/dist/orchestrate/briefs.js +1 -0
- package/dist/orchestrate/command.js +6 -6
- package/dist/orchestrate/cycle.js +52 -87
- package/dist/orchestrate/precheck.js +79 -0
- package/dist/orchestrate/probe.js +124 -0
- package/dist/orchestrate/schemas.js +10 -1
- package/dist/perf.js +1 -1
- package/dist/plan-commit.js +4 -4
- package/dist/plan.js +3 -3
- package/dist/proc.js +1 -1
- package/dist/ref/add.js +2 -2
- package/dist/ref/analyse.js +2 -2
- package/dist/ref/coverage.js +2 -2
- package/dist/ref/diff.js +1 -1
- package/dist/ref/measure.js +4 -4
- package/dist/ref/pdf.js +1 -1
- package/dist/ref/regard.js +2 -2
- package/dist/ref/store.js +1 -1
- package/dist/ref/tools.js +1 -1
- package/dist/release.js +4 -4
- package/dist/verify.js +2 -2
- package/dist/yaml-keys.js +6 -0
- package/docs/cadence-hud.md +1 -1
- package/docs/orchestrate.md +21 -2
- package/docs/qualite.md +2 -0
- package/docs/whats-new.md +9 -0
- package/package.json +1 -1
- package/templates/orchestrate/probe.md +20 -0
package/dist/ref/measure.js
CHANGED
|
@@ -7,9 +7,9 @@ import { SLUG } from './add.js';
|
|
|
7
7
|
import { decodePng, encodePng } from './png.js';
|
|
8
8
|
import { readDocument } from './store.js';
|
|
9
9
|
import { requireTools } from './tools.js';
|
|
10
|
-
|
|
10
|
+
const QUOI = ['couleurs', 'contraste', 'boites', 'texte'];
|
|
11
11
|
/** Largeur d'écran de référence, en pixels, à laquelle les mesures sont ramenées. */
|
|
12
|
-
|
|
12
|
+
const REFERENCE_WIDTH = 1440;
|
|
13
13
|
/** Écart d'un canal (0-255) après arrondi de la moyenne d'un carré. */
|
|
14
14
|
const COLOR_TOLERANCE = 1;
|
|
15
15
|
/** Part de la taille de police due à la forme des lettres : la hauteur de capitale n'est pas la même dans toutes les polices (0,70 à 0,73 em). */
|
|
@@ -41,13 +41,13 @@ function luminance([r, g, b]) {
|
|
|
41
41
|
return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
|
|
42
42
|
}
|
|
43
43
|
/** Rapport de contraste WCAG 2.2, non arrondi. */
|
|
44
|
-
|
|
44
|
+
function contrastRatio(a, b) {
|
|
45
45
|
const la = luminance(a);
|
|
46
46
|
const lb = luminance(b);
|
|
47
47
|
return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);
|
|
48
48
|
}
|
|
49
49
|
/** `page`, `x,y` (un point) ou `x,y,l,h` (un carré), en pixels de la page rendue. */
|
|
50
|
-
|
|
50
|
+
function parseZone(text, raster) {
|
|
51
51
|
if (text === 'page')
|
|
52
52
|
return { zone: { x: 0, y: 0, l: raster.width, h: raster.height }, point: false };
|
|
53
53
|
const parts = text.split(',');
|
package/dist/ref/pdf.js
CHANGED
|
@@ -89,7 +89,7 @@ export function renderPages(tools, file, pages, dir) {
|
|
|
89
89
|
poppler('pdftoppm', tools, ['-r', String(DPI), '-png', '-singlefile', '-f', String(n), '-l', String(n), file, join(dir, `page-${n}`)], file);
|
|
90
90
|
}
|
|
91
91
|
/** Résolution des vignettes de toutes les pages (à parcourir pour repérer les planches d'un document sans texte). */
|
|
92
|
-
|
|
92
|
+
const THUMB_DPI = 40;
|
|
93
93
|
/** Vignettes basse résolution de toutes les pages dans `dir/page-<n>.png`. */
|
|
94
94
|
export function renderThumbnails(tools, file, total, dir) {
|
|
95
95
|
mkdirSync(dir, { recursive: true });
|
package/dist/ref/regard.js
CHANGED
|
@@ -4,9 +4,9 @@ import { PACKAGE_ROOT } from '../orchestrate/snapshot.js';
|
|
|
4
4
|
import { decodePng, encodePng } from './png.js';
|
|
5
5
|
import { sessionDeRef } from './session.js';
|
|
6
6
|
/** Marge (pixels de la page rendue) ajoutée de chaque côté de la zone d'un élément dans sa découpe : de quoi lire ce qui l'entoure. */
|
|
7
|
-
|
|
7
|
+
const MARGE_DECOUPE = 24;
|
|
8
8
|
/** Sortie structurée du troisième regard : un verdict par numéro d'élément ; le programme ne retient que les verdicts valides. */
|
|
9
|
-
|
|
9
|
+
const REGARD_SCHEMA = {
|
|
10
10
|
type: 'object',
|
|
11
11
|
properties: {
|
|
12
12
|
decisions: {
|
package/dist/ref/store.js
CHANGED
|
@@ -20,7 +20,7 @@ export function referencesDir(root, configPath, env) {
|
|
|
20
20
|
throw new RafError(`ref : references.dir (${abs}) est dans un dépôt Git : les documents de référence restent hors du dépôt (choisir un dossier ailleurs, ou retirer la clé pour $XDG_DATA_HOME/cadence/references)`);
|
|
21
21
|
return abs;
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
const documentFile = (docDir) => join(docDir, 'document.json');
|
|
24
24
|
export function readDocument(docDir) {
|
|
25
25
|
const file = documentFile(docDir);
|
|
26
26
|
if (!existsSync(file))
|
package/dist/ref/tools.js
CHANGED
|
@@ -3,7 +3,7 @@ import { delimiter, join } from 'node:path';
|
|
|
3
3
|
import { RafError } from '../plan.js';
|
|
4
4
|
const POPPLER = 'sudo apt install poppler-utils';
|
|
5
5
|
/** Les outils du système dont `cadence ref` dépend, dans l'ordre où l'erreur les nomme. */
|
|
6
|
-
|
|
6
|
+
const TOOLS = [
|
|
7
7
|
{ name: 'pdftoppm', commands: ['pdftoppm'], install: POPPLER },
|
|
8
8
|
{ name: 'pdftotext', commands: ['pdftotext'], install: POPPLER },
|
|
9
9
|
{ name: 'pdfimages', commands: ['pdfimages'], install: POPPLER },
|
package/dist/release.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { currentBranch, hasTrackedChanges, tagExists } from './git.js';
|
|
4
4
|
import { RafError } from './plan.js';
|
|
5
|
-
|
|
5
|
+
const BUMPS = ['patch', 'minor', 'major'];
|
|
6
6
|
const PACKAGE = 'package.json';
|
|
7
7
|
const LOCK = 'package-lock.json';
|
|
8
8
|
const PLUGIN = '.claude-plugin/plugin.json';
|
|
@@ -10,8 +10,8 @@ const MARKETPLACE = '.claude-plugin/marketplace.json';
|
|
|
10
10
|
const CHANGELOG = 'CHANGELOG.md';
|
|
11
11
|
const WHATS_NEW = 'docs/whats-new.md';
|
|
12
12
|
/** Longueur maximale (en caractères) de la ligne d'une version dans la liste courte de docs/whats-new.md. */
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const SHORT_LINE_MAX = 240;
|
|
14
|
+
function nextVersion(current, bump) {
|
|
15
15
|
const m = /^(\d+)\.(\d+)\.(\d+)$/.exec(current);
|
|
16
16
|
if (!m)
|
|
17
17
|
throw new RafError(`release : la version de ${PACKAGE} (${current}) n'est pas de la forme x.y.z, elle ne se calcule pas`);
|
|
@@ -172,7 +172,7 @@ function plan(root, bump, today) {
|
|
|
172
172
|
* une ligne de la liste « In two lines » (≤ 240 caractères, en tête) et un paragraphe long (en tête de « Version by version »).
|
|
173
173
|
* Rend les écarts, une ligne chacun ; vide quand les deux sont là, à leur place.
|
|
174
174
|
*/
|
|
175
|
-
|
|
175
|
+
function whatsNewIssues(text, version) {
|
|
176
176
|
const lines = text.split('\n');
|
|
177
177
|
const issues = [];
|
|
178
178
|
// « Version by version » coupe le fichier : la liste courte est avant, les paragraphes longs sont après (sauf l'introduction, premier paragraphe de la section).
|
package/dist/verify.js
CHANGED
|
@@ -72,7 +72,7 @@ export function summaryLine(results) {
|
|
|
72
72
|
: `verify : ${red} effet${red > 1 ? 's' : ''} rouge${red > 1 ? 's' : ''} sur ${n} vérification${n > 1 ? 's' : ''}`;
|
|
73
73
|
}
|
|
74
74
|
/** Variables passées aux commandes de vérification, comme à celles de deliver. */
|
|
75
|
-
|
|
75
|
+
function verifyEnv(sha) {
|
|
76
76
|
return { CADENCE_SHA: sha, CADENCE_SHORT: sha.slice(0, 7), CADENCE_BRANCH: '' };
|
|
77
77
|
}
|
|
78
78
|
/**
|
|
@@ -98,7 +98,7 @@ export function expectedTarget(root, config, last) {
|
|
|
98
98
|
/** Sha attendu de la reprise et de `cadence verify` sans --sha. */
|
|
99
99
|
export const defaultTarget = (root, config) => expectedTarget(root, config, lastDelivery(sharedStateDir(root)));
|
|
100
100
|
/** Délai de chaque essai d'une vérification de `cadence verify`. */
|
|
101
|
-
|
|
101
|
+
const VERIFY_ATTEMPT_MS = 120_000;
|
|
102
102
|
/** `cadence verify` : 0 tout vert, 1 un effet rouge, 2 rien à vérifier. */
|
|
103
103
|
export async function verifyCommand(ctx, deps) {
|
|
104
104
|
const { config, out } = ctx;
|
package/docs/cadence-hud.md
CHANGED
|
@@ -81,7 +81,7 @@ A project shows at most 5 lots (L411), the first ones in the order above (so tho
|
|
|
81
81
|
|
|
82
82
|
**Reordering (L402).** Drag a lot onto another lot of the same project and of the same display group (or a sub-task onto another sub-task of its lot, same group): press on the row, move with the button held, release. While you drag, the row you started from shows `●` and the row under the pointer shows where it will land, `⇡` (before it) or `⇣` (after it), or a red `⊘` when it belongs to another parent or to another display group (L410) and the drop will be refused. The keyboard does the same wherever the panel is drawn by a `Client` region (terminal and desktop app): click a row (or press ↑ / ↓ once the panel has the focus), then **Alt**+↑ / **Alt**+↓ moves the selected lot before its previous sibling / after its next one. Only the rows the panel shows take part (L411): a lot hidden behind `+ N lots`, or the sub-lots of a closed lot, are not rows, so they are never a target — Alt+↓ on the fifth lot, the last row before the `+ N lots` button, moves nothing, like Alt+↓ on the last row of a project; open the rest (or the lot) first, and the drop runs `raf move` as usual. The `+ N lots` / `moins` button sits outside the `Client` region, after the project's rows. The drop runs `raf move <id> --before|--after <id>` ([raf move](raf.md)) in the project folder, then the panel reads the plans again and says, under the title, `✔ L13 placé avant L10 — le plan est modifié, à commiter (raf move ne commite pas)`: the panel never commits, the plan file is yours to commit. Everything is relative to what the panel shows, in the L410 order, not to the order of the plan: the row you drop on, and the "previous" and "next" sibling of Alt+↑ / Alt+↓, are the ones displayed around the lot, and `raf move` is given that lot as its target. **A lot is reordered only inside its display group** (L410: in progress, free, blocked): dropping a lot on a lot of another group is refused, `raf` is not called and nothing moves. While you drag, the row under the pointer shows the red `⊘` (as for another parent), and on release the panel says why, by group: `✖ L411 est en cours : un lot libre se range parmi les libres` (the words: `en cours` / `libre` / `bloqué`; the lot is named by what it is, `un lot` or `une sous-tâche`). A parent with an in-progress sub-lot is shown with the lots in progress, so it counts as one of them. Alt+↑ / Alt+↓ toward a displayed neighbour of another group gets the same refusal; at the edge of the displayed rows (or before the `+ N lots` button) nothing happens. (Case that led to this: plan L402 L403 L407 L411, L403 free dropped on L411 in progress moved L403 below L407 and hid it behind `+ 11 lots`.) Inside a group the screen follows the plan, so a gesture that goes through always shows: the lot moves where you dropped it. A drop that would leave the order of the group as it is — the lot is already right before (or after) the target among the lots of its group — runs nothing and says `• L10 est déjà avant L13 dans le plan : rien à déplacer`; no gesture of the panel leads there (the screen follows the plan inside a group), the check guards a request the drawing did not make. The same holds between the sub-tasks of a lot. The `déjà` check is made on the table the panel last read: from a successful `raf move` until the end of a re-reading started *after* it (`cadence lead tour` takes several seconds; a reading already in flight read the old plan, so another one follows it) the table is held stale: no `déjà` short-circuit, `raf move` runs and decides (the group refusal stays: it depends on the states, not on the order). A refusal is written under the title with its reason and nothing moves: a wave holds the repository (`move : orchestration en cours …`), a plan kept by another tool (`plan en lecture seule : … — le modifier avec l'outil du projet`, the message does not name that tool's command: `raf` does not know it, so look in the project), an archived lot, different parents (`L402 et L401/2 n'ont pas le même parent …`) or different display groups (`L411 est en cours : …`), the last two checked before `raf` runs; `raf` missing from the `PATH` says so. On a surface with no `Client` region (mobile, editor) the panel stays read-only (`lecture seule` in its title).
|
|
83
83
|
|
|
84
|
-
**Reordering the projects (L449).** Above the tree, `ordre des projets (priority:) — glisser, ou Alt+↑ / Alt+↓` and one row per project (`cadence 7 lots non clos`; `illisible` for a project the tour could not read
|
|
84
|
+
**Reordering the projects (L449).** Above the tree, `ordre des projets (priority:) — glisser, ou Alt+↑ / Alt+↓` and one row per project, in the order of `priority:`: the name (in a `Box` of fixed width, the longest name's: the desktop app's font is proportional, so padding with spaces would align nothing; L495), the progress bar of the band — closed lots over total, filled cells coloured by the share done (red under 33 %, orange under 66 %, green above), the lots in progress with their ids and `+N cette semaine` (L481; `cadence ▮▮▮▯▯▯▯▯▯▯ 3/10 · 1 en cours : L401 · +2 cette semaine`) — so the progress reads without scrolling the band. A project with no `progress` in the tour (an older `cadence`) keeps `7 lots non clos`; `illisible` for a project the tour could not read. It is drawn only where the lots can be reordered (a `Client` region: terminal and desktop app), when the folder has two projects or more, and when the panel is tall enough to keep a row for each project and one lot under it (otherwise the tree has the room). Drag a project onto another (`●` the row you hold, `⇡` / `⇣` where it will land) or click it and press **Alt**+↑ / **Alt**+↓ (↑ / ↓ alone select): the drop runs `cadence lead priority <project> --before|--after <project> <folder>` ([lead priority](lead.md#lead-priority)), which rewrites the `priority:` list of the `cadence.yaml` of the parent folder, comments kept; the panel then reads the plans again and says under the title `✔ ol placé avant cadence — priority: du cadence.yaml est modifiée, à commiter`. This order is the one of the tour, of `cadence orchestrate --continue` and of the panel itself. The panel never commits. A refusal is written under the title with its reason (`✖ /dev/cadence.yaml illisible : …`, a `priority:` that is not a list) and nothing is written; `cadence` missing from the `PATH` says so; a project already at that place says `• … est déjà avant …`. The error row `cadence.yaml` that the tour adds for an unreadable file is not a project and cannot be moved or targeted.
|
|
85
85
|
|
|
86
86
|
States: `▶ en cours` (doing), `○ libre` (todo, no open `after:`), `⊘ bloqué` (todo, an `after:` is still open); a lot in a wave takes the wave's state and words, as the band writes them (`… en attente`, `⟳ implémente`, `⟳ relit`, `⟳ corrige`, `? QUESTION`, `✔ prêt`, `↩ rendu`, `✖ échec`, `⏸ suspendu`). In a native plan the sub-tasks of an open lot (`L401/2`) are its sub-lots (`├`/`└`); they only read `▶ en cours` or `○ à faire`, and are not counted in the project's `N lots non clos`. In a plan kept by another tool the sub-lots come from `parent:`. An `after:` id that is closed or unknown is struck through and blocks nothing. A project the tour could not read shows `illisible : <error>`; the others stay.
|
|
87
87
|
|
package/docs/orchestrate.md
CHANGED
|
@@ -262,7 +262,7 @@ table at the end of the wave, and is the lead's to take into the plan of the oth
|
|
|
262
262
|
|
|
263
263
|
**Effort level per pass** (L137). Each session is launched with `claude -p --effort <level>` (Claude Code 2.1.284; an
|
|
264
264
|
older `claude` is refused at launch unless every pass is `default`). Defaults: `precheck` low (it only reads),
|
|
265
|
-
`implement` and `fix` medium, `review` high (`review-small` follows `review`), `ux` high. A project overrides any of them
|
|
265
|
+
`implement`, `probe` and `fix` medium, `review` high (`review-small` follows `review`), `ux` high. A project overrides any of them
|
|
266
266
|
in `cadence.yaml`; the levels are `low`, `medium`, `high`, `xhigh`, `max`, and `default` sends no `--effort` (the
|
|
267
267
|
level of the session, as before this key). The format-retry session (`--resume`) keeps the level of its pass, and
|
|
268
268
|
`--dry-run` shows the flag in each command line, except for a `precheck: local` session: `claude-local` is launched
|
|
@@ -270,7 +270,7 @@ without `--effort` (see below), so `effort.precheck` has no effect on it and the
|
|
|
270
270
|
|
|
271
271
|
```yaml
|
|
272
272
|
orchestrate:
|
|
273
|
-
effort: { precheck: low, spec: medium, maquette: high, fiche: medium, accept: medium, implement: medium, fix: medium, review: high, ux: high } # defaults
|
|
273
|
+
effort: { precheck: low, spec: medium, maquette: high, fiche: medium, accept: medium, implement: medium, probe: medium, fix: medium, review: high, ux: high } # defaults
|
|
274
274
|
```
|
|
275
275
|
|
|
276
276
|
To measure what a level costs, run the same kind of wave before and after changing the key: each step of
|
|
@@ -535,6 +535,25 @@ except a copy that is still needed, which stays and is said: a copy that a live
|
|
|
535
535
|
The waves that count are those of the launch folders the script knows (`<folder>/.cadence/runs/<wave>/wave.json`): the repository itself and the working directory of every wave the orchestrator's registry still lists (`~/.cadence/orchestrate/waves/<pid>.json`; the registry drops a dead wave when another registers, so it does not know suspended waves by itself). There is no search over the whole disk: a suspended wave launched from another folder is not protected here, and `--resume` repairs its snapshot instead (above). A wave never marked `done` keeps its copy until it is, or until its folder is removed. A failure of the purge (unreadable copy, busy file) once `service` and the links have switched is a warning on the error output (`avertissement : purge des anciennes copies interrompue …`): the new version is in service, the fingerprint is printed, the exit code is 0, the next put in service tries again. The same run updates the **local copy of the `cadence-hud` mod** (L419), the one `CLAUDE_CODE_PLUGIN_DIRS` makes Claude Code load (`~/.claude/mods/cadence-hud`, `--mod-dir` for another folder): `plugins/cadence-hud` of the copy just put in service (not the working repository) is synchronised into it with `rsync -a --delete`, which leaves out `.claude-plugin/types` (generated by Claude Code in the copy). The output says `mod cadence-hud : copie locale mise à jour (<dir>)`. A machine without that folder gets no copy created (`copie locale absente … non mise à jour`), and a failed `rsync` is a warning on the error output (`avertissement : mod cadence-hud non mis à jour …`), exit code 0 like the purge: the version is in service. Before L419 the copy was updated by hand at each release and a forgotten one left the old mod loaded. The first run is also what installs the links in `~/.local/bin`. It prints the fingerprint of the copy
|
|
536
536
|
(bin, dist, package.json).
|
|
537
537
|
|
|
538
|
+
## The edge-case probe (`orchestrate.probe`, L497)
|
|
539
|
+
|
|
540
|
+
Code bugs are the first cause of correction passes, and an edge case is the first sub-cause of those (64 % of the `bug-code` passes since the instruction of L447, 69 % before: writing it in the brief changed nothing). `orchestrate.probe: true` adds a step between the writing and the review: a **fresh Sonnet session** (`probe`, brief `templates/orchestrate/probe.md`, `effort.probe` medium, the delay of a write step `timeouts.work`) that has not written the code, reads the lot's diff, and tries to break it with tests at the edges: empty, absent, twice, wrong type, refused, the real shape of the data, the other callers. The diff is given as a command (`git diff <start sha>..HEAD`), never pasted; the sheet of the lot is named when there is one. Like `implement` and `fix`, the brief gives the program's exact gate (L399: the probe commits tests the gate replays, `tsc` and the quality script included) and the session's machine share (L350). The session writes its tests in new files and commits them all, the passing and the failing, with `probe(L<n>): …`; it does not touch the application code nor the sealed acceptance tests.
|
|
541
|
+
|
|
542
|
+
```yaml
|
|
543
|
+
orchestrate:
|
|
544
|
+
probe: true # true or false; absent = nothing changes (no session, no field in the journal, no line in the output)
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
**When it plays.** Once per lot, after a writing session whose gates are green (tests, build, acceptance) and after the « code sans test » gate, before the librarian and the review; never during the minors pass, never for a lot with no commit. It is recorded in the lot's state (`probe`): a resume does not replay it, except after a quota, where it is the step that was interrupted. `--dry-run` lists the `probe (sonnet)` step between `implement` and `review`.
|
|
548
|
+
|
|
549
|
+
**What a red test does.** After the session the program plays its own gate (`orchestrate.build`, `orchestrate.test`) as after any writing. A test red **now and not at the start sha** (never a failure already there, L213) sends the lot to a correction pass (`fix`) before the review, with a finding of severity *major* whose text starts with `sonde de cas limites : ` and names the test; the probe's own report (`echecs`, « test — edge — expected ») is added to it so the fix session sees the edge. Without `orchestrate.test` there is no gate to read: the failures the session announces are taken as they are, with the warning `sonde de cas limites : échecs annoncés par la session, non vérifié par le programme (orchestrate.test absent)`. All the probe's tests stay in the lot. A test outside `orchestrate.testGate.tests` committed by the probe is a warning that names the files (`sonde de cas limites : la session a modifié du code hors tests (…)`); nothing is removed.
|
|
550
|
+
|
|
551
|
+
**Cost and limits.** The probe's session counts in the lot's tokens and budget. The correction it triggers is one of the two ordinary passes (`MAX_PASSES`): after it, one pass is left for the review, so the librarian is not called (the `bibliothécaire non appelé` warning says so, and the review carries the documentation gap). The probe does not play when a correction pass is already done, or when the budget does not pay the probe (estimated at 65 k tokens, `PROBE_RESERVE`, no measure yet), the correction and the review that follows: the warning `sonde de cas limites non jouée : <n> passe(s) de correction déjà faite(s) ou budget du lot (<count>) insuffisant` says so and the review goes ahead. If the red tests cannot be corrected for lack of budget after the probe, the lot goes back to the lead without a review, with its findings, as for any red tests after a writing (L145). Without a new commit from the probe, the review keeps the results of the gate played after the writing (it does not rerun the suite and the build).
|
|
552
|
+
|
|
553
|
+
**It never blocks the lot.** A failed, cut or timed-out session, or an unreadable report, is the warning `sonde de cas limites non jouée : <cause>` and the review goes ahead; the questions of the report become warnings, nobody waits. A quota suspends the wave like any session and the resume replays the probe. What a cut session committed before the cut goes through the same checks as an answered one (commits in the journal, lock on sealed tests, warning for files outside the tests). What a failed or cut session leaves uncommitted, staged or not (a cut between `git add` and the commit is ordinary), is put back (index unstaged, tracked files restored, new files removed) with a warning that names the files, so a timed-out probe never hands the lot back for a dirty tree. Only a violation of the lock on sealed acceptance tests, or a dirty repository after a session that did answer, hands the lot back, as after any writing session.
|
|
554
|
+
|
|
555
|
+
**Measuring it.** The key is set in cadence's own `cadence.yaml` only, as a trial, and the lead sets it to `true` after the release is in service. Keep or drop it on figures: `cadence corrections <folder> --since <date>` (share of `bug-code` and of `cas limite` among the correction passes, lots with 2 passes or more, L430) and `cadence perf` (the `probe` step has its own row; tokens per lot). The `probe` step keeps the texts of the findings it sent to correction (`constats`, each starting with `sonde de cas limites : `): `cadence corrections` reads them as the findings of the `fix` pass that follows, in place of a review's. The pass is also told apart by the `probe` step that precedes the `fix` step and by the lot's warning `sonde de cas limites : <n> constat(s), passe de correction avant la revue`; the finding given to the fix session starts with `sonde de cas limites : `.
|
|
556
|
+
|
|
538
557
|
## The subject of the plan commits (`plan.commit`, L343)
|
|
539
558
|
|
|
540
559
|
The commits the program writes for the plan in a wave (`plan: <lot> démarré (orchestrate <wave>)`, `… 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`) take the template of the `plan.commit` key of `cadence.yaml`
|
package/docs/qualite.md
CHANGED
|
@@ -128,3 +128,5 @@ Shell has no complexity rule: keep a script small, and move logic into a languag
|
|
|
128
128
|
Start from the table above, measure, and fix the baseline **where the code is**: a threshold chosen to fit the existing
|
|
129
129
|
code is not a guard rail. Lower a threshold only when the baseline for it is empty or near, and never raise one: a
|
|
130
130
|
threshold that goes up is a decision, written in the plan.
|
|
131
|
+
|
|
132
|
+
The simplification audit of L461 (dead code, copies, how to split the three largest files, each point with the tests that protect it and its measure) is in [docs/mesures/audit-simplification-l461.md](mesures/audit-simplification-l461.md).
|
package/docs/whats-new.md
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
## In two lines
|
|
6
6
|
|
|
7
|
+
- **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
|
+
- **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
|
+
- **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.
|
|
7
10
|
- **1.32.0**: code-quality guard rails in a ratchet (ESLint, sonarjs, knip, jscpd vs a versioned baseline), a recipe for TS, Python, Java, shell; `raf done` refuses a lot whose recorded review is `non conforme`.
|
|
8
11
|
- **1.31.0**: `deliver --sha` refuses, outside a wave too, a sha that carries commits of a lot neither done nor ready (a `non conforme` verdict is not ready); `raf add/note/done` warn when a wave session writes in the main tree.
|
|
9
12
|
- **1.30.0**: a question can be answered while its wave still runs; the sibling-repository check of 1.29.0 only flags commits that cite a lot of the wave; `session context` reads the lead's threshold from the lead's folder.
|
|
@@ -59,6 +62,12 @@ Each is a paragraph in [docs/whats-new.md](whats-new.md) and a full section in [
|
|
|
59
62
|
|
|
60
63
|
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).
|
|
61
64
|
|
|
65
|
+
**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
|
+
|
|
67
|
+
**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).
|
|
68
|
+
|
|
69
|
+
**1.33.0**: the lots panel (`/hud lots`) shows, on each row of its « ordre des projets » section, the progress bar of the band — closed lots over total, coloured by the share done, the lots in progress and `+N cette semaine` (L481, `docs/cadence-hud.md`); the bars all start at the same column, the project name sitting in a box as wide as the longest name, which a proportional font aligns where spaces did not (L494, L495). Dragging and Alt+↑ / Alt+↓ are unchanged. A read-only simplification audit of the code (L461, `docs/mesures/audit-simplification-l461.md`) ranks dead code, copies and split plans by gain and risk; its first cleanups remove exports nothing imports and a dead type (L483, L484), with no change of behaviour.
|
|
70
|
+
|
|
62
71
|
**1.32.0**: code-quality guard rails for cadence itself and a reference recipe for any project (L462, `docs/qualite.md`): ESLint with typescript-eslint and sonarjs (file and function length, depth, parameters, cyclomatic and cognitive complexity), knip (dead code, unused exports and dependencies) and jscpd (duplicates), compared by `npm run qualite` to a versioned baseline — existing code passes, nothing may get worse, a file a lot touches can only improve; `--migrer` is the admitted path to move or split a file of the baseline, and a changed tool configuration or a new suppression directive is refused. The recipe gives the same ratchet for Python, Java and shell. `raf done` refuses, without `--force`, a lot whose recorded code-review verdict is non-compliant, even when the review covers all its commits (L476, `docs/raf.md`), the predicate `cadence deliver --sha` uses since 1.31.0.
|
|
63
72
|
|
|
64
73
|
**1.31.0**: `cadence deliver --sha <sha>` refuses, outside a wave too, a sha whose history since the last delivery carries work commits of a lot that is neither done nor ready — ready meaning a compliant code review that covers the lot's commits up to that sha, so a fix stacked above a reviewed sha does not block it and a `non conforme` verdict does — and `--dry-run` lists the lots of the interval with their state (L474, `docs/deliver.md`). Before, the check only ran during a wave of the repository: on 30-10 a sha delivered as « L49 alone » took two unreviewed lots whose commits sat beneath it. `raf add`, `raf note` and `raf done` warn on stderr when a session of a live wave writes in the main tree of the repository (L475, `docs/raf.md`): a plan commit of the lead at that moment hands the lot back, as it did on 30-10.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sylad/cadence",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.34.1",
|
|
4
4
|
"description": "A small, repo-native working method: a versioned plan linked to your commits, a changelog with screenshots, session rituals and deliveries proven by their effect.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sylvain Ladoire",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Edge-case probe for lot `{{lot}}` — "{{titre}}" — of the repository `{{chemin}}`. You are a fresh session: you did not write this code, and the review that follows reads it as it stands. Your job is to try to break it, with tests at its edges, before that review.
|
|
2
|
+
Goal of the lot: {{objectif}}
|
|
3
|
+
{{repos}}
|
|
4
|
+
{{fiche}}
|
|
5
|
+
Commits of the lot:
|
|
6
|
+
{{commits}}
|
|
7
|
+
The diff of the lot is not pasted here: read it with `{{diff}}` (add `--stat` first for a large lot, then read it file by file), and open the code around each change.
|
|
8
|
+
For every function, parser, pattern, threshold or command the diff adds or changes, try the inputs at its edge:
|
|
9
|
+
- empty (empty string, list, object, file, zero);
|
|
10
|
+
- absent (missing key, null, undefined, a file that does not exist);
|
|
11
|
+
- twice (the same item or the same call twice, a duplicate, a repeat);
|
|
12
|
+
- wrong type (a string where a number is expected, an object for a list);
|
|
13
|
+
- refused (a rejected input, a failing dependency, the error path: the exact message and code the lot or its fiche states);
|
|
14
|
+
- the real shape of the data (a real file or a real call, never only a fixture you built to fit the code);
|
|
15
|
+
- other callers of what the diff changed (find them with `grep`; each must still work).
|
|
16
|
+
Rules: write the tests in NEW test files only (never edit an existing test), named after the rule they attack when the lot has a fiche. Run them, and commit them all, the ones that pass and the ones that fail, with explicit paths (never `git add -A` or `commit -a`) and a message that cites the lot (`probe({{lot}}): …`). Do not modify the application code: you find defects, you do not fix them. Do not modify any existing test, and never an `acceptation-<lot>.json` or the tests it seals. Do not push, deliver, run `raf done`, `raf ux` or `raf review`. Read the project's CLAUDE.md first.
|
|
17
|
+
Report in `echecs` one entry per test of yours that fails, written « <test name> — <the edge tried> — <what was expected> »; a test that passes is not listed. Leave `echecs` empty when none fails. What you could not try goes under `nonVerifie`. A question is only for a real blocker: the program writes it down and does not wait for an answer.
|
|
18
|
+
{{gate}}
|
|
19
|
+
{{workers}}
|
|
20
|
+
{{tmp}}
|