@sylad/cadence 1.6.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +47 -1734
  4. package/agents/acceptance-writer.md +1 -0
  5. package/bin/cadence.js +4 -1
  6. package/dist/audit.js +4 -3
  7. package/dist/cli.js +68 -7
  8. package/dist/config.js +46 -0
  9. package/dist/corrections.js +57 -22
  10. package/dist/deliver.js +8 -1
  11. package/dist/orchestrate/accept.js +8 -3
  12. package/dist/orchestrate/briefs.js +1 -1
  13. package/dist/orchestrate/command.js +3 -0
  14. package/dist/orchestrate/cycle.js +68 -6
  15. package/dist/perf.js +559 -0
  16. package/dist/state.js +29 -0
  17. package/docs/cadence-hud.md +50 -0
  18. package/docs/corrections.md +24 -0
  19. package/docs/cycle-vague-dark.svg +42 -0
  20. package/docs/cycle-vague-light.svg +42 -0
  21. package/docs/deliver.md +204 -0
  22. package/docs/fonctionnement-lead-dark.svg +101 -0
  23. package/docs/fonctionnement-lead-light.svg +101 -0
  24. package/docs/fonctionnement-lot-dark.svg +38 -0
  25. package/docs/fonctionnement-lot-light.svg +38 -0
  26. package/docs/fonctionnement-service-dark.svg +23 -0
  27. package/docs/fonctionnement-service-light.svg +23 -0
  28. package/docs/fonctionnement-wave-dark.svg +66 -0
  29. package/docs/fonctionnement-wave-light.svg +66 -0
  30. package/docs/fonctionnement.md +106 -0
  31. package/docs/lead-workflow-dark.svg +200 -0
  32. package/docs/lead-workflow-light.svg +200 -0
  33. package/docs/lead.md +149 -0
  34. package/docs/news.md +245 -0
  35. package/docs/orchestrate.md +639 -0
  36. package/docs/overview.md +27 -0
  37. package/docs/perf.md +84 -0
  38. package/docs/raf.md +192 -0
  39. package/docs/releasing.md +59 -0
  40. package/docs/session.md +107 -0
  41. package/docs/skills.md +76 -0
  42. package/docs/spec.md +60 -0
  43. package/docs/stabilite.md +35 -0
  44. package/docs/whats-new.md +83 -0
  45. package/package.json +29 -1
  46. package/skills/lead/SKILL.md +7 -0
  47. package/templates/acceptation-runner.mjs +1 -1
  48. package/templates/fiche-back.yaml +1 -1
  49. package/templates/fiche.yaml +1 -1
