@sylad/cadence 1.6.0 → 1.7.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 (41) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +45 -1734
  4. package/agents/acceptance-writer.md +1 -0
  5. package/dist/audit.js +4 -3
  6. package/dist/cli.js +4 -4
  7. package/dist/orchestrate/accept.js +8 -3
  8. package/dist/orchestrate/briefs.js +1 -1
  9. package/dist/orchestrate/command.js +3 -0
  10. package/dist/orchestrate/cycle.js +68 -6
  11. package/docs/cadence-hud.md +50 -0
  12. package/docs/corrections.md +24 -0
  13. package/docs/cycle-vague-dark.svg +42 -0
  14. package/docs/cycle-vague-light.svg +42 -0
  15. package/docs/deliver.md +204 -0
  16. package/docs/fonctionnement-lead-dark.svg +101 -0
  17. package/docs/fonctionnement-lead-light.svg +101 -0
  18. package/docs/fonctionnement-lot-dark.svg +38 -0
  19. package/docs/fonctionnement-lot-light.svg +38 -0
  20. package/docs/fonctionnement-service-dark.svg +23 -0
  21. package/docs/fonctionnement-service-light.svg +23 -0
  22. package/docs/fonctionnement-wave-dark.svg +66 -0
  23. package/docs/fonctionnement-wave-light.svg +66 -0
  24. package/docs/fonctionnement.md +106 -0
  25. package/docs/lead-workflow-dark.svg +200 -0
  26. package/docs/lead-workflow-light.svg +200 -0
  27. package/docs/lead.md +147 -0
  28. package/docs/news.md +245 -0
  29. package/docs/orchestrate.md +639 -0
  30. package/docs/overview.md +27 -0
  31. package/docs/raf.md +192 -0
  32. package/docs/releasing.md +59 -0
  33. package/docs/session.md +107 -0
  34. package/docs/skills.md +76 -0
  35. package/docs/spec.md +60 -0
  36. package/docs/stabilite.md +35 -0
  37. package/docs/whats-new.md +81 -0
  38. package/package.json +28 -1
  39. package/templates/acceptation-runner.mjs +1 -1
  40. package/templates/fiche-back.yaml +1 -1
  41. package/templates/fiche.yaml +1 -1
