@sylad/cadence 1.21.0 → 1.21.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.
@@ -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.21.0",
11
+ "version": "1.21.1",
12
12
  "source": "./",
13
13
  "author": {
14
14
  "name": "Sylvain Ladoire"
@@ -17,7 +17,7 @@
17
17
  {
18
18
  "name": "cadence-hud",
19
19
  "description": "A status band above the Claude Code prompt: context, 5 h / 7 d quota windows, cost per model, agents of the session and the running cadence orchestrate waves, plus a read-only lots panel (`/hud lots`). Works without the cadence CLI, except the per-project plan progress and the lots panel, which need `cadence` on the PATH.",
20
- "version": "0.6.0",
20
+ "version": "0.6.1",
21
21
  "source": "./plugins/cadence-hud",
22
22
  "author": {
23
23
  "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.21.0",
4
+ "version": "1.21.1",
5
5
  "author": { "name": "Sylvain Ladoire" },
6
6
  "homepage": "https://github.com/Sylad/cadence",
7
7
  "repository": "https://github.com/Sylad/cadence",
@@ -704,6 +704,8 @@ async function session(c, kind, local = false) {
704
704
  if (playwright)
705
705
  l.uxCaptures = join(dirname(mcpConfig), 'playwright');
706
706
  const answerInBrief = l.pendingAnswer; // gardée pour la rendre si la session ne part jamais (créneau abandonné, L332)
707
+ if (answerInBrief && kind === 'fix')
708
+ step.answered = true;
707
709
  l.pendingAnswer = null; // la réponse est dans le brief : elle ne repart pas avec la session suivante
708
710
  const tmpDir = w.store.tmpDir(l.project, l.lot); // TMPDIR de la session, aussi en --add-dir : hors du cwd, un Write y serait refusé en `claude -p`
709
711
  // Délai (L298) : l'étape d'écriture est proportionnée à l'estimate et à la fiche du lot, puis prolongée à chaque échéance où elle a commité.
@@ -2199,12 +2201,19 @@ async function work(c, kind) {
2199
2201
  return;
2200
2202
  }
2201
2203
  // La session peut n'avoir plus rien à commiter (réponse du lead, lot commité avant la vague) : le travail du lot est déjà dans git.
2202
- // Même règle côté fix (L56) : la passe n'avait rien à ajouter, le lot a déjà ses commits de travail → revue neuve ; la passe reste consommée, MAX_PASSES borne la boucle.
2204
+ // Même règle côté fix (L56) : la passe n'avait rien à ajouter, le lot a déjà ses commits de travail → revue neuve, à condition que la session donne sa raison (L406, plus bas) ; la passe reste consommée, MAX_PASSES borne la boucle.
2203
2205
  const alreadyDone = hasWork(plan, wd(c), l);
2204
2206
  if (made === 0 && !alreadyDone && !headMoved) {
2205
2207
  stop(c, 'handed-back', `${kind} sans commit`);
2206
2208
  return;
2207
2209
  }
2210
+ // L406 : une correction qui ne commite rien doit dire pourquoi (« choix », lu par la revue). Sans raison, la revue relirait les mêmes commits et rendrait les mêmes constats : la passe ne compte pas (toFix l'avait comptée), le lot est rendu.
2211
+ const reason = (rep.choix ?? []).some((x) => x.trim()) || !!done.step.answered; // la réponse du lead, que la session a lue dans son brief, vaut raison
2212
+ if (kind === 'fix' && made === 0 && !headMoved && !docsPass && !reason) {
2213
+ l.pass = Math.max(0, l.pass - 1);
2214
+ stop(c, 'handed-back', 'fix sans commit ni raison (choix vide) : la revue aurait relu les mêmes commits');
2215
+ return;
2216
+ }
2208
2217
  // L317 : la passe du bibliothécaire qui laisse l'écart ouvert (rien commité, ou autre chose que la documentation) ne passe pas à la revue : le lot ne finirait pas prêt, `raf check` resterait rouge.
2209
2218
  if (docsPass) {
2210
2219
  const open = openDocGap(c);
@@ -2216,7 +2225,7 @@ async function work(c, kind) {
2216
2225
  if (headMoved)
2217
2226
  l.warnings.push(`${minorsPass ? 'passe des mineurs' : 'correction'} reprise sans nouveau commit : un commit d'une session précédente est relu par la revue`);
2218
2227
  else if (made === 0)
2219
- l.warnings.push(kind === 'fix' ? 'fix sans nouveau commit : revue lancée sur les commits du lot' : `${kind} sans nouveau commit : revue lancée sur les commits déjà faits du lot`);
2228
+ l.warnings.push(kind === 'fix' ? 'fix sans nouveau commit : revue lancée sur les commits du lot, avec la raison de la session (choix)' : `${kind} sans nouveau commit : revue lancée sur les commits déjà faits du lot`);
2220
2229
  const red = [];
2221
2230
  // Tests annoncés rouges (L213) : avec orchestrate.test, le programme rejoue et compare à la ligne de base, la session n'est crue que si les tests y sont rouges autrement que par des échecs de départ ; sans, la liste des échecs de base de la session, non vérifiée.
2222
2231
  const claimed = { source: 'tests', gravite: 'bloquant', texte: `tests annoncés rouges par la session : ${rep.tests.commande} — ${rep.tests.resultat}` };
@@ -59,7 +59,7 @@ answers `argument inconnu : … (attendu : cmd, projets, lots)` and leaves the b
59
59
 
60
60
  ### The lots panel (`/hud lots`, L401)
61
61
 
62
- `/hud lots` opens a read-only **panel** beside the conversation (inline above the prompt on the main screen); the same command closes it. It is never opened on its own, and a terminal under 110 columns answers `terminal trop étroit pour le panneau (110 colonnes au moins)` and opens nothing. For each project of the folder (the order of `priority:`) it draws the open lots as a tree, with their state and their `after:` links:
62
+ `/hud lots` opens a read-only **panel** beside the conversation (inline above the prompt on the main screen); the same command closes it. It is never opened on its own, and the command opens it whatever the width of the window, Claude placing it; when Claude cannot place it, the command answers `panneau des lots non placé : <reason>` and nothing opens. For each project of the folder (the order of `priority:`) it draws the open lots as a tree, with their state and their `after:` links:
63
63
 
64
64
  ```
65
65
  Lots lecture seule lu à 15:52
@@ -454,9 +454,13 @@ review) still starts with the implementation session: its brief tells it to read
454
454
  sub-tasks, which carry the findings of any earlier review. If that session ends without a new commit on a lot that
455
455
  already has commits, the wave goes on to the review (warning `implement sans nouveau commit`) instead of handing the
456
456
  lot back; with no commit on the lot at all it is handed back as `implement sans commit`. The same goes for a
457
- correction pass: a `fix` session that adds no commit to a lot that already has work commits goes on to a fresh review
458
- (warning `fix sans nouveau commit : revue lancée sur les commits du lot`), the pass still counted — the cap of two
459
- correction passes stays the guard against a loop; with no commit on the lot it is handed back as `fix sans commit`.
457
+ correction pass: a `fix` session that adds no commit to a lot that already has work commits must give its reason under
458
+ `choix` (the brief says so; a blank entry is no reason). With the reason, the wave goes on to a fresh review, which reads
459
+ it (warning `fix sans nouveau commit : revue lancée sur les commits du lot, avec la raison de la session (choix)`), the
460
+ pass counted — the cap of two correction passes stays the guard against a loop. Without it (L406), a review would reread
461
+ the same commits and return the same findings, so the lot is handed back as `fix sans commit ni raison (choix vide) :
462
+ la revue aurait relu les mêmes commits` and the pass is not counted (measured over the wave states of 2026-10-28 and before: 68 `fix` sessions without commit, 5 with an empty `choix` — about 7 %; the two L401 passes of 2026-10-28 gave a reason and stay counted, the test gate relaunched them, not a review). With no commit on the lot at all it is handed back as
463
+ `fix sans commit`.
460
464
 
461
465
  **Compliant with minor findings**: the minors are not left for a follow-up lot. One **minors pass** runs
462
466
  before concluding: a new Sonnet session with its own brief (`fix-minors.md`) fixes the minors that are right
package/docs/whats-new.md CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  ## In two lines
6
6
 
7
+ - **1.21.1**: `/hud lots` opens on the desktop app whatever the width; a correction session that makes no commit must say why, or the lot is handed back.
7
8
  - **1.21.0**: `/hud lots` opens a panel beside the conversation with the open lots of every project; the pre-push hook of a wave refuses a push that carries a lot not ready.
8
9
  - **1.20.0**: `raf move <id> --before|--after <id>` reorders a lot or a sub-task in the plan, refused during a wave of the repository and on a plan kept by another tool.
9
10
  - **1.19.1**: `cadence verify --gate` in the main tree reads `HEAD` and `git status` again after the steps, says what moved and prints no green or red verdict that is not the sha's.
@@ -46,6 +47,8 @@ Each is a paragraph in [docs/whats-new.md](whats-new.md) and a full section in [
46
47
 
47
48
  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).
48
49
 
50
+ **1.21.1**: `/hud lots` opened nothing on the desktop app, even on a very wide screen (« terminal trop étroit », L408): the mod checked 110 columns itself, while a panel the person asks for is placed at any width; the engine now decides, and says « non placé » with its reason otherwise (cadence-hud 0.6.1). In a wave, a correction session that makes no commit must give its reason under `choix`; without one the lot is handed back instead of replaying the same review (L406, `docs/orchestrate.md`).
51
+
49
52
  **1.21.0**: what is in progress, project by project, is now visible beside the conversation. `/hud lots` (cadence-hud 0.6.0, L401, `docs/cadence-hud.md`) opens a read-only panel with, for each project of the parent folder, the tree of its open lots and native sub-tasks, their state (in progress, ready, blocked, in a wave, handed back, in question) and their `after:` links, crossed out once satisfied; it reads `cadence lead tour --json`, which now carries a `lots` field (measured 7.0–8.4 s on ten projects, as before). The temporary `pre-push` hook of a wave also refuses a push of the lead or of a hand-started session that carries a commit of a lot not ready, names the lot and gives the safe command `git push <remote> <sha>:<branch>`; for a tag it refuses without a command, since a tag must name its own commit (L405, `docs/orchestrate.md`).
50
53
 
51
54
  **1.20.0**: the order of the plan is no longer edited by hand. `raf move <id> --before|--after <id>` (L400, `docs/raf.md`) moves a lot among the lots, or a sub-task among the sub-tasks of its lot; it is refused across different parents, on an archived lot, during a live wave of the repository (the same detection as `cadence deliver`) and on a plan kept by another tool (with that tool's command); a lot already in place leaves the file untouched, and like every plan write it does not commit. A test that read the real plan file directly, red since `raf archive`, now goes through the plan loader, and a guard test refuses any test that reads the real plan without it (L404).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sylad/cadence",
3
- "version": "1.21.0",
3
+ "version": "1.21.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",
@@ -25,7 +25,7 @@ A point you cannot hold is written under "choix" or "nonVerifie" of your report,
25
25
 
26
26
  Auto-verification once the tests are green, before the review: when the full test suite and the build pass, re-read the complete diff of your fix commits (`git diff <HEAD before your first fix>..HEAD`, run in each repository where you committed a fix: the project and any neighbouring repository above) against the grid of the code-reviewer agent: code bug; architecture drift; docs/architecture.md (or the project's architecture documentation) up to date; edge cases; one test per changed behaviour. What you find in your own fix, fix it at once (a `fix({{lot}}): …` commit) and rerun the suite and the build; touch nothing else. Then write in "resume" a paragraph that starts with « auto-vérification »: what you re-read, what you found and fixed, what you could not hold. It is one reading of the diff, not a second review: no subagent, no new exploration, no re-reading of files the diff does not touch.
27
27
 
28
- If a finding is wrong, say so under "choix" with the reason. Ask (under "questions") only when a fix needs a decision that passes the rule below.
28
+ If a finding is wrong, say so under "choix" with the reason. If you make no commit at all, "choix" MUST say why: a session with no commit and no reason is handed back to the lead without a new review (the review would reread the same commits). Ask (under "questions") only when a fix needs a decision that passes the rule below.
29
29
  A question is legitimate only if it names what it would change: the scope of the lot, the architecture, or a costly rollback (data, production, public API);
30
30
  otherwise it is a choice: decide, write the alternative you did not take, go on. Minor choices to settle yourself:
31
31
  a spacing, colour or label value when a measurement or a rule justifies it; the URL of a link (the most general official page if a precise one is not certain);