package/docs/news.md ADDED
@@ -0,0 +1,245 @@
1
+ [← cadence](../README.md)
2
+
3
+ # news
4
+
5
+ What changed *for the user*, one entry per visible lot, each with a screenshot.
6
+
7
+ - Mark a lot as user-facing with `raf add … --visible` (or `visible: true` in
8
+ the YAML). `raf done` and the post-commit hook remind you to write its entry;
9
+ `raf check` fails while a visible lot is done without one.
10
+ - An entry is a Markdown file in `docs/nouveautes/`, with a YAML header.
11
+ Screenshots are files you take yourself, stored next to the entries.
12
+ - `cadence news build` writes `nouveautes.json` for your app to display, a
13
+ self-contained `index.html`, and copies the screenshots.
14
+
15
+ ```sh
16
+ raf add "Amounts like 3.000 read as three thousand" --visible # → L8
17
+ raf start L8 && git commit -m "fix(L8): thousands separator" && raf done L8
18
+ cadence news new L8 # docs/nouveautes/2026-09-29-amounts-like-3-000-….md (title: the lot's public title if any)
19
+ # add docs/nouveautes/captures/l8.png, list it under `captures:`, write the text
20
+ cadence news check # exit 1 on drift (also part of raf check)
21
+ cadence news build -o frontend/public/nouveautes
22
+ ```
23
+
24
+ ```markdown
25
+ ---
26
+ title: Amounts like 3.000 read as three thousand
27
+ date: 2026-09-29
28
+ created: 2026-09-29T14:32+02:00
29
+ lots: [L8]
30
+ captures: [captures/l8.png]
31
+ # nocapture: reason, when a screenshot makes no sense
32
+ ---
33
+ Imported statements now read **3.000** as three thousand, not three.
34
+ ```
35
+
36
+ A screenshot can say what it shows: write it as `{ file, alt }` instead of a
37
+ bare path, one text per screenshot.
38
+
39
+ ```yaml
40
+ captures:
41
+ - { file: captures/l8-before.png, alt: "Statement total read as 3 instead of 3,000" }
42
+ - captures/l8-after.png # a bare path still works: no alternative text
43
+ ```
44
+
45
+ | Command | Effect |
46
+ |---|---|
47
+ | `cadence news new <lot…> [--title t]` | entry skeleton, dated and timed now (`date`, `created`), titled after the lot's public title (`public`), else its title; `--title` wins |
48
+ | `cadence news list` | entries, newest first (see *Order* below) |
49
+ | `cadence news check` | visible lots done without entry, unknown lots, missing or undeclared screenshots, entries without creation time, bad headers, a lot whose screen sheet has hypotheses and whose entry lacks the `## Hypothèses` section (or a line for one of them) |
50
+ | `cadence news stamp` | migration: writes `created:` into entries without one (or with an empty one), from the author date of the commit that added the file under its current name (now if not committed yet) |
51
+ | `cadence news build [-o dir]` | `nouveautes.json` + `index.html` + screenshots (default `docs/nouveautes/site`) |
52
+
53
+ `--dir` changes the entries folder (default `docs/nouveautes` at the git root).
54
+ The Markdown is deliberately small: headings (`#` to `######`, rendered one level lower, `<h2>` to `<h6>`; a heading takes its own line and cuts the paragraph or list around it), paragraphs, `-` lists (a bullet may continue on the next lines, indented), `**bold**`,
55
+ `` `code` ``, `[links](../url)`; everything else is escaped text. The JSON holds
56
+ `{ project, generated, entries: [{ slug, title, date, lots, captures, html }] }`,
57
+ with screenshot paths relative to the JSON file. `captures` is always a list of
58
+ paths; an entry that gives at least one alternative text also carries `alts`,
59
+ the texts in the same order (`""` for a screenshot without one) — an entry
60
+ without any keeps exactly the shape above. The built page puts the text in the
61
+ image's `alt`, and falls back to "Capture : <title>".
62
+
63
+ **Order.** Everywhere (`list`, `build`, the JSON), entries are strictly newest
64
+ first: by `date`, then, on the same day, by creation time. Every entry carries
65
+ it to the minute in its `created` header, which `cadence news new` writes as
66
+ local time with an explicit offset (`2026-09-29T14:32+02:00`, or `Z`). The
67
+ offset is required, so the order does not depend on the machine's time zone:
68
+ `news check` (and `raf check`) flags a value without it, an impossible one, an
69
+ empty `created:`, and an entry without `created`. `cadence news stamp` fills
70
+ it in older entries (or replaces an empty one) from the author date of the
71
+ commit that added the file under its current name; until then, that date is
72
+ used for sorting (an entry not committed yet counts as the newest). Renames
73
+ are not followed: a renamed entry counts as added on the day of the rename,
74
+ so stamp it before renaming it. The file name only breaks the remaining ties,
75
+ since it follows the title, not the chronology. The page and the JSON still
76
+ show the day only.
77
+
78
+ ## UX review
79
+
80
+ ```sh
81
+ raf ux enable # from today, a --visible lot needs a UX review before done
82
+ raf ux L4 "compliant after 2 fixes" # record the verdict (from the ux-reviewer agent)
83
+ raf ux L8 "no screen: calculation fix"
84
+ ```
85
+
86
+ With the rule on, `raf done` refuses a visible lot without a review (`--force`
87
+ to override) and `raf check` reports visible lots finished after the `uxSince`
88
+ day without one. An empty verdict is refused, and one left empty or blank by hand
89
+ in the YAML counts as no review. Plans without `uxSince` are not affected.
90
+
91
+ ## Code review
92
+
93
+ ```sh
94
+ raf review enable # from today, a lot with commits needs a code review before done
95
+ raf commits L4 # what there is to review: the commits the gate counts for the lot
96
+ raf review L4 "compliant after 2 fixes" # record the verdict (from the code-reviewer agent)
97
+ ```
98
+
99
+ The counterpart of the UX review, off by default. With the rule on, `raf done`
100
+ refuses a lot that has at least one commit citing it and no recorded verdict
101
+ (`--force` to override), and `raf check` reports such lots finished after the
102
+ `reviewSince` day. A lot with no commit has nothing to review; neither does a
103
+ lot whose only commits touch plan files alone (the plan, a file listed under
104
+ `plan.files`, or the QA expectations file), are version commits (see [Releasing](releasing.md#releasing)), predate the plan's `since` or match an `ignore:` pattern — `raf commits <id>` prints exactly the counted set.
105
+
106
+ The verdict is tied to what was reviewed: `raf review` stores it on the lot with
107
+ the sha of the lot's latest counted commit (`review: { date, verdict, commit }`,
108
+ `commit: null` when the lot had none). A counted commit made after that one
109
+ makes the review stale: `raf done` refuses (`--force` to override), and
110
+ `raf check` reports a finished lot, until the lot is reviewed again and
111
+ `raf review` is rerun. A verdict
112
+ written by hand without a `commit` field is not checked for staleness. An empty
113
+ verdict is refused, and one left empty or blank by hand in the YAML counts as no
114
+ review. Plans without `reviewSince` are not affected.
115
+
116
+ A lot that works in neighbouring repositories (`repos:`, see [orchestrate](orchestrate.md#a-lot-whose-work-is-in-a-neighbouring-repository))
117
+ has its verdict tied to each of them: `raf review` also stores, under `repos`, the sha of the latest counted commit of the
118
+ lot in each neighbour (the one `raf commits` lists last: it cites the lot, falls within the lot's period and contains the `cite:` string if any) (`review: { date, verdict, commit, repos: { ../aetherwx-gitops: <sha> } }`, `null` when a
119
+ neighbour has none), and refuses to record when a listed repository cannot be read. `raf check` does not audit the
120
+ neighbours: their staleness is not checked, only the project's own commits are.
121
+
122
+ ## Documentation that follows the code
123
+
124
+ A stale README misleads. `cadence.yaml` can declare which documents must follow which code:
125
+
126
+ ```yaml
127
+ docs:
128
+ sync:
129
+ - paths: [src/**, bin/*.js] # what changes…
130
+ docs: [README.md, docs/usage.md] # …must change one of these, in the same lot
131
+ - paths: [templates/]
132
+ docs: [CLAUDE.md]
133
+ - paths: [frontend/src/**, '!**/*.test.tsx'] # a pattern starting with ! leaves files out
134
+ docs: [README.md]
135
+ since: 2026-10-09 # optional: also audit lots finished on or after this day
136
+ ```
137
+
138
+ A pattern is an exact path, with `*` (inside a folder), `**` (across folders), `?`, or a trailing `/` for
139
+ a whole folder. `raf check` takes the **work commits** of every lot in progress (plan-only commits and
140
+ version commits do not count — so a "What's new" line written in the version commit is not documentation; a lot finished on or after `docs.since` is audited too) and, for each pair, reports the lot when
141
+ those commits touch `paths` without any of them touching a file of `docs`:
142
+
143
+ ```
144
+ ✗ L7 : documentation en retard — src/a.ts, src/b.ts sans toucher README.md ou docs/usage.md (docs.sync)
145
+ ```
146
+
147
+ It counts as drift: exit code 1, shown in the `dérive` column of `cadence lead tour`, and the review
148
+ brief of `cadence orchestrate` (`review` and `review-small`) carries the list the program computed,
149
+ to be reported as one **major** finding per line — a stale document is not left to the reviewer's
150
+ memory of a sentence. Touching a document is what the program checks; whether its text is true is
151
+ still the review's reading. The commits of neighbouring repositories (`repos:`) are not audited.
152
+
153
+ ### An article elsewhere that follows the delivery
154
+
155
+ A case study that lives in a neighbouring repository (the project's article on a showcase site) goes stale
156
+ the same way. `docs.articles` names it:
157
+
158
+ ```yaml
159
+ docs:
160
+ articles:
161
+ - repo: ../claude-code-codex # neighbouring repository, relative to the project
162
+ file: src/pages/cas/demo.md # the article in it
163
+ name: demo # optional: the name in the lot title (default: the plan's project)
164
+ ```
165
+
166
+ After a **green** `cadence deliver`, for the lots it lists as delivered **that have a public title** (`public:`, or
167
+ the title of their Nouveautés entry), cadence opens in this repository's plan the lot
168
+ `Article demo à rafraîchir` (todo, estimate 0.5, `repos: [{ path: ../claude-code-codex, cite: demo }]`), with a note
169
+ that quotes the delivery, the public titles delivered, the article and the **sections to read again**: the headings
170
+ (`#` lines, or `<h1>`…`<h6>` of an Astro page) that share a word of five letters or more with a delivered title,
171
+ else all the `##` headings. The lot is then played like any other, in an ordinary wave (`cadence orchestrate`: an
172
+ implementer rewrites the article in the neighbouring repository, the review checks it against the note). If a lot
173
+ of that title is still open, it receives a note instead of a duplicate. Two entries with the same name (the same
174
+ project told in two neighbouring repositories) share one lot, which declares both repositories in `repos:`. Internal lots (no public title) open nothing;
175
+ a red delivery opens nothing; `cadence deliver --dry-run` announces the articles. The plan is written but **not
176
+ committed** (`deliver` never commits): the line `article à rafraîchir : L9 …` says so. With a plan kept by another
177
+ tool (read-only), the same line carries the instruction to open the lot with that tool. This replaces the manual
178
+ `sync-site-docs` skill.
179
+
180
+ ## QA review
181
+
182
+ No gate and no command here: the QA review comes **after** a delivery, and
183
+ `raf done` does not wait for it. It follows any delivery that changes what a
184
+ page shows or what it is served (screen, API, data source, configuration of
185
+ either) — in practice every delivery except docs-, plan- or tests-only ones: a
186
+ backend-only lot can empty a page without touching a screen, and the agent then
187
+ walks the pages that call the changed endpoints. It also walks the pages that consume the services the lot changed; when the diff changes no route and no screen, or cannot be linked to pages, it walks every page and says so. The `qa-reviewer` agent
188
+ opens each page of the running app in a real browser and judges it from the
189
+ user's side. A page can be empty while everything else is green — no code
190
+ changed, a data source went down upstream, the unit tests replace the network,
191
+ `/api/health` answers ok, and the "nothing found" on screen is the message the
192
+ code was written to show.
193
+
194
+ The agent cannot tell such an empty state from a normal one by itself: the
195
+ project says what each page must show, in `docs/qa/expectations.md` — one
196
+ `## <route>` section per page, three kinds of lines:
197
+
198
+ ```markdown
199
+ # QA expectations
200
+
201
+ ## *
202
+ - shows: the header and the navigation links
203
+ - never: "Loading failed", "Too Many Requests"
204
+ - api: /api/live/current — may be empty when no match is within 24 hours
205
+
206
+ ## /players
207
+ - shows: the squad of the last match — at least 11 players
208
+ - shows: the season statistics table, 8 columns — 1440 only
209
+ - never: "No recent line-up found"
210
+ - api: /api/squad/last — a non-empty list
211
+
212
+ ## /fixtures/:id (the first match linked from /fixtures)
213
+ - shows: both team names, the date, the score once the match is played
214
+ - never: "Unknown match"
215
+ - api: /api/fixtures/:id
216
+ ```
217
+
218
+ - `shows:` — content that must be present and non-empty, with a count where one exists;
219
+ - `never:` — texts that must not appear: error messages, and empty-state messages that mean
220
+ missing data;
221
+ - `api:` — the calls the page depends on: each must answer 2xx with a non-empty body (a 200 with
222
+ `[]`, `{}` or `null` is a failure, unless its line says `may be empty when …`).
223
+
224
+ An optional `## *` section holds what every page must show, never show and call. A line may end
225
+ with a condition in plain words, which the agent honours: `may be empty when …`, `1440 only`,
226
+ `390 only` (a line without a width holds at both). Content hidden on the phone by design is not a
227
+ defect unless a `shows:` line requires it at 390; content pushed outside the visible area (it
228
+ needs a sideways scroll) is reported as suspect and handed to `ux-reviewer` in one line.
229
+
230
+ The rest is free text, written for a reader: a line can be repeated, and a route with a parameter
231
+ names a real value to visit or says where to find one. The file can live elsewhere:
232
+
233
+ ```yaml
234
+ # cadence.yaml
235
+ qa:
236
+ expectations: docs/quality/pages.md
237
+ ```
238
+
239
+ The agent reads that key, and so does `raf check`: a commit touching only that file is plan upkeep (no lot to cite, see above). Without an expectations file the agent walks
240
+ the routes it discovers and still runs its universal checks: an error shown, a failed API call
241
+ whose content is missing on screen, a broken or missing content image are defects with or without a
242
+ file; an empty 2xx body, like whatever else would need an expectation to judge, is suspect at most
243
+ (it may be a normal absence). For a route with a
244
+ parameter, it finds a real value in the app's links or its API responses and says how it built the
245
+ URL. The agent then returns a draft for you to correct — it never writes the file itself.