@@ -0,0 +1,200 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1650 810" width="1650" height="810" role="img" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif" font-size="13" fill="#1f2328">
2
+ <title>Workflow of the lead skill in three lanes: the human, the lead session, and the orchestrate program with its agents</title>
3
+ <defs><marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#57606a"/></marker>
4
+ <marker id="arrw" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#cf222e"/></marker></defs>
5
+ <rect width="1650" height="810" fill="#ffffff"/>
6
+ <text x="825" y="34" text-anchor="middle" font-size="18" font-weight="600">The lead workflow: decide at the top, work in fresh sessions</text>
7
+ <rect x="10" y="70" width="1630" height="200" fill="#f6f8fa" stroke="#d0d7de"/>
8
+ <line x1="150" y1="70" x2="150" y2="270" stroke="#d0d7de"/>
9
+ <text x="24" y="146" font-weight="700" font-size="15" fill="#bf8700">Human</text>
10
+ <text x="24" y="166" font-size="11.5" fill="#57606a">chooses, answers,</text>
11
+ <text x="24" y="181" font-size="11.5" fill="#57606a">gives the UX verdict</text>
12
+ <rect x="10" y="270" width="1630" height="200" fill="#ffffff" stroke="#d0d7de"/>
13
+ <line x1="150" y1="270" x2="150" y2="470" stroke="#d0d7de"/>
14
+ <text x="24" y="339" font-weight="700" font-size="15" fill="#0969da">Lead session</text>
15
+ <text x="24" y="359" font-size="11.5" fill="#57606a">stays small:</text>
16
+ <text x="24" y="374" font-size="11.5" fill="#57606a">reads, decides, checks,</text>
17
+ <text x="24" y="389" font-size="11.5" fill="#57606a">delivers</text>
18
+ <rect x="10" y="470" width="1630" height="320" fill="#f6f8fa" stroke="#d0d7de"/>
19
+ <line x1="150" y1="470" x2="150" y2="790" stroke="#d0d7de"/>
20
+ <text x="24" y="606" font-weight="700" font-size="15" fill="#1a7f37">orchestrate</text>
21
+ <text x="24" y="626" font-size="11.5" fill="#57606a">program and agents</text>
22
+ <text x="24" y="641" font-size="11.5" fill="#57606a">(fresh short sessions)</text>
23
+ <text x="240" y="88" text-anchor="middle" font-size="11.5" font-weight="600" fill="#57606a">1 Tour</text>
24
+ <text x="420" y="88" text-anchor="middle" font-size="11.5" font-weight="600" fill="#57606a">2 Wave</text>
25
+ <text x="600" y="88" text-anchor="middle" font-size="11.5" font-weight="600" fill="#57606a">3 Relay</text>
26
+ <text x="780" y="88" text-anchor="middle" font-size="11.5" font-weight="600" fill="#57606a">4 Review</text>
27
+ <text x="960" y="88" text-anchor="middle" font-size="11.5" font-weight="600" fill="#57606a">5 Re-check</text>
28
+ <text x="1140" y="88" text-anchor="middle" font-size="11.5" font-weight="600" fill="#57606a">6 Delivery</text>
29
+ <text x="1320" y="88" text-anchor="middle" font-size="11.5" font-weight="600" fill="#57606a">7 Threshold</text>
30
+ <text x="1500" y="88" text-anchor="middle" font-size="11.5" font-weight="600" fill="#57606a">8 Close</text>
31
+ <g id="tour"><rect x="161" y="337" width="158" height="66" rx="8" fill="#ddf4ff" stroke="#0969da" stroke-width="1.5"/>
32
+ <text x="240" y="358.5" text-anchor="middle" font-weight="600" font-family="ui-monospace,SFMono-Regular,Menlo,monospace" font-size="11.5">cadence lead tour</text>
33
+ <text x="240" y="374.5" text-anchor="middle">one line per project</text>
34
+ <text x="240" y="390.5" text-anchor="middle">+ three proposals</text>
35
+ </g>
36
+ <g id="choose"><rect x="161" y="137" width="158" height="66" rx="8" fill="#fff8c5" stroke="#bf8700" stroke-width="1.5"/>
37
+ <text x="240" y="158.5" text-anchor="middle" font-weight="600">Picks the lots</text>
38
+ <text x="240" y="174.5" text-anchor="middle">and the order</text>
39
+ <text x="240" y="190.5" text-anchor="middle">(the priority)</text>
40
+ </g>
41
+ <g id="launch"><rect x="341" y="337" width="158" height="66" rx="8" fill="#ddf4ff" stroke="#0969da" stroke-width="1.5"/>
42
+ <text x="420" y="358.5" text-anchor="middle" font-weight="600">Starts the wave</text>
43
+ <text x="420" y="374.5" text-anchor="middle" font-family="ui-monospace,SFMono-Regular,Menlo,monospace" font-size="11.5">orchestrate … --wave</text>
44
+ <text x="420" y="390.5" text-anchor="middle">in the background</text>
45
+ </g>
46
+ <g id="precheck"><rect x="161" y="508" width="158" height="82" rx="8" fill="#dafbe1" stroke="#1a7f37" stroke-width="1.5" stroke-dasharray="5 3"/>
47
+ <text x="240" y="529.5" text-anchor="middle" font-weight="600">Precheck</text>
48
+ <text x="240" y="545.5" text-anchor="middle">local model or Sonnet:</text>
49
+ <text x="240" y="561.5" text-anchor="middle">already delivered?</text>
50
+ <text x="240" y="577.5" text-anchor="middle">yes → back to lead</text>
51
+ </g>
52
+ <g id="spec"><rect x="341" y="480" width="158" height="66" rx="8" fill="#dafbe1" stroke="#1a7f37" stroke-width="1.5" stroke-dasharray="5 3"/>
53
+ <text x="420" y="501.5" text-anchor="middle" font-weight="600">Spec (screen: page)</text>
54
+ <text x="420" y="517.5" text-anchor="middle">spec-writer: mockup</text>
55
+ <text x="420" y="533.5" text-anchor="middle">+ sheet, 1440 / 390</text>
56
+ </g>
57
+ <g id="mockup"><rect x="521" y="480" width="158" height="66" rx="8" fill="#dafbe1" stroke="#1a7f37" stroke-width="1.5" stroke-dasharray="5 3"/>
58
+ <text x="600" y="501.5" text-anchor="middle" font-weight="600">Mockup review</text>
59
+ <text x="600" y="517.5" text-anchor="middle">ux-reviewer, 2 passes</text>
60
+ <text x="600" y="533.5" text-anchor="middle">max, then handed back</text>
61
+ </g>
62
+ <g id="backspec"><rect x="341" y="552" width="158" height="66" rx="8" fill="#dafbe1" stroke="#1a7f37" stroke-width="1.5" stroke-dasharray="5 3"/>
63
+ <text x="420" y="573.5" text-anchor="middle" font-weight="600">Back-end spec</text>
64
+ <text x="420" y="589.5" text-anchor="middle">spec: true: cases,</text>
65
+ <text x="420" y="605.5" text-anchor="middle">rules, contracts</text>
66
+ </g>
67
+ <g id="sheetreview"><rect x="521" y="552" width="158" height="66" rx="8" fill="#dafbe1" stroke="#1a7f37" stroke-width="1.5" stroke-dasharray="5 3"/>
68
+ <text x="600" y="573.5" text-anchor="middle" font-weight="600">Sheet review</text>
69
+ <text x="600" y="589.5" text-anchor="middle">code-reviewer, 2</text>
70
+ <text x="600" y="605.5" text-anchor="middle">passes max</text>
71
+ </g>
72
+ <g id="accept"><rect x="701" y="480" width="158" height="138" rx="8" fill="#dafbe1" stroke="#1a7f37" stroke-width="1.5" stroke-dasharray="5 3"/>
73
+ <text x="780" y="543" text-anchor="middle" font-weight="600">Accept</text>
74
+ <text x="780" y="559" text-anchor="middle">red tests + lock</text>
75
+ <text x="780" y="575" text-anchor="middle">if accept declared</text>
76
+ </g>
77
+ <g id="implement"><rect x="341" y="650" width="158" height="66" rx="8" fill="#dafbe1" stroke="#1a7f37" stroke-width="1.5"/>
78
+ <text x="420" y="671.5" text-anchor="middle" font-weight="600">Implementation</text>
79
+ <text x="420" y="687.5" text-anchor="middle">test first, commits</text>
80
+ <text x="420" y="703.5" text-anchor="middle">cite the lot</text>
81
+ </g>
82
+ <g id="relay"><rect x="521" y="337" width="158" height="66" rx="8" fill="#ddf4ff" stroke="#0969da" stroke-width="1.5"/>
83
+ <text x="600" y="358.5" text-anchor="middle" font-weight="600">Relays the journal</text>
84
+ <text x="600" y="374.5" text-anchor="middle" font-family="ui-monospace,SFMono-Regular,Menlo,monospace" font-size="11.5">tail -F journal.log</text>
85
+ <text x="600" y="390.5" text-anchor="middle">one sentence per line</text>
86
+ </g>
87
+ <g id="answer"><rect x="521" y="137" width="158" height="66" rx="8" fill="#fff8c5" stroke="#bf8700" stroke-width="1.5"/>
88
+ <text x="600" y="158.5" text-anchor="middle" font-weight="600">Answers a question</text>
89
+ <text x="600" y="174.5" text-anchor="middle">the lead never</text>
90
+ <text x="600" y="190.5" text-anchor="middle">answers for them</text>
91
+ </g>
92
+ <g id="uxpass"><rect x="521" y="650" width="158" height="66" rx="8" fill="#dafbe1" stroke="#1a7f37" stroke-width="1.5" stroke-dasharray="5 3"/>
93
+ <text x="600" y="671.5" text-anchor="middle" font-weight="600">UX pass</text>
94
+ <text x="600" y="687.5" text-anchor="middle">visible lot + app</text>
95
+ <text x="600" y="703.5" text-anchor="middle">declared; vs mockup</text>
96
+ </g>
97
+ <g id="codereview"><rect x="701" y="650" width="158" height="66" rx="8" fill="#dafbe1" stroke="#1a7f37" stroke-width="1.5"/>
98
+ <text x="780" y="671.5" text-anchor="middle" font-weight="600">Code review</text>
99
+ <text x="780" y="687.5" text-anchor="middle">Opus (Sonnet ≤ 0.25 d)</text>
100
+ <text x="780" y="703.5" text-anchor="middle">records raf review</text>
101
+ </g>
102
+ <g id="fix"><rect x="881" y="650" width="158" height="66" rx="8" fill="#dafbe1" stroke="#1a7f37" stroke-width="1.5" stroke-dasharray="5 3"/>
103
+ <text x="960" y="671.5" text-anchor="middle" font-weight="600">Correction</text>
104
+ <text x="960" y="687.5" text-anchor="middle">new session, 2 passes</text>
105
+ <text x="960" y="703.5" text-anchor="middle">3rd if it converges</text>
106
+ </g>
107
+ <g id="table"><rect x="701" y="337" width="158" height="66" rx="8" fill="#ddf4ff" stroke="#0969da" stroke-width="1.5"/>
108
+ <text x="780" y="358.5" text-anchor="middle" font-weight="600">Final table</text>
109
+ <text x="780" y="374.5" text-anchor="middle">ready · handed back</text>
110
+ <text x="780" y="390.5" text-anchor="middle">· « livrable jusqu'à »</text>
111
+ </g>
112
+ <g id="recheck"><rect x="881" y="337" width="158" height="66" rx="8" fill="#ddf4ff" stroke="#0969da" stroke-width="1.5"/>
113
+ <text x="960" y="358.5" text-anchor="middle" font-weight="600">Re-verifies itself</text>
114
+ <text x="960" y="374.5" text-anchor="middle">git log · tests · build</text>
115
+ <text x="960" y="390.5" text-anchor="middle" font-family="ui-monospace,SFMono-Regular,Menlo,monospace" font-size="11.5">raf check</text>
116
+ </g>
117
+ <g id="uxverdict"><rect x="881" y="137" width="158" height="66" rx="8" fill="#fff8c5" stroke="#bf8700" stroke-width="1.5"/>
118
+ <text x="960" y="158.5" text-anchor="middle" font-weight="600">Looks at the captures</text>
119
+ <text x="960" y="174.5" text-anchor="middle">UX verdict →</text>
120
+ <text x="960" y="190.5" text-anchor="middle" font-family="ui-monospace,SFMono-Regular,Menlo,monospace" font-size="11.5">raf ux (visible lot)</text>
121
+ </g>
122
+ <g id="done"><rect x="1061" y="337" width="158" height="66" rx="8" fill="#ddf4ff" stroke="#0969da" stroke-width="1.5"/>
123
+ <text x="1140" y="358.5" text-anchor="middle" font-weight="600" font-family="ui-monospace,SFMono-Regular,Menlo,monospace" font-size="11.5">raf done</text>
124
+ <text x="1140" y="374.5" text-anchor="middle">then push</text>
125
+ <text x="1140" y="390.5" text-anchor="middle" font-family="ui-monospace,SFMono-Regular,Menlo,monospace" font-size="11.5">cadence deliver</text>
126
+ </g>
127
+ <g id="qa"><rect x="1061" y="650" width="158" height="66" rx="8" fill="#dafbe1" stroke="#1a7f37" stroke-width="1.5" stroke-dasharray="5 3"/>
128
+ <text x="1140" y="671.5" text-anchor="middle" font-weight="600">qa-reviewer</text>
129
+ <text x="1140" y="687.5" text-anchor="middle">reads only; blocking</text>
130
+ <text x="1140" y="703.5" text-anchor="middle">findings → the human</text>
131
+ </g>
132
+ <g id="ctx"><rect x="1241" y="337" width="158" height="66" rx="8" fill="#ddf4ff" stroke="#0969da" stroke-width="1.5"/>
133
+ <text x="1320" y="358.5" text-anchor="middle" font-weight="600">Context under 60 %?</text>
134
+ <text x="1320" y="374.5" text-anchor="middle" font-family="ui-monospace,SFMono-Regular,Menlo,monospace" font-size="11.5">session context</text>
135
+ <text x="1320" y="390.5" text-anchor="middle">error = at threshold</text>
136
+ </g>
137
+ <g id="next"><rect x="1241" y="650" width="158" height="66" rx="8" fill="#dafbe1" stroke="#1a7f37" stroke-width="1.5"/>
138
+ <text x="1320" y="671.5" text-anchor="middle" font-weight="600">Next wave</text>
139
+ <text x="1320" y="687.5" text-anchor="middle" font-family="ui-monospace,SFMono-Regular,Menlo,monospace" font-size="11.5">… --continue</text>
140
+ <text x="1320" y="703.5" text-anchor="middle">draws the next ready lot</text>
141
+ </g>
142
+ <g id="close"><rect x="1421" y="337" width="158" height="66" rx="8" fill="#ddf4ff" stroke="#0969da" stroke-width="1.5"/>
143
+ <text x="1500" y="358.5" text-anchor="middle" font-weight="600">Close</text>
144
+ <text x="1500" y="374.5" text-anchor="middle" font-family="ui-monospace,SFMono-Regular,Menlo,monospace" font-size="11.5">session-close</text>
145
+ <text x="1500" y="390.5" text-anchor="middle" font-family="ui-monospace,SFMono-Regular,Menlo,monospace" font-size="11.5">session next ×3</text>
146
+ </g>
147
+ <g id="report"><rect x="1421" y="137" width="158" height="66" rx="8" fill="#fff8c5" stroke="#bf8700" stroke-width="1.5"/>
148
+ <text x="1500" y="158.5" text-anchor="middle" font-weight="600">One line per project</text>
149
+ <text x="1500" y="174.5" text-anchor="middle">delivered · in progress</text>
150
+ <text x="1500" y="190.5" text-anchor="middle">· blocked (and why)</text>
151
+ </g>
152
+ <polyline points="240,337 240,203" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
153
+ <text x="248" y="236" text-anchor="start" font-size="11" fill="#57606a" class="lbl">proposals</text>
154
+ <polyline points="319,170 420,170 420,337" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
155
+ <text x="414" y="164" text-anchor="end" font-size="11" fill="#57606a" class="lbl">choice</text>
156
+ <polyline points="499,683 521,683" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
157
+ <polyline points="679,683 701,683" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
158
+ <polyline points="859,683 881,683" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
159
+ <polyline points="960,650 960,632 820,632 820,650" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
160
+ <text x="968" y="626" text-anchor="start" font-size="11" fill="#57606a" class="lbl">then review again</text>
161
+ <polyline points="870,683 870,430 780,430 780,403" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
162
+ <text x="876" y="446" text-anchor="start" font-size="11" fill="#57606a" class="lbl">wave ends</text>
163
+ <polyline points="510,683 510,430 600,430 600,403" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
164
+ <text x="516" y="646" text-anchor="start" font-size="11" fill="#57606a" class="lbl">journal</text>
165
+ <polyline points="630,337 630,203" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
166
+ <text x="636" y="236" text-anchor="start" font-size="11" fill="#57606a" class="lbl">question</text>
167
+ <polyline points="570,203 570,337" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
168
+ <text x="564" y="236" text-anchor="end" font-size="11" class="lbl" fill="#57606a">--resume --answer</text>
169
+ <polyline points="859,370 881,370" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
170
+ <polyline points="960,203 960,337" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
171
+ <text x="968" y="236" text-anchor="start" font-size="11" fill="#57606a" class="lbl">on the human's verdict,</text>
172
+ <text x="968" y="251" text-anchor="start" font-size="11" fill="#57606a" class="lbl">or the lead's (lead.ux: lead)</text>
173
+ <polyline points="1039,370 1061,370" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
174
+ <polyline points="1140,403 1140,650" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
175
+ <polyline points="1320,403 1320,650" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
176
+ <text x="1326" y="440" text-anchor="start" font-size="11" fill="#57606a" class="lbl">yes: chain</text>
177
+ <polyline points="1399,370 1421,370" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
178
+ <text x="1410" y="329" text-anchor="middle" font-size="11" fill="#57606a" class="lbl">≥ 60 %: close</text>
179
+ <polyline points="1500,337 1500,203" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
180
+ <polyline points="1320,716 1320,746 420,746 420,716" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
181
+ <text x="870" y="740" text-anchor="middle" font-size="11" fill="#57606a" class="lbl">next wave: back to step 2, the limits still apply</text>
182
+ <rect x="170" y="760" width="22" height="14" rx="3" fill="none" stroke="#57606a" stroke-dasharray="5 3"/>
183
+ <text x="200" y="771" font-size="11.5" fill="#57606a">conditional step</text>
184
+ <text x="340" y="771" font-size="11.5" fill="#57606a">The lead never commits where a wave runs, and never delivers two projects at once. At most as many sessions or subagents as the cap the human sets (CADENCE_MAX_SESSIONS, 2 by default).</text>
185
+ <polyline points="420,403 420,440 240,440 240,508" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
186
+ <polyline points="319,549 330,549 330,513 341,513" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
187
+ <polyline points="330,549 330,585 341,585" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
188
+ <polyline points="499,513 521,513" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
189
+ <polyline points="679,513 701,513" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
190
+ <polyline points="499,585 521,585" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
191
+ <polyline points="679,585 701,585" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
192
+ <polyline points="240,590 240,683 341,683" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
193
+ <polyline points="780,618 780,634 420,634 420,650" fill="none" stroke="#57606a" stroke-width="1.6" marker-end="url(#arr)"/>
194
+ <text x="232" y="640" text-anchor="end" font-size="11" fill="#57606a" class="lbl">other lots</text>
195
+ <text x="232" y="655" text-anchor="end" font-size="11" fill="#57606a" class="lbl">go straight on</text>
196
+ <text x="890" y="508" text-anchor="start" font-size="11" fill="#57606a" class="lbl">lots with screen: page</text>
197
+ <text x="890" y="523" text-anchor="start" font-size="11" fill="#57606a" class="lbl">spec, mockup, accept</text>
198
+ <text x="890" y="568" text-anchor="start" font-size="11" fill="#57606a" class="lbl">lots with spec: true</text>
199
+ <text x="890" y="583" text-anchor="start" font-size="11" fill="#57606a" class="lbl">spec, sheet review, accept</text>
200
+ </svg>
package/docs/lead.md ADDED
@@ -0,0 +1,147 @@
1
+ # The lead workflow
2
+
3
+ The `lead` skill pilots several projects from a parent folder. Its session stays small: it reads
4
+ summaries, decides with the human, and leaves the work to fresh short sessions run by a program
5
+ (`cadence orchestrate`). This page draws who does what, in three lanes: the **human**, the
6
+ **lead session**, and the **`orchestrate` program with its agents**.
7
+
8
+ <picture>
9
+ <source media="(prefers-color-scheme: dark)" srcset="lead-workflow-dark.svg">
10
+ <img alt="The lead workflow in three lanes (human, lead session, orchestrate program and agents), from the tour of the projects to the close of the session" src="lead-workflow-light.svg">
11
+ </picture>
12
+
13
+ Dashed boxes are conditional steps: the precheck runs only for a lot without a commit yet (unless `orchestrate.precheck: false`), and the spec, sheet review and accept steps run only for a `screen: page` lot or a `spec: true` lot. The skill itself is `skills/lead/SKILL.md`; this page is its
14
+ picture, not its source.
15
+
16
+ ## The steps
17
+
18
+ 1. **Tour.** The lead runs `cadence lead tour` (a program, no model) and reports one row per project.
19
+ It proposes three items: finish what is in progress, then drift that blocks a delivery, then ready
20
+ quick wins. It stops and waits: the human picks the lots and the order (`--priority`, or the
21
+ `priority:` list of the parent folder's `cadence.yaml`).
22
+ 2. **Wave.** The lead starts `cadence orchestrate <project>:<lot> … --wave <id>` in the background.
23
+ For each lot the program runs, in fresh sessions and in this order: `precheck → spec → maquette →
24
+ accept → implement → review → ux`. The **precheck** applies to any lot without a commit yet (unless
25
+ `orchestrate.precheck: false`). The spec steps exist only for a lot that declares
26
+ a `screen:` of `page` (a visible lot that creates or changes a whole screen; `screen: component` and `screen: journey`
27
+ lots take the ordinary path, straight to the implementation, unless they already have a sheet) or `spec: true` (a lot without a screen
28
+ that still has a behaviour to pin down: `precheck → spec → fiche → accept → implement → review`);
29
+ spec, sheet review and accept apply to `screen: page` and to `spec: true` alike; the other lots go
30
+ straight from the precheck (when it applies) to the implementation:
31
+ - **spec**: the `spec-writer` agent draws a static mockup to the project's own style and writes the
32
+ screen sheet (`fiche.yaml`: fields, states, numbered rules), rendered at 1440 and 390 px;
33
+ - **fiche** (a lot with a back-end part: `spec: true`, or a screen lot whose sheet has a `sujet` block):
34
+ the `code-reviewer` agent in sheet mode reviews the back-end sheet (two passes at most, then the lot
35
+ is handed back) unless `orchestrate.fiche: false`; a mixed lot has both reviews, and their findings
36
+ go together to a single second `spec` pass. A lot without a screen has no News entry: the
37
+ hypotheses of its final sheet become one note of the lot each, and the end-of-wave table lists them
38
+ as `hypothèse de la fiche : …` — the lead relays them to the human;
39
+ - **maquette**: the `ux-reviewer` agent reviews the mockup (two passes at most, then the lot is handed
40
+ back) unless `orchestrate.maquette: false`;
41
+ - **accept**: a separate session writes the acceptance tests from the sheet, committed red and locked,
42
+ when the project declares `orchestrate.accept`; without it the step is skipped with a warning;
43
+ - the implementation (test first, commits citing the lot) makes them green without touching them;
44
+ - a UX pass if the lot is `visible` and the project says how to see its app (`orchestrate.ux`); for a
45
+ lot with a sheet it is a conformity pass against the mockup;
46
+ - the code review (Opus; Sonnet for a lot of 0.25 day or less), which also follows each rule of the
47
+ sheet to its test;
48
+ - a correction in a new session if the review is not compliant (two passes at most, a third when the review
49
+ converges — blocking + major findings down and only one left —, each followed by a review).
50
+
51
+ The program records `raf review` itself once the review is compliant.
52
+ 3. **Relay.** The lead follows the wave's journal (`tail -n +1 -F .cadence/runs/<id>/journal.log`, one
53
+ line per transition) and tells the human each line in one sentence, with no polling loop. A
54
+ question from a session comes back to the human at once; the answer goes in with
55
+ `cadence orchestrate --resume --answer <project>:<lot> "…"`. The lead never answers in the
56
+ human's place. `--drop` and `--stop-after-current` steer a wave that is running.
57
+ 4. **Review.** The final table of the wave lists the lots ready, handed back, and the line
58
+ « livrable jusqu'à <sha> » for a ready lot stacked under a handed-back one. Minor findings come back in
59
+ the table: one becomes a lot of its own only if it describes an observable bug.
60
+ 5. **Re-check.** The lead verifies itself, one project at a time: `git log`, the test suite and the
61
+ build run by the lead, `raf check` clean. A `visible` lot waits for the human to look at the
62
+ UX reviewer's captures: the lead records `raf ux` on the human's verdict, never on its own — unless the parent folder's `cadence.yaml` says `lead.ux: lead`: then the lead forms the verdict from the reviewer's report and its own look at the captures, and asks the human only at the slightest doubt. Then
63
+ `raf done`.
64
+ 6. **Delivery.** Push (for a « livrable jusqu'à <sha> », that sha alone, never HEAD), then
65
+ `cadence deliver`. After a green delivery that changes what a page shows or what it is served, the
66
+ `qa-reviewer` agent walks the delivered pages in a real browser, reads only, and brings its blocking
67
+ findings to the human. It is not a gate: a finding becomes a new lot.
68
+ 7. **Threshold and chaining.** Before every new wave the lead reads `cadence session context`. Under
69
+ **60 %** it chains: `cadence orchestrate --continue` draws the next ready lot of the plan, in the
70
+ declared priority, without asking the human « next? ». From 60 % upward, or when the figure cannot
71
+ be read (exit code 2: the band is not loaded, or its figure is stale), it starts nothing. A lot
72
+ that was not handed back ready is reported, not chained over; a question or a UX reservation
73
+ pending on a lot never stops the chain on the other lots.
74
+ 8. **Close.** `session-close` in each project touched, filtered memory, three lines for next time
75
+ with `cadence session next` (the wave that was about to start comes first), then one line per project
76
+ to the human: delivered, in progress, blocked (and why).
77
+
78
+ ## Permanent rules
79
+
80
+ | Rule | Why |
81
+ |---|---|
82
+ | At most **as many subagents as the session cap** running at once (2 by default; the human sets it with `CADENCE_MAX_SESSIONS`), orchestrate sessions included | `cadence orchestrate --status` and `cadence lead tour` print `créneaux libres : N sur M`, M being the configured cap; the lead never raises `--max-sessions` or `CADENCE_MAX_SESSIONS` itself |
83
+ | Never two sessions in the same repository at the same time; the lead does not commit where a wave runs | a wave's lock refuses `cadence deliver` while a lot still works there |
84
+ | A locked acceptance test that contradicts the sheet is corrected by the lead with `cadence spec reseal <lot> <test> --reason "…"` (lot in progress, outside a wave; an amended sheet is accepted once committed, every commit that touched it citing the lot, L217, never put it back to the red state; a delivered lot with an unstable test: add `--porteur <lot in progress>`, L212), then `--resume --answer` for a lot in question, or a new `cadence orchestrate <project>:<lot>` for a lot handed back (`--resume` skips it) | never by a session, never by editing `acceptation.json` |
85
+ | Deliveries and the `raf ux` / `raf review` verdicts belong to the lead, one project at a time | never to a subagent, never two deliveries in parallel |
86
+ | The UX verdict is the human's unless `lead.ux: lead` (parent `cadence.yaml`, default `human`) | then the lead decides from the report and the captures, and brings any doubt to the human |
87
+ | A session cannot ask the human anything | it stops and reports; the lead brings the question back |
88
+ | Never push or deliver HEAD above a handed-back lot | HEAD holds code that was not reviewed |
89
+ | A plan kept by another tool is read-only for `raf` | its own commands record the lot's state |
90
+
91
+ ## Exit codes
92
+
93
+ `cadence orchestrate`:
94
+
95
+ | Code | Meaning |
96
+ |---|---|
97
+ | `0` | every lot is ready |
98
+ | `1` | some lots were handed back to the lead |
99
+ | `2` | refused before acting (a precondition failed) |
100
+ | `3` | wave suspended (budget or usage limit); `--resume --budget …` continues |
101
+
102
+ `cadence session context` exits `2` when it cannot prove the figure (no band, several sessions in
103
+ the folder without `$CLAUDE_CODE_SESSION_ID`, figure older than two minutes): the lead then treats it
104
+ as being at the threshold.
105
+
106
+ The mechanics around it (the life of a lot in the plan, a lot inside a wave, putting cadence in service, the budgets) are drawn in
107
+ [fonctionnement.md](fonctionnement.md). See also the [lead tour](lead.md#lead-tour) section below and the [orchestrate](orchestrate.md#orchestrate)
108
+ page.
109
+
110
+ ## lead tour
111
+
112
+ `cadence lead tour [folder] [--idle 3] [--depth n] [--json]` is the lead's morning table, with no model in
113
+ the loop. From a parent folder (default: the current one) it takes every direct sub-folder that
114
+ holds `docs/plan/raf.yaml`, or a `cadence.yaml` with a `plan:` key (a plan kept by another tool
115
+ included), and for each one reads the same facts as `cadence session start` — in-process, no
116
+ sub-process, no call to `claude` — then prints **one line per project**:
117
+
118
+ ```
119
+ alpha · en cours L1 (silencieux 4j) · dérive 1 (✗ L2 a 1 commit(s) mais est encore todo) · notes : finir L1 puis livrer · prochain L3 Typo · dépôt non commité, non poussé
120
+ beta · en cours rien · dérive aucune · notes : aucune · prochain T2 Second · dépôt propre
121
+ ```
122
+
123
+ | Column | Content |
124
+ |---|---|
125
+ | `en cours` | ids of the lots in progress; `(aucune activité)` when it has none at all, `(silencieux Nj)` when the lot's last activity (commit, note or start) is more than `--idle` days old (default 3) |
126
+ | `dérive` | the gaps `raf check` reports (a lot whose commits leave a document behind, [`docs.sync`](news.md#documentation-that-follows-the-code), included), counted and the first two shown |
127
+ | `notes` | the notes left by the last `session close`, joined with ` / ` and cut at 120 characters |
128
+ | `prochain` | the first ready lot (quick wins first) — id and title cut at 60 characters; a lot whose [`gate`](raf.md#plan-file) is not met is not ready |
129
+ | `attend` | only when a lot waits on its `gate`: `attend L190` |
130
+ | `dépôt` | `non commité` (modified or untracked files), `non poussé` (commits ahead of the upstream), `livraison en cours` (live delivery lock); `propre` otherwise |
131
+
132
+ When an orchestrated wave is live, one more line closes the tour (not part of `--json`): `vagues en cours : 1 · sessions en cours : 0 · créneaux libres : 1 sur 2` — the lead reads the free slots there instead of computing them (L141). The `sur M` is the cap the human set (`CADENCE_MAX_SESSIONS`, 2 by default), not a fixed 2 (L208); an invalid value falls back to 2 in this display.
133
+
134
+ `--json` prints the same content as an array of objects (`project`, `doing`, `drift`, `notes`, `waiting` (only when a lot waits on its `gate`),
135
+ `next`, `repo`, and `error` when the project could not be read), plus `progress` — `{ done, doing, todo, added7 }`,
136
+ the lots done / in progress / to do (dropped and recurring lots left out) and those created in the last 7 days (L149), which
137
+ [`cadence-hud`](../plugins/cadence-hud/README.md) draws as one progress bar per project. Projects come in the order of the
138
+ `priority:` key of the folder's `cadence.yaml` (the one `orchestrate --continue` reads), the others after, alphabetically; an unreadable `cadence.yaml` or
139
+ a `priority:` that is not a list of names (`priority: ol`, `priority: []`) keeps the alphabetical order and adds a first row `cadence.yaml · ✗ erreur : <cause>` (`project: "cadence.yaml"` with `error` in `--json`).
140
+ Sub-projects are looked for one level down by default. `--depth n` goes `n` levels down (same meaning as in `cadence session start --all --depth n`:
141
+ a folder that is a project is not entered; an integer ≥ 1, otherwise refused), and the `depth:` key of the folder's `cadence.yaml`, next to `priority:`, sets it once for all
142
+ (`depth: 2`); `--depth` wins over the key, and a `depth:` that is not an integer ≥ 1 adds the same first row `cadence.yaml · ✗ erreur : …` and leaves one level read.
143
+ `cadence-hud` asks the tour from the folder of the session, so it follows the key with no change. A project is named by its folder's name; one found below the first level is named by its path from the folder (`groupe/gamma`), unique and ready for `cadence orchestrate groupe/gamma:L1` run from there, while `priority:` and the alphabetical order read the folder's own name.
144
+ "Created in the last 7 days" means today and the six days before. When the folder has no sub-project but is itself a project, the tour is that project's single line
145
+ (this is what `cadence-hud` asks from a session opened inside a project). The tour is read-only: it changes
146
+ no plan. It exits 0 even when a project is in error — that project's line reads
147
+ `beta · ✗ erreur : <cause>`. The `lead` skill runs it instead of one subagent per project.
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.