@sylad/cadence 1.38.1 → 1.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +3 -3
- package/dist/cli.js +4 -2
- package/dist/config-set.js +2 -0
- package/dist/cost.js +40 -0
- package/dist/memory-index.js +113 -0
- package/dist/orchestrate/ajout.js +87 -2
- package/dist/orchestrate/command.js +44 -49
- package/dist/orchestrate/continue.js +33 -0
- package/dist/orchestrate/cout.js +46 -0
- package/dist/orchestrate/cycle.js +10 -7
- package/dist/orchestrate/deja-traitee.js +76 -0
- package/dist/orchestrate/pool.js +1 -1
- package/dist/orchestrate/table.js +35 -14
- package/dist/perf.js +2 -15
- package/dist/release.js +18 -3
- package/dist/session.js +8 -0
- package/docs/concepts-livraison-dark.svg +32 -0
- package/docs/concepts-livraison-light.svg +32 -0
- package/docs/concepts-lot-dark.svg +52 -0
- package/docs/concepts-lot-light.svg +52 -0
- package/docs/concepts-vague-dark.svg +39 -0
- package/docs/concepts-vague-light.svg +39 -0
- package/docs/concepts-worktrees-dark.svg +45 -0
- package/docs/concepts-worktrees-light.svg +45 -0
- package/docs/concepts.md +159 -0
- package/docs/fonctionnement.md +2 -0
- package/docs/lead.md +3 -1
- package/docs/orchestrate.md +22 -6
- package/docs/overview.md +1 -1
- package/docs/perf.md +2 -0
- package/docs/releasing.md +4 -0
- package/docs/session.md +32 -0
- package/docs/whats-new.md +6 -0
- package/package.json +10 -1
- package/skills/lead/SKILL.md +6 -0
- package/skills/session-close/SKILL.md +6 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1100 300" width="1100" height="300" role="img" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif" font-size="13" fill="#1f2328">
|
|
2
|
+
<title>Journey of a lot</title>
|
|
3
|
+
<desc>A lot goes through spec, code, review, correction when the review is not compliant, UX if the lot is visible, then ready; below each step, who does it.</desc>
|
|
4
|
+
<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></defs>
|
|
5
|
+
<rect width="1100" height="300" fill="#ffffff"/>
|
|
6
|
+
<text x="20" y="26" text-anchor="start" font-size="11.5" font-weight="600" fill="#57606a">STEP</text>
|
|
7
|
+
<text x="20" y="168" text-anchor="start" font-size="11.5" font-weight="600" fill="#57606a">WHO</text>
|
|
8
|
+
<rect x="20" y="40" width="160" height="60" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5" stroke-dasharray="6 4"/>
|
|
9
|
+
<text x="100" y="66" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">spec</text>
|
|
10
|
+
<text x="100" y="83" text-anchor="middle" font-size="11.5" fill="#57606a">if screen or spec: true</text>
|
|
11
|
+
<rect x="200" y="40" width="160" height="60" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5"/>
|
|
12
|
+
<text x="280" y="66" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">code</text>
|
|
13
|
+
<text x="280" y="83" text-anchor="middle" font-size="11.5" fill="#57606a">test first</text>
|
|
14
|
+
<rect x="380" y="40" width="160" height="60" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5"/>
|
|
15
|
+
<text x="460" y="66" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">review</text>
|
|
16
|
+
<text x="460" y="83" text-anchor="middle" font-size="11.5" fill="#57606a">code</text>
|
|
17
|
+
<rect x="560" y="40" width="160" height="60" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5" stroke-dasharray="6 4"/>
|
|
18
|
+
<text x="640" y="66" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">correction</text>
|
|
19
|
+
<text x="640" y="83" text-anchor="middle" font-size="11.5" fill="#57606a">if not compliant</text>
|
|
20
|
+
<rect x="740" y="40" width="160" height="60" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5" stroke-dasharray="6 4"/>
|
|
21
|
+
<text x="820" y="66" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">UX</text>
|
|
22
|
+
<text x="820" y="83" text-anchor="middle" font-size="11.5" fill="#57606a">if visible</text>
|
|
23
|
+
<rect x="920" y="40" width="160" height="60" rx="6" fill="#ddf4ff" stroke="#0969da" stroke-width="2"/>
|
|
24
|
+
<text x="1000" y="66" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">ready</text>
|
|
25
|
+
<text x="1000" y="83" text-anchor="middle" font-size="11.5" fill="#57606a">integrated (worktree mode)</text>
|
|
26
|
+
<polyline points="180,70 198,70" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
27
|
+
<polyline points="360,70 378,70" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
28
|
+
<polyline points="540,70 558,70" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
29
|
+
<polyline points="720,70 738,70" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
30
|
+
<polyline points="900,70 918,70" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
31
|
+
<polyline points="640,40 640,22 460,22 460,38" fill="none" stroke="#57606a" stroke-width="1.5" stroke-dasharray="5 3" marker-end="url(#arr)"/>
|
|
32
|
+
<text x="550" y="16" text-anchor="middle" font-size="11.5" fill="#57606a">back to the review after each correction</text>
|
|
33
|
+
<rect x="20" y="180" width="160" height="56" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1"/>
|
|
34
|
+
<text x="100" y="204" text-anchor="middle" font-size="12.5" font-weight="600" fill="#1f2328">spec-writer</text>
|
|
35
|
+
<text x="100" y="222" text-anchor="middle" font-size="11.5" fill="#57606a">then reviewer</text>
|
|
36
|
+
<rect x="200" y="180" width="160" height="56" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1"/>
|
|
37
|
+
<text x="280" y="204" text-anchor="middle" font-size="12.5" font-weight="600" fill="#1f2328">fresh session</text>
|
|
38
|
+
<text x="280" y="222" text-anchor="middle" font-size="11.5" fill="#57606a">of the program</text>
|
|
39
|
+
<rect x="380" y="180" width="160" height="56" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1"/>
|
|
40
|
+
<text x="460" y="204" text-anchor="middle" font-size="12.5" font-weight="600" fill="#1f2328">code-reviewer</text>
|
|
41
|
+
<text x="460" y="222" text-anchor="middle" font-size="11.5" fill="#57606a">agent</text>
|
|
42
|
+
<rect x="560" y="180" width="160" height="56" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1"/>
|
|
43
|
+
<text x="640" y="204" text-anchor="middle" font-size="12.5" font-weight="600" fill="#1f2328">fresh session</text>
|
|
44
|
+
<text x="640" y="222" text-anchor="middle" font-size="11.5" fill="#57606a">2 passes, 3 if it converges</text>
|
|
45
|
+
<rect x="740" y="180" width="160" height="56" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1"/>
|
|
46
|
+
<text x="820" y="204" text-anchor="middle" font-size="12.5" font-weight="600" fill="#1f2328">ux-reviewer</text>
|
|
47
|
+
<text x="820" y="222" text-anchor="middle" font-size="11.5" fill="#57606a">then the human</text>
|
|
48
|
+
<rect x="920" y="180" width="160" height="56" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1"/>
|
|
49
|
+
<text x="1000" y="204" text-anchor="middle" font-size="12.5" font-weight="600" fill="#1f2328">the lead</text>
|
|
50
|
+
<text x="1000" y="222" text-anchor="middle" font-size="11.5" fill="#57606a">re-checks, raf done</text>
|
|
51
|
+
<text x="550" y="270" text-anchor="middle" font-size="11.5" fill="#57606a">Dashed: a conditional step. The program chains the sessions; the verdicts of the review and of the UX pass are recorded in the plan.</text>
|
|
52
|
+
</svg>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1100 390" width="1100" height="390" role="img" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif" font-size="13" fill="#e6edf3">
|
|
2
|
+
<title>Wave and slots</title>
|
|
3
|
+
<desc>A wave plays its lots in fresh sessions under a cap of slots; a lot waits in the queue until a slot is free, and a session the lead started by hand is held and takes a slot.</desc>
|
|
4
|
+
<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="#8b949e"/></marker></defs>
|
|
5
|
+
<rect width="1100" height="390" fill="#0d1117"/>
|
|
6
|
+
<rect x="20" y="44" width="170" height="240" rx="6" fill="#0d1117" stroke="#8b949e" stroke-width="1.5"/>
|
|
7
|
+
<text x="105" y="160" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">Queue</text>
|
|
8
|
+
<text x="105" y="177" text-anchor="middle" font-size="11.5" fill="#8b949e">lots waiting, in the</text>
|
|
9
|
+
<text x="105" y="190" text-anchor="middle" font-size="11.5" fill="#8b949e">priority order</text>
|
|
10
|
+
<text x="105" y="222" text-anchor="middle" font-size="11.5" fill="#8b949e">a lot that depends on</text>
|
|
11
|
+
<text x="105" y="238" text-anchor="middle" font-size="11.5" fill="#8b949e">another waits for it</text>
|
|
12
|
+
<text x="230" y="26" text-anchor="start" font-size="11.5" font-weight="600" fill="#e6edf3">SLOTS: as many sessions at once as the cap (CADENCE_MAX_SESSIONS)</text>
|
|
13
|
+
<rect x="270" y="44" width="380" height="52" rx="6" fill="#0d1117" stroke="#8b949e" stroke-width="1.5"/>
|
|
14
|
+
<text x="460" y="66" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">slot 1 · L1</text>
|
|
15
|
+
<text x="460" y="83" text-anchor="middle" font-size="11.5" fill="#8b949e">implementation: a session running</text>
|
|
16
|
+
<polyline points="190,164 268,70" fill="none" stroke="#8b949e" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
17
|
+
<rect x="270" y="108" width="380" height="52" rx="6" fill="#0d1117" stroke="#8b949e" stroke-width="1.5"/>
|
|
18
|
+
<text x="460" y="130" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">slot 2 · L2</text>
|
|
19
|
+
<text x="460" y="147" text-anchor="middle" font-size="11.5" fill="#8b949e">review: a session running</text>
|
|
20
|
+
<polyline points="190,164 268,134" fill="none" stroke="#8b949e" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
21
|
+
<rect x="270" y="172" width="380" height="52" rx="6" fill="#0c2d6b" stroke="#58a6ff" stroke-width="2" stroke-dasharray="6 4"/>
|
|
22
|
+
<text x="460" y="194" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">slot 3 · hold</text>
|
|
23
|
+
<text x="460" y="211" text-anchor="middle" font-size="11.5" fill="#8b949e">a fix started by hand by the lead</text>
|
|
24
|
+
<polyline points="190,164 268,198" fill="none" stroke="#8b949e" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
25
|
+
<rect x="270" y="236" width="380" height="52" rx="6" fill="#0d1117" stroke="#8b949e" stroke-width="1.5" stroke-dasharray="6 4"/>
|
|
26
|
+
<text x="460" y="258" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">slot 4 · free</text>
|
|
27
|
+
<text x="460" y="275" text-anchor="middle" font-size="11.5" fill="#8b949e">with --continue, the next ready lot is drawn</text>
|
|
28
|
+
<polyline points="190,164 268,262" fill="none" stroke="#8b949e" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
29
|
+
<rect x="740" y="44" width="200" height="80" rx="6" fill="#0d1117" stroke="#8b949e" stroke-width="1.5"/>
|
|
30
|
+
<text x="840" y="80" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">Table of the wave</text>
|
|
31
|
+
<text x="840" y="97" text-anchor="middle" font-size="11.5" fill="#8b949e">ready · handed back · questions</text>
|
|
32
|
+
<polyline points="650,70 738,84" fill="none" stroke="#8b949e" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
33
|
+
<rect x="740" y="170" width="200" height="80" rx="6" fill="#0c2d6b" stroke="#58a6ff" stroke-width="2"/>
|
|
34
|
+
<text x="840" y="206" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">The lead</text>
|
|
35
|
+
<text x="840" y="223" text-anchor="middle" font-size="11.5" fill="#8b949e">relays, re-checks, delivers</text>
|
|
36
|
+
<polyline points="840,124 840,168" fill="none" stroke="#8b949e" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
37
|
+
<text x="550" y="330" text-anchor="middle" font-size="11.5" fill="#8b949e">A hold (cadence lead hold) counts against the cap like a running session: the wave waits for it instead of overtaking it.</text>
|
|
38
|
+
<text x="550" y="352" text-anchor="middle" font-size="11.5" fill="#8b949e">A freed slot goes to the wave queue; with --continue it also draws the next ready lot of the plan.</text>
|
|
39
|
+
</svg>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1100 390" width="1100" height="390" role="img" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif" font-size="13" fill="#1f2328">
|
|
2
|
+
<title>Wave and slots</title>
|
|
3
|
+
<desc>A wave plays its lots in fresh sessions under a cap of slots; a lot waits in the queue until a slot is free, and a session the lead started by hand is held and takes a slot.</desc>
|
|
4
|
+
<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></defs>
|
|
5
|
+
<rect width="1100" height="390" fill="#ffffff"/>
|
|
6
|
+
<rect x="20" y="44" width="170" height="240" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5"/>
|
|
7
|
+
<text x="105" y="160" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">Queue</text>
|
|
8
|
+
<text x="105" y="177" text-anchor="middle" font-size="11.5" fill="#57606a">lots waiting, in the</text>
|
|
9
|
+
<text x="105" y="190" text-anchor="middle" font-size="11.5" fill="#57606a">priority order</text>
|
|
10
|
+
<text x="105" y="222" text-anchor="middle" font-size="11.5" fill="#57606a">a lot that depends on</text>
|
|
11
|
+
<text x="105" y="238" text-anchor="middle" font-size="11.5" fill="#57606a">another waits for it</text>
|
|
12
|
+
<text x="230" y="26" text-anchor="start" font-size="11.5" font-weight="600" fill="#1f2328">SLOTS: as many sessions at once as the cap (CADENCE_MAX_SESSIONS)</text>
|
|
13
|
+
<rect x="270" y="44" width="380" height="52" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5"/>
|
|
14
|
+
<text x="460" y="66" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">slot 1 · L1</text>
|
|
15
|
+
<text x="460" y="83" text-anchor="middle" font-size="11.5" fill="#57606a">implementation: a session running</text>
|
|
16
|
+
<polyline points="190,164 268,70" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
17
|
+
<rect x="270" y="108" width="380" height="52" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5"/>
|
|
18
|
+
<text x="460" y="130" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">slot 2 · L2</text>
|
|
19
|
+
<text x="460" y="147" text-anchor="middle" font-size="11.5" fill="#57606a">review: a session running</text>
|
|
20
|
+
<polyline points="190,164 268,134" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
21
|
+
<rect x="270" y="172" width="380" height="52" rx="6" fill="#ddf4ff" stroke="#0969da" stroke-width="2" stroke-dasharray="6 4"/>
|
|
22
|
+
<text x="460" y="194" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">slot 3 · hold</text>
|
|
23
|
+
<text x="460" y="211" text-anchor="middle" font-size="11.5" fill="#57606a">a fix started by hand by the lead</text>
|
|
24
|
+
<polyline points="190,164 268,198" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
25
|
+
<rect x="270" y="236" width="380" height="52" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5" stroke-dasharray="6 4"/>
|
|
26
|
+
<text x="460" y="258" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">slot 4 · free</text>
|
|
27
|
+
<text x="460" y="275" text-anchor="middle" font-size="11.5" fill="#57606a">with --continue, the next ready lot is drawn</text>
|
|
28
|
+
<polyline points="190,164 268,262" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
29
|
+
<rect x="740" y="44" width="200" height="80" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5"/>
|
|
30
|
+
<text x="840" y="80" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">Table of the wave</text>
|
|
31
|
+
<text x="840" y="97" text-anchor="middle" font-size="11.5" fill="#57606a">ready · handed back · questions</text>
|
|
32
|
+
<polyline points="650,70 738,84" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
33
|
+
<rect x="740" y="170" width="200" height="80" rx="6" fill="#ddf4ff" stroke="#0969da" stroke-width="2"/>
|
|
34
|
+
<text x="840" y="206" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">The lead</text>
|
|
35
|
+
<text x="840" y="223" text-anchor="middle" font-size="11.5" fill="#57606a">relays, re-checks, delivers</text>
|
|
36
|
+
<polyline points="840,124 840,168" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
37
|
+
<text x="550" y="330" text-anchor="middle" font-size="11.5" fill="#57606a">A hold (cadence lead hold) counts against the cap like a running session: the wave waits for it instead of overtaking it.</text>
|
|
38
|
+
<text x="550" y="352" text-anchor="middle" font-size="11.5" fill="#57606a">A freed slot goes to the wave queue; with --continue it also draws the next ready lot of the plan.</text>
|
|
39
|
+
</svg>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1100 330" width="1100" height="330" role="img" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif" font-size="13" fill="#e6edf3">
|
|
2
|
+
<title>Worktrees to main</title>
|
|
3
|
+
<desc>Each lot works on its own branch in its own worktree; at the end of its cycle it is rebased onto the tip of main, its checks are replayed, and it is fast-forwarded into main one lot at a time under a lock.</desc>
|
|
4
|
+
<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="#8b949e"/></marker></defs>
|
|
5
|
+
<rect width="1100" height="330" fill="#0d1117"/>
|
|
6
|
+
<rect x="20" y="30" width="200" height="56" rx="6" fill="#0d1117" stroke="#8b949e" stroke-width="1.5"/>
|
|
7
|
+
<text x="120" y="54" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">worktree L1</text>
|
|
8
|
+
<text x="120" y="71" text-anchor="middle" font-size="11.5" fill="#8b949e">cadence/<wave>/<project>--L1</text>
|
|
9
|
+
<rect x="280" y="30" width="180" height="56" rx="6" fill="#0d1117" stroke="#8b949e" stroke-width="1.5"/>
|
|
10
|
+
<text x="370" y="54" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">cycle</text>
|
|
11
|
+
<text x="370" y="71" text-anchor="middle" font-size="11.5" fill="#8b949e">code · review · UX</text>
|
|
12
|
+
<polyline points="220,58 278,58" fill="none" stroke="#8b949e" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
13
|
+
<polyline points="460,58 518,58" fill="none" stroke="#8b949e" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
14
|
+
<rect x="20" y="110" width="200" height="56" rx="6" fill="#0d1117" stroke="#8b949e" stroke-width="1.5"/>
|
|
15
|
+
<text x="120" y="134" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">worktree L2</text>
|
|
16
|
+
<text x="120" y="151" text-anchor="middle" font-size="11.5" fill="#8b949e">cadence/<wave>/<project>--L2</text>
|
|
17
|
+
<rect x="280" y="110" width="180" height="56" rx="6" fill="#0d1117" stroke="#8b949e" stroke-width="1.5"/>
|
|
18
|
+
<text x="370" y="134" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">cycle</text>
|
|
19
|
+
<text x="370" y="151" text-anchor="middle" font-size="11.5" fill="#8b949e">code · review · UX</text>
|
|
20
|
+
<polyline points="220,138 278,138" fill="none" stroke="#8b949e" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
21
|
+
<polyline points="460,138 518,138" fill="none" stroke="#8b949e" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
22
|
+
<rect x="20" y="190" width="200" height="56" rx="6" fill="#0d1117" stroke="#8b949e" stroke-width="1.5"/>
|
|
23
|
+
<text x="120" y="214" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">worktree L3</text>
|
|
24
|
+
<text x="120" y="231" text-anchor="middle" font-size="11.5" fill="#8b949e">cadence/<wave>/<project>--L3</text>
|
|
25
|
+
<rect x="280" y="190" width="180" height="56" rx="6" fill="#0d1117" stroke="#8b949e" stroke-width="1.5"/>
|
|
26
|
+
<text x="370" y="214" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">cycle</text>
|
|
27
|
+
<text x="370" y="231" text-anchor="middle" font-size="11.5" fill="#8b949e">code · review · UX</text>
|
|
28
|
+
<polyline points="220,218 278,218" fill="none" stroke="#8b949e" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
29
|
+
<polyline points="460,218 518,218" fill="none" stroke="#8b949e" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
30
|
+
<rect x="520" y="30" width="240" height="216" rx="6" fill="#0d1117" stroke="#8b949e" stroke-width="1.5"/>
|
|
31
|
+
<text x="640" y="142" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3"></text>
|
|
32
|
+
<text x="640" y="56" text-anchor="middle" font-size="13.5" font-weight="600" fill="#e6edf3">Integration</text>
|
|
33
|
+
<text x="640" y="120" text-anchor="middle" font-size="11.5" fill="#e6edf3">one lot at a time (lock)</text>
|
|
34
|
+
<text x="640" y="142" text-anchor="middle" font-size="11.5" fill="#8b949e">1. rebase onto the tip of main</text>
|
|
35
|
+
<text x="640" y="160" text-anchor="middle" font-size="11.5" fill="#8b949e">2. replay the checks</text>
|
|
36
|
+
<text x="640" y="178" text-anchor="middle" font-size="11.5" fill="#8b949e">3. fast-forward main</text>
|
|
37
|
+
<text x="640" y="200" text-anchor="middle" font-size="11.5" fill="#8b949e">main moved? replay, twice at most</text>
|
|
38
|
+
<polyline points="760,138 858,138" fill="none" stroke="#8b949e" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
39
|
+
<rect x="860" y="100" width="220" height="76" rx="6" fill="#0c2d6b" stroke="#58a6ff" stroke-width="2"/>
|
|
40
|
+
<text x="970" y="134" text-anchor="middle" font-weight="600" font-size="13.5" fill="#e6edf3">main</text>
|
|
41
|
+
<text x="970" y="151" text-anchor="middle" font-size="11.5" fill="#8b949e">linear history, then ready</text>
|
|
42
|
+
<text x="970" y="196" text-anchor="middle" font-size="11.5" fill="#8b949e">the plan is written here, by the program</text>
|
|
43
|
+
<text x="550" y="280" text-anchor="middle" font-size="11.5" fill="#8b949e">orchestrate.worktrees: true lets independent lots of one repository play at the same time.</text>
|
|
44
|
+
<text x="550" y="300" text-anchor="middle" font-size="11.5" fill="#8b949e">Without it, lots play one after the other in the repository itself.</text>
|
|
45
|
+
</svg>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1100 330" width="1100" height="330" role="img" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif" font-size="13" fill="#1f2328">
|
|
2
|
+
<title>Worktrees to main</title>
|
|
3
|
+
<desc>Each lot works on its own branch in its own worktree; at the end of its cycle it is rebased onto the tip of main, its checks are replayed, and it is fast-forwarded into main one lot at a time under a lock.</desc>
|
|
4
|
+
<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></defs>
|
|
5
|
+
<rect width="1100" height="330" fill="#ffffff"/>
|
|
6
|
+
<rect x="20" y="30" width="200" height="56" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5"/>
|
|
7
|
+
<text x="120" y="54" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">worktree L1</text>
|
|
8
|
+
<text x="120" y="71" text-anchor="middle" font-size="11.5" fill="#57606a">cadence/<wave>/<project>--L1</text>
|
|
9
|
+
<rect x="280" y="30" width="180" height="56" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5"/>
|
|
10
|
+
<text x="370" y="54" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">cycle</text>
|
|
11
|
+
<text x="370" y="71" text-anchor="middle" font-size="11.5" fill="#57606a">code · review · UX</text>
|
|
12
|
+
<polyline points="220,58 278,58" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
13
|
+
<polyline points="460,58 518,58" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
14
|
+
<rect x="20" y="110" width="200" height="56" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5"/>
|
|
15
|
+
<text x="120" y="134" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">worktree L2</text>
|
|
16
|
+
<text x="120" y="151" text-anchor="middle" font-size="11.5" fill="#57606a">cadence/<wave>/<project>--L2</text>
|
|
17
|
+
<rect x="280" y="110" width="180" height="56" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5"/>
|
|
18
|
+
<text x="370" y="134" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">cycle</text>
|
|
19
|
+
<text x="370" y="151" text-anchor="middle" font-size="11.5" fill="#57606a">code · review · UX</text>
|
|
20
|
+
<polyline points="220,138 278,138" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
21
|
+
<polyline points="460,138 518,138" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
22
|
+
<rect x="20" y="190" width="200" height="56" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5"/>
|
|
23
|
+
<text x="120" y="214" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">worktree L3</text>
|
|
24
|
+
<text x="120" y="231" text-anchor="middle" font-size="11.5" fill="#57606a">cadence/<wave>/<project>--L3</text>
|
|
25
|
+
<rect x="280" y="190" width="180" height="56" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5"/>
|
|
26
|
+
<text x="370" y="214" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">cycle</text>
|
|
27
|
+
<text x="370" y="231" text-anchor="middle" font-size="11.5" fill="#57606a">code · review · UX</text>
|
|
28
|
+
<polyline points="220,218 278,218" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
29
|
+
<polyline points="460,218 518,218" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
30
|
+
<rect x="520" y="30" width="240" height="216" rx="6" fill="#ffffff" stroke="#57606a" stroke-width="1.5"/>
|
|
31
|
+
<text x="640" y="142" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328"></text>
|
|
32
|
+
<text x="640" y="56" text-anchor="middle" font-size="13.5" font-weight="600" fill="#1f2328">Integration</text>
|
|
33
|
+
<text x="640" y="120" text-anchor="middle" font-size="11.5" fill="#1f2328">one lot at a time (lock)</text>
|
|
34
|
+
<text x="640" y="142" text-anchor="middle" font-size="11.5" fill="#57606a">1. rebase onto the tip of main</text>
|
|
35
|
+
<text x="640" y="160" text-anchor="middle" font-size="11.5" fill="#57606a">2. replay the checks</text>
|
|
36
|
+
<text x="640" y="178" text-anchor="middle" font-size="11.5" fill="#57606a">3. fast-forward main</text>
|
|
37
|
+
<text x="640" y="200" text-anchor="middle" font-size="11.5" fill="#57606a">main moved? replay, twice at most</text>
|
|
38
|
+
<polyline points="760,138 858,138" fill="none" stroke="#57606a" stroke-width="1.5" marker-end="url(#arr)"/>
|
|
39
|
+
<rect x="860" y="100" width="220" height="76" rx="6" fill="#ddf4ff" stroke="#0969da" stroke-width="2"/>
|
|
40
|
+
<text x="970" y="134" text-anchor="middle" font-weight="600" font-size="13.5" fill="#1f2328">main</text>
|
|
41
|
+
<text x="970" y="151" text-anchor="middle" font-size="11.5" fill="#57606a">linear history, then ready</text>
|
|
42
|
+
<text x="970" y="196" text-anchor="middle" font-size="11.5" fill="#57606a">the plan is written here, by the program</text>
|
|
43
|
+
<text x="550" y="280" text-anchor="middle" font-size="11.5" fill="#57606a">orchestrate.worktrees: true lets independent lots of one repository play at the same time.</text>
|
|
44
|
+
<text x="550" y="300" text-anchor="middle" font-size="11.5" fill="#57606a">Without it, lots play one after the other in the repository itself.</text>
|
|
45
|
+
</svg>
|
package/docs/concepts.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
[← cadence](../README.md)
|
|
2
|
+
|
|
3
|
+
# The notions of cadence, for a human
|
|
4
|
+
|
|
5
|
+
cadence has become a rich tool, and its vocabulary comes faster than its pages. This one explains each notion in a few sentences,
|
|
6
|
+
**in the order you meet them**, with four figures; the technical detail stays in the pages it links, and the
|
|
7
|
+
[glossary](#glossary) at the end is the one-line version. You do not need to know cadence to read it: the journey of a lot
|
|
8
|
+
([figure 1](#the-steps-of-a-lot)) is the five minutes to keep if you keep only one thing.
|
|
9
|
+
|
|
10
|
+
## Plan and lot
|
|
11
|
+
|
|
12
|
+
The **plan** is a file in your repository (`.cadence/raf.yaml`): the list of what is left to do and what was done.
|
|
13
|
+
Each item is a **lot**: a piece of work small enough to be finished in a day or two, with an identifier (`L12`), a title, an
|
|
14
|
+
estimate and a status (`todo`, `doing`, `done`, or `dropped`). A commit that belongs to a lot cites it in its subject:
|
|
15
|
+
`feat(L12): …`. That link is the whole idea: from any commit you know what it was for, from any lot you know its commits.
|
|
16
|
+
The `raf` command reads and writes the plan; `raf check` lists the commits that cite no lot. Detail: [raf.md](raf.md).
|
|
17
|
+
|
|
18
|
+
## Verdicts
|
|
19
|
+
|
|
20
|
+
A lot is not finished when its code is written, but when two independent readers said so, and the plan keeps their word:
|
|
21
|
+
the **review verdict** (`raf review`) says the code is compliant, the **UX verdict** (`raf ux`) says the screen is
|
|
22
|
+
usable, for a lot that shows one (a `visible` lot). A verdict is recorded by the program (the review) or by the lead (the UX verdict, on the human's word), not by
|
|
23
|
+
the session that wrote the code. `raf done` is refused while a sub-task is open. Detail: [raf.md](raf.md), [news.md](news.md).
|
|
24
|
+
|
|
25
|
+
## Session and wave
|
|
26
|
+
|
|
27
|
+
A **session** is one fresh run of Claude Code with a brief and a single job (write the spec, write the code, review, fix). It
|
|
28
|
+
remembers nothing of the previous one: what it needs is in the brief and in the repository. A **wave** is a run of
|
|
29
|
+
`cadence orchestrate` over several lots: the program (not a model) starts the sessions, chains the steps of each lot, runs
|
|
30
|
+
the tests, and prints a final table with the lots ready and the lots handed back. A session cannot ask you anything: when it is
|
|
31
|
+
stuck it stops and reports, and the question comes back to you through the lead. Detail: [orchestrate.md](orchestrate.md).
|
|
32
|
+
|
|
33
|
+
## The steps of a lot
|
|
34
|
+
|
|
35
|
+
<picture>
|
|
36
|
+
<source media="(prefers-color-scheme: dark)" srcset="concepts-lot-dark.svg">
|
|
37
|
+
<img alt="A lot goes through spec, code, review, correction, UX and ready; under each step, who does it: spec-writer, a fresh session, the code-reviewer, a fresh session, the ux-reviewer, the lead" src="concepts-lot-light.svg">
|
|
38
|
+
</picture>
|
|
39
|
+
|
|
40
|
+
Inside a wave, a lot goes through these steps, each in a fresh session. Dashed boxes are conditional.
|
|
41
|
+
|
|
42
|
+
| Step | What happens | Who |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| **spec** | For a lot that creates a screen (`screen: page`) or has a behaviour to pin down (`spec: true`): a mockup and a **sheet** (fields, states, numbered rules); reviewed before any code, and the acceptance tests are written from it, committed red and locked | the `spec-writer` agent, reviewed by the `ux-reviewer` (mockup) or the `code-reviewer` (sheet); then the `acceptance-writer` agent, a separate session, writes the tests; the program locks them |
|
|
45
|
+
| **code** | Test first, then the code, commits that cite the lot; the lot's own tests must pass | a fresh session of the program |
|
|
46
|
+
| **review** | Reads the diff against the lot (and the sheet, rule by rule) and returns findings: blocking, major, minor | the `code-reviewer` agent; the program records `raf review` when it is compliant |
|
|
47
|
+
| **correction** | Only if the review is not compliant: a new session fixes the findings, then a new review. Two passes at most, three when the findings converge; then the lot is **handed back** | a fresh session; the program decides how many |
|
|
48
|
+
| **UX** | For a visible lot: the screen is opened in a real browser, in each state, with captures at 1440 and 390 px | the `ux-reviewer` agent for the report; the verdict is **the human's**, or the lead's when the parent folder says `lead.ux: lead` |
|
|
49
|
+
| **ready** | In worktree mode the lot is integrated (see [below](#one-worktree-per-lot-and-integration)); without worktree (the default) it is ready as soon as its review is compliant; the lead re-checks it, records `raf done`, delivers it | the lead |
|
|
50
|
+
|
|
51
|
+
Before all that, a lot whose title cites a finding or another lot gets a **precheck**: « is it already done? ». Small lots (half a day or
|
|
52
|
+
less) get a single review pass. Detail: [fonctionnement.md](fonctionnement.md#2-a-lot-inside-a-wave), [spec.md](spec.md).
|
|
53
|
+
|
|
54
|
+
## The test gate
|
|
55
|
+
|
|
56
|
+
After each writing session the program plays the project's own **gate**: the build (`orchestrate.build`), then the tests
|
|
57
|
+
(`orchestrate.test`). A session's « the tests pass » is never taken on trust. Three rules keep the gate honest:
|
|
58
|
+
|
|
59
|
+
- **Already red at the start.** If a test fails, the program replays the suite at the sha the lot started from, in a **throwaway copy**
|
|
60
|
+
of the repository (a temporary `git worktree` outside it, removed afterwards). A test that was already red is not the lot's fault: no correction pass,
|
|
61
|
+
and the table lists it apart.
|
|
62
|
+
- **Replayed alone.** With `orchestrate.testReplay`, a test red in the whole suite is replayed alone: green alone means a load
|
|
63
|
+
failure, not a defect, so no correction is spent on it. Without this key, nothing is replayed.
|
|
64
|
+
- **A test that reads the plan.** The commits that only touch the plan are crossed when the gate's verdict is carried over them. A project whose
|
|
65
|
+
tests read `.cadence/raf.yaml` says so with `orchestrate.gate: { readsPlan: true }`, or the gate would not see a break.
|
|
66
|
+
|
|
67
|
+
A **resume** (`cadence orchestrate --resume`) picks a suspended or handed-back wave where it stopped, instead of starting again.
|
|
68
|
+
Detail: [orchestrate.md](orchestrate.md#orchestrate), [deliver.md](deliver.md), [remote-gate.md](remote-gate.md).
|
|
69
|
+
|
|
70
|
+
## One worktree per lot, and integration
|
|
71
|
+
|
|
72
|
+
<picture>
|
|
73
|
+
<source media="(prefers-color-scheme: dark)" srcset="concepts-worktrees-dark.svg">
|
|
74
|
+
<img alt="Three lots each work in their own worktree on their own branch; at the end of their cycle they pass one at a time through the integration (rebase, replayed checks, fast-forward) into main" src="concepts-worktrees-light.svg">
|
|
75
|
+
</picture>
|
|
76
|
+
|
|
77
|
+
By default a wave plays the lots of a repository one after the other. With `orchestrate.worktrees: true`, independent lots play **at the same
|
|
78
|
+
time**, each in its own **worktree** (a second checkout of the same repository, in its own folder) on its own branch
|
|
79
|
+
`cadence/<wave>/<project>--<lot>`, so two sessions never edit the same files. When a lot's cycle ends, the program **integrates** it: one
|
|
80
|
+
lot at a time under a lock, it rebases the branch on the tip of `main`, replays the checks, and fast-forwards `main`. Only then is the
|
|
81
|
+
lot `ready`. If `main` moved in the meantime the rebase is replayed, twice at most, then the lot is handed back. Two rules protect
|
|
82
|
+
you: the program, not the sessions, writes the plan; and a session never commits on the `main` branch of another repository
|
|
83
|
+
(it uses a `wip/` branch). Detail: [orchestrate.md](orchestrate.md#one-worktree-per-lot-orchestrateworktrees-l279).
|
|
84
|
+
|
|
85
|
+
## Deliverable up to a sha
|
|
86
|
+
|
|
87
|
+
<picture>
|
|
88
|
+
<source media="(prefers-color-scheme: dark)" srcset="concepts-livraison-dark.svg">
|
|
89
|
+
<img alt="Commits stack on main: L1 and L2 are ready, L3 is handed back, L4 is ready above it; the deliverable sha is the last commit of L2, so L3 and L4 are not pushed" src="concepts-livraison-light.svg">
|
|
90
|
+
</picture>
|
|
91
|
+
|
|
92
|
+
Lots commit on top of each other on `main`. When a ready lot sits **under** a lot that is not ready, pushing `HEAD` would also publish
|
|
93
|
+
unreviewed code. The final table then says « **livrable jusqu'à `<sha>`** »: the last commit of the highest ready lot that has no
|
|
94
|
+
unfinished lot beneath it. You ship exactly that, and nothing above:
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
git push origin <sha>:main && cadence deliver --sha <sha>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`cadence deliver` waits for the CI of that exact sha, deploys, and replays the effect checks: a delivery is finished only when its effect is proved.
|
|
101
|
+
Where the project declares a gate, the `pre-push` hook refuses a sha with no green `cadence verify --gate`. Detail: [deliver.md](deliver.md), [orchestrate.md](orchestrate.md#orchestrate).
|
|
102
|
+
|
|
103
|
+
## Lead and delivery agent
|
|
104
|
+
|
|
105
|
+
The **lead** is a Claude Code session (`/cadence:lead`) that drives the waves for you: it reads the state of every project
|
|
106
|
+
(`cadence lead tour`), proposes lots, starts the waves, relays each line of the journal and each question, **re-verifies** what comes back
|
|
107
|
+
(git log, tests, build, `raf check`), then delivers. It never codes and never commits where a wave runs. The **delivery agent**
|
|
108
|
+
(`livreur`) is a subagent the lead hands one ready lot to: it checks the sha, runs the gate, records `raf done`, pushes the sha and
|
|
109
|
+
delivers, then reports in one line. You stay the one who decides what matters, and the UX verdict if you did not delegate it.
|
|
110
|
+
Detail: [lead.md](lead.md), [skills.md](skills.md).
|
|
111
|
+
|
|
112
|
+
## Slots and holds
|
|
113
|
+
|
|
114
|
+
<picture>
|
|
115
|
+
<source media="(prefers-color-scheme: dark)" srcset="concepts-vague-dark.svg">
|
|
116
|
+
<img alt="A queue of lots feeds the slots of a wave: two sessions running, a slot held by a fix the lead started by hand, a free slot that `--continue` fills from the plan; the wave's table goes to the lead" src="concepts-vague-light.svg">
|
|
117
|
+
</picture>
|
|
118
|
+
|
|
119
|
+
The machine and your quota are shared, so at most **N sessions run at once**: N is the cap (`CADENCE_MAX_SESSIONS` or `--max-sessions`, 2 by default;
|
|
120
|
+
the lead never raises it itself). Each running session occupies a **slot**; a lot waits in the queue until one is free, and a freed slot goes to the next
|
|
121
|
+
lot of the wave's queue; with `--continue`, a freed slot is also filled at once by the next ready lot of the plan; without it, nothing is drawn from the plan. A session the lead starts by hand (a fix, a QA pass) is invisible to the waves, so
|
|
122
|
+
the lead declares it with `cadence lead hold <label>` and lifts it with `cadence lead release <label>`: a **hold** takes a slot, and
|
|
123
|
+
the waves wait for it instead of overtaking it. `cadence orchestrate --status` prints `créneaux libres : 1 sur 3`. Detail: [lead.md](lead.md#lead-hold-and-release), [orchestrate.md](orchestrate.md#orchestrate).
|
|
124
|
+
|
|
125
|
+
## Escalation
|
|
126
|
+
|
|
127
|
+
A lot that is still not compliant after its correction passes would normally be handed back. A project can ask for one more try
|
|
128
|
+
with a stronger model: `orchestrate.escalation: { model: fable }` plays one correction and one fresh review on that model first
|
|
129
|
+
(absent, nothing changes; it costs a share of the lot's budget). If that is not enough, the lot is **handed back** to the lead,
|
|
130
|
+
who either fixes it, answers the question, or brings it to you: the question always reaches a human, never a session. Detail: [orchestrate.md](orchestrate.md#orchestrate), [perf.md](perf.md).
|
|
131
|
+
|
|
132
|
+
## Putting into service and release
|
|
133
|
+
|
|
134
|
+
Two moments are easy to confuse. **Putting into service** concerns cadence itself, where the `raf` and `cadence` commands you type must
|
|
135
|
+
not run the code a wave is rewriting: they read a separate copy, updated only by `npm run service -- <sha>`, which refuses a sha
|
|
136
|
+
that is not an ancestor of `HEAD` or whose lots are not `done`. A **release** is a published version: `cadence release patch|minor|major` writes the version
|
|
137
|
+
files and the changelog, then prints the steps the lead plays (tag, gate, push, CI, publication). Detail: [fonctionnement.md](fonctionnement.md#4-putting-cadence-itself-in-service), [releasing.md](releasing.md).
|
|
138
|
+
|
|
139
|
+
## Glossary
|
|
140
|
+
|
|
141
|
+
- **plan**: the file `.cadence/raf.yaml` that lists the lots; the single source of truth.
|
|
142
|
+
- **lot**: one item of the plan, cited by its commits (`feat(L12): …`).
|
|
143
|
+
- **verdict**: the recorded opinion of a reviewer on a lot: `raf review` (code) and `raf ux` (screen).
|
|
144
|
+
- **session**: one fresh Claude Code run with a brief and one job.
|
|
145
|
+
- **wave**: a `cadence orchestrate` run that plays several lots and prints a table of what is ready and what is handed back.
|
|
146
|
+
- **sheet**: the written spec of a screen or a behaviour, with numbered rules, each tested.
|
|
147
|
+
- **gate**: the build and the tests the program plays after each session, with the already-red baseline and the replay alone.
|
|
148
|
+
- **readsPlan**: `orchestrate.gate` key declaring that a test reads the plan, so plan-only commits are not crossed.
|
|
149
|
+
- **worktree**: a second checkout of the repository on its own branch, one per lot, so lots play at the same time.
|
|
150
|
+
- **integration**: rebasing a lot on the tip of `main`, replaying the checks and fast-forwarding, one lot at a time, before `ready`.
|
|
151
|
+
- **handed back**: a lot the wave could not finish and returns to the lead with its cause.
|
|
152
|
+
- **deliverable up to**: the sha up to which a delivery is safe, below the first lot that is not ready.
|
|
153
|
+
- **lead**: the session that drives the waves, re-verifies and delivers; it never codes.
|
|
154
|
+
- **delivery agent**: the `livreur` subagent that delivers one ready lot and reports in one line.
|
|
155
|
+
- **slot**: one place under the cap of simultaneous sessions.
|
|
156
|
+
- **hold**: a slot kept by a session the lead started by hand, so waves do not overtake it.
|
|
157
|
+
- **escalation**: one more correction and review on a stronger model before a lot is handed back.
|
|
158
|
+
- **service**: the separate copy of cadence the `PATH` commands read, updated by `npm run service -- <sha>`.
|
|
159
|
+
- **release**: a published version, prepared by `cadence release`.
|
package/docs/fonctionnement.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# How cadence works
|
|
2
2
|
|
|
3
|
+
New to the vocabulary? Start with [the notions of cadence](concepts.md); this page is the mechanics.
|
|
4
|
+
|
|
3
5
|
A versioned plan (`raf`) tied to the commits, waves of fresh sessions driven by a program
|
|
4
6
|
(`cadence orchestrate`), a lead that decides and re-verifies, then deliveries proved by their effect.
|
|
5
7
|
Four figures go from the isolated lot to the tool itself. Dashed boxes are conditional steps; a
|
package/docs/lead.md
CHANGED
|
@@ -158,7 +158,7 @@ cadence config set orchestrate.build 'npx tsc --noEmit' --all
|
|
|
158
158
|
- `<key>` is a dotted path (`orchestrate.escalation`); `<value>` is read as YAML, so `true`, a command, or a flow mapping like `{ model: fable }` all work. A key already at that value is left alone.
|
|
159
159
|
- The rest of the file is kept as it is, byte for byte — comments, key order, blank lines, inline lists (`[a, b]`) and mappings: only the lines of the key change (a new key goes at the end of its parent; a value replaced in place keeps its end-of-line comment). The only exception is a file whose rewrite by the YAML library moves lines other than the key's (its line count changes, a comment lands on another line, or the lines carried over would not read back as the same document): then the whole file is rewritten in the library's style. A project with no `cadence.yaml` gets one.
|
|
160
160
|
- In each project it creates a **config lot** that quotes the key (`config cadence.yaml : <key> = <value>`, estimate 0.05), as `raf add` then `raf start` would, and commits `cadence.yaml`, the plan file and, when the project names `plan.onWrite`, the files that command produces (it runs when the plan is written; see `docs/raf.md`) with explicit paths (`chore(L12): cadence.yaml — <key> = <value>`): nothing else in the index or the working tree goes in. The lot is left `doing`: closing it (`raf done`) stays the lead's step. **Nothing is pushed.**
|
|
161
|
-
- The new text is read back with cadence's own config loaders (plan, news, hook, perf, session, orchestrate, docs, references, migrate, lead.ux, depth, priority, deliver) before anything is written. A `cadence.yaml` that does not read back — before the change or after it — **stops the run** (exit code 1) at that project, with nothing written there; the projects after it are named `non traités`. A commit the repository refuses (a hook) or a `plan.onWrite` command that fails stops it the same way (`lot ou commit impossible`), `cadence.yaml`, the plan file and the produced files put back as they were (a produced file HEAD does not know is deleted).
|
|
161
|
+
- The new text is read back with cadence's own config loaders (plan, news, hook, perf, session, orchestrate, docs, references, migrate, memory, lead.ux, depth, priority, deliver) before anything is written. A `cadence.yaml` that does not read back — before the change or after it — **stops the run** (exit code 1) at that project, with nothing written there; the projects after it are named `non traités`. A commit the repository refuses (a hook) or a `plan.onWrite` command that fails stops it the same way (`lot ou commit impossible`), `cadence.yaml`, the plan file and the produced files put back as they were (a produced file HEAD does not know is deleted).
|
|
162
162
|
- A project is **skipped**, with the reason, when: it is not its own git repository; the key is already at that value; the key cannot be set in its file (a plain value in the way); `cadence.yaml`, the plan file or a file named by `plan.onWrite.files` has uncommitted changes (the explicit-path commit would take them); or its plan is read-only (kept by another tool) and `cadence.yaml` names no creation command. A read-only plan that names one with `plan.add` (a shell command containing `{title}`, replaced by the quoted title of the config lot, e.g. `plan: { path: taches.yaml, lots: taches, add: 'mytool add {title}' }`) gets its config lot from that command, run in the project folder; the lot id is the first id-like word of its output (the commit subject has none when there is none), and `cadence.yaml` and the plan file are committed together. The command alone decides the lot's status.
|
|
163
163
|
- `--dry-run` prints the same lines, prefixed `+ … serait fait`, and writes and commits nothing. The last line counts what was done and skipped. Without `--all` the command refuses (run `raf`/an editor inside the project for a single one).
|
|
164
164
|
|
|
@@ -194,6 +194,8 @@ After the project lines the tour lists the **worktrees kept by waves** (L279, `o
|
|
|
194
194
|
|
|
195
195
|
Before the project lines the tour prints the **perf header** (L227): one line per `⚠` of `cadence perf` for the folder, in the order of `perf`, each ending with its decision and, for a trend, the value of its quality twin (speed and quality side by side); the net-bottleneck `⚠ goulot` line is relayed as is. Nothing is printed when no `⚠` stands, and the output is then the one of a tour without header. The header is read with `perf`'s own reading of the folder (projects up to two levels, whatever `--depth`) and only in the text output: `--json` is unchanged. When `perf` cannot read the folder (no `.cadence/runs`, malformed price grid, unreadable journals or plans) the tour prints no header, reports no perf error and exits 0. The [lead skill](skills.md) reads the header before proposing the three lots and opens an improvement lot only on a trend confirmed on two windows or a net bottleneck.
|
|
196
196
|
|
|
197
|
+
After the worktree lines the tour prints, when the `MEMORY.md` index of Claude Code for the parent folder outgrows its threshold (L442), `mémoire · MEMORY.md 15700 octets > seuil 12000 · 14 entrée(s) datée(s) à regrouper (cadence session close détaille)`. The index is `projects/<parent folder>/memory/MEMORY.md` under the Claude Code folder (`CLAUDE_CONFIG_DIR`, else the default one) (the folder resolved from the argument of `lead tour`); the threshold is 12000 bytes, or `memory.indexMaxBytes` in the parent folder's `cadence.yaml`, the same key and the same rule as for `cadence session close` ([docs/session.md](session.md#memory-index-size-l442)). A value that is not an integer ≥ 1 does not stop the tour (exit code 0): the line `cadence.yaml · ✗ erreur : memory.indexMaxBytes doit être un entier ≥ 1 (octets), pas <valeur>` replaces it. An unreadable index prints `mémoire · MEMORY.md illisible (<cause>)`. Nothing is printed for an absent index or one at the threshold, `--json` is unchanged, and the tour never writes the memory: the [lead skill](skills.md) relays the line and proposes the grouping, which is done once the human agrees.
|
|
198
|
+
|
|
197
199
|
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. The sessions held with [`lead hold`](#lead-hold-and-release) are subtracted from the free slots. The line is always printed (L416), with no live wave and no held session too: `vagues en cours : 0 · sessions en cours : 0 · créneaux libres : 3 sur 3`, so that an empty slot is read, not deduced from a missing line.
|
|
198
200
|
|
|
199
201
|
Next to it, when at least one ready lot is free, a line `prêts, ressources libres : alpha:L3 <title> · beta:L2 <title> (banc)` (L252, GitHub issue #13, 2/3) lists, for every project of the tour, the ready lots (same rule as `next`, minus the ones marked « à décider ») that can start now: a lot is free when none of the resources in its `uses:` (shown in parentheses) is held by a lot `doing` in any project of the tour or in any project that shares its resources (the projects under the folder whose `cadence.yaml` declares `resources:`, walked with that file's `depth:`, one level by default, so `P/x` and `P/grp/alpha` share the `banc` of `P/cadence.yaml` with `depth: 2` wherever the tour is launched from, even from inside one project; with no declared resource, the projects of the parent folder), nor by an unfinished lot of a live wave (a wave's lot is recognised by its repository and its id, not by the project name: a nested project `grp/alpha` matches the wave launched from `grp/` that cites it as `alpha`, and a wave launched from another folder only hides the lots of its own repositories); a lot with no `uses:` holds none and is always free. The line shows at most 3 lots per project, then `alpha +K` for the others. Like the slots line it is always printed (L416), whether or not a wave is live or a session is held. It is a display: nothing locks, `raf start` and `orchestrate` still start a lot whose resource is taken. `--json` gives the same lots, always, as a `free` array on each project (`id`, `title`, and `uses` when the lot has any; absent when the project has none).
|
package/docs/orchestrate.md
CHANGED
|
@@ -64,7 +64,7 @@ refuse the resume, and a refusal writes nothing to `control.log`.
|
|
|
64
64
|
|
|
65
65
|
**Answering on a live wave (L407).** `--answer <project:lot> "…"` (from the folder that launched the wave, `--wave` when several are live) no longer waits for the wave to end: on 28-10 a lot waited about 15 minutes for its answer because another lot of the wave was still running, and `--resume` refuses a wave that is running. The answer is appended to the wave's queue (`answers.log` in `.cadence/runs/<wave>/`, one JSON line per answer and per answer taken), the command prints `<lot> : réponse déposée` and returns at once. The live wave reads the queue every 2 seconds and each time a lot finishes, applies the answer to the lot (the same state as `--resume --answer`: the answer joins the brief of its next session) and replays it as one more line of the pool, as soon as a session slot is free; a lot with no worktree never plays together with another lot of its repository. The documented form `--resume --wave <wave> --answer …` does the same when that wave is still running (it used to be refused with `tourne encore`); combined with another resume option (`--budget`, `--drop`, `--integrate`, `--continue`) it is still refused. Refused (exit 2) before anything is written: a lot that is unknown, that several projects carry, or that is not waiting for an answer (`question`); no live wave in that folder (the message gives the `--resume --wave <wave> --answer` form for a stopped wave); a wave started before L407, whose snapshot does not read the queue. `--answer` alone does not combine with `--drop`, `--stop-after-current`, `--budget`, `--dry-run`, `--continue` or lots to launch. An answer whose lot is no longer waiting when the wave reads it (dropped, or already answered by an earlier line) is discarded and the journal says so (`réponse écartée`), it is never played twice; if the wave finishes between the check and the write, the answer is withdrawn and the command says to use `--resume`. Not covered: a lot that depends (`after`) on the answered lot and was left waiting in the pool is not started by this wave when the answer makes the lot ready; `--resume` plays it.
|
|
66
66
|
|
|
67
|
-
**Adding a lot to a live wave (L421).** A second `cadence orchestrate <project:lot>` in a repository that a live wave holds is refused (`une orchestration y est déjà en cours (<wave>, pid …)`), and the lead used to wait for the whole wave to end. The refusal now names the way out when that wave was launched from the same folder: `… ; pour y ajouter ce lot : cadence orchestrate --add <project>:<lot> --wave <wave>`. `--add <project:lot> [--wave <wave>]` (repeatable; from the folder that launched the wave, `--wave` when several are live) checks each lot like a lot given at launch (known, open, dependencies, Node, `repos:`), with three differences: a repository held **by that wave** is accepted (its dirty tree and its push guard are the wave's own), a dependency counts when it is a lot of the wave or an earlier `--add` of the same call, and the remaining budget of the wave (`budget − consumed`) must hold the budget of the lot. Then it appends the lot to the wave's queue (`adds.log` in `.cadence/runs/<wave>/`, one JSON line per request and per request taken), prints `<lot> : ajout déposé` and returns at once. The live wave reads the queue with the answers (every 2 seconds and each time a lot finishes), checks the lot again at that moment, and adds it: the lot is written in the wave state and in `wave.json`, the repository lock and push guard are taken if the wave does not hold the repository (any more), and the journal says `<lot> : ajouté à la vague <wave>`. The lot then plays as one more line of the pool as soon as a session slot is free; a lot of a repository where another lot of the wave is playing waits for it (never two sessions in one repository), and plays in its own worktree only when every lot still to play in that repository does. Refused (exit 2) before anything is written, nothing queued for any lot as soon as one is refused: a lot unknown or already finished, a lot already in the wave or already queued, a dependency neither done nor in the wave, a repository held by another wave, a budget that does not fit, no live wave in that folder, several live waves without `--wave`, a wave started before L421 (its snapshot does not read the queue). `--add` combines with nothing but `--wave`. A request that no longer holds when the wave reads it (lot done meanwhile, repository taken by another wave, budget spent, `--stop-after-current` requested, usage limit, incident) is discarded and the journal says so (`ajout écarté (<cause>)`) — a request kept waiting for its repository is checked again at the moment it is taken, so a stop requested or a budget spent while it waited discards it too, and the lot never enters `wave.json`; the same goes for a request still queued when no session is left to play (`la vague a fini de jouer`) — if the wave ends between the check and the write, the command withdraws the request and says to launch the lot in a new wave. A legitimate commit of an added lot on the main branch of its repository is not an incident for a session already running in a sibling repository (L456). With `--continue`, the lots added by hand count as lots of the wave and are not drawn a second time. The case of `--resume --integrate` refused while another wave holds the repository is not part of `--add`: the resume waits for that wave (L443).
|
|
67
|
+
**Adding a lot to a live wave (L421).** A second `cadence orchestrate <project:lot>` in a repository that a live wave holds is refused (`une orchestration y est déjà en cours (<wave>, pid …)`), and the lead used to wait for the whole wave to end. The refusal now names the way out when that wave was launched from the same folder: `… ; pour y ajouter ce lot : cadence orchestrate --add <project>:<lot> --wave <wave>`. `--add <project:lot> [--wave <wave>]` (repeatable; from the folder that launched the wave, `--wave` when several are live) checks each lot like a lot given at launch (known, open, dependencies, Node, `repos:`), with three differences: a repository held **by that wave** is accepted (its dirty tree and its push guard are the wave's own), a dependency counts when it is a lot of the wave or an earlier `--add` of the same call, and the remaining budget of the wave (`budget − consumed`) must hold the budget of the lot. Then it appends the lot to the wave's queue (`adds.log` in `.cadence/runs/<wave>/`, one JSON line per request and per request taken), prints `<lot> : ajout déposé` and returns at once. The live wave reads the queue with the answers (every 2 seconds and each time a lot finishes), checks the lot again at that moment, and adds it: the lot is written in the wave state and in `wave.json`, the repository lock and push guard are taken if the wave does not hold the repository (any more), and the journal says `<lot> : ajouté à la vague <wave>`. The lot then plays as one more line of the pool as soon as a session slot is free; in a repository in `orchestrate.worktrees: true` mode with a cap above one it plays in its own worktree at once, in parallel with the lot already playing there (L527, every lot of such a repository has its own); otherwise a lot of a repository where another lot of the wave is playing waits for it (never two sessions in one repository), and plays in its own worktree only when every lot still to play in that repository does. Refused (exit 2) before anything is written, nothing queued for any lot as soon as one is refused: a lot unknown or already finished, a lot already in the wave or already queued, a dependency neither done nor in the wave, a repository held by another wave, a budget that does not fit, no live wave in that folder, several live waves without `--wave`, a wave started before L421 (its snapshot does not read the queue). `--add` combines with nothing but `--wave`. A request that no longer holds when the wave reads it (lot done meanwhile, repository taken by another wave, budget spent, `--stop-after-current` requested, usage limit, incident) is discarded and the journal says so (`ajout écarté (<cause>)`) — a request kept waiting for its repository is checked again at the moment it is taken, so a stop requested or a budget spent while it waited discards it too, and the lot never enters `wave.json`; the same goes for a request still queued when no session is left to play (`la vague a fini de jouer`) — if the wave ends between the check and the write, the command withdraws the request and says to launch the lot in a new wave. A legitimate commit of an added lot on the main branch of its repository is not an incident for a session already running in a sibling repository (L456). With `--continue`, the lots added by hand count as lots of the wave and are not drawn a second time. The case of `--resume --integrate` refused while another wave holds the repository is not part of `--add`: the resume waits for that wave (L443).
|
|
68
68
|
|
|
69
69
|
**`--goal "…"` and `goal:` — the objective of the briefs when the title is stale (L258)**: the first line of the `{{objectif}}` of every
|
|
70
70
|
brief of a lot (and the title quoted in their first sentence) is the lot's title; when a change of scope made it stale, the lead no longer
|
|
@@ -121,9 +121,11 @@ journal (`continue : lot sauté — <cause>`; for the first draw also on the err
|
|
|
121
121
|
time window (`--until HH:MM`, today's clock: nothing new is drawn from then on, a running lot is not cut), the usage limit (« usage limit reached », « rate limit », « You've hit your weekly limit »),
|
|
122
122
|
a question asked (the wave stays resumable with `--answer`), two lots handed back in a row, an interrupted wave, a `--stop-after-current` request (`arrêt demandé`, even when the last running
|
|
123
123
|
lots finished cleanly), or no ready
|
|
124
|
-
lot whose estimate fits the budget left. `--resume … --continue` draws again after the resumed lots. When the wave starts, `--continue` (and its `--dry-run`) prints the line `prêts, ressources libres : <project>:<lot> <title> (<resources>) · …` that `cadence lead tour` prints (L252): the ready lots, from every project of the folder, whose `uses:` resources (`raf uses`, `resources:` of the parent `cadence.yaml`) are held neither by a lot `doing` (of the folder's projects, and of every project that shares their resources: those under the folder whose `cadence.yaml` declares `resources:`, walked with its `depth:`, one level by default, so launched from a group or from inside one project it still sees the others) nor by an unfinished lot of a live wave nor by the lots of the first draw of the wave that starts (a lot of a wave is recognised by its repository and its id, not by the project name; those lots, and the ready lots that compete with them for a resource, are not listed); at most 3 lots per project, then `<project> +K`; nothing is held back by it, the draw below is unchanged. `--dry-run --continue`
|
|
125
|
-
|
|
126
|
-
names the candidates skipped with their cause: `
|
|
124
|
+
lot whose estimate fits the budget left. `--resume … --continue` draws again after the resumed lots. When the wave starts, `--continue` (and its `--dry-run`) prints the line `prêts, ressources libres : <project>:<lot> <title> (<resources>) · …` that `cadence lead tour` prints (L252): the ready lots, from every project of the folder, whose `uses:` resources (`raf uses`, `resources:` of the parent `cadence.yaml`) are held neither by a lot `doing` (of the folder's projects, and of every project that shares their resources: those under the folder whose `cadence.yaml` declares `resources:`, walked with its `depth:`, one level by default, so launched from a group or from inside one project it still sees the others) nor by an unfinished lot of a live wave nor by the lots of the first draw of the wave that starts (a lot of a wave is recognised by its repository and its id, not by the project name; those lots, and the ready lots that compete with them for a resource, are not listed); at most 3 lots per project, then `<project> +K`; nothing is held back by it, the draw below is unchanged. `--dry-run --continue` simulates the
|
|
125
|
+
free-slot fill below with the same function as the wave, one lot at a time (the first ready lot in the priority order, pre-check, budget counted on the estimates), and
|
|
126
|
+
names the candidates skipped with their cause: `tirés ensuite, un par un au fil des créneaux libres, dans l'ordre de priorité (budget décompté sur les estimations) : b:L2, a:L2, a:L3` (ten at most, then `…`). The simulation cannot know which repository will be busy at each look: it lists the lots in the order the fill would take them if every repository were free. The round draw happens between rounds: a round of up to `--max-sessions` lots must finish before the next round draw; a free slot is filled in the meantime (below).
|
|
127
|
+
|
|
128
|
+
**A free slot is filled at once (L527, GitHub issue #21).** Between rounds is not the only moment of the draw: while the pool plays, each time a session slot is free — no queue playing, none waiting for its dependency — the wave draws the next ready lot of the plan, in the priority order above, and plays it without waiting for the lots still playing (on 02-11 a lot added to a wave waited behind the other one, played alone in the main tree, while a slot stayed empty; a lot handed back at the pre-check frees its slot within seconds the same way). The wave looks at the slots at the end of each lot and every 2 seconds. The draw keeps every rule of the round: at most `--max-sessions` sessions across all the waves; never two sessions in one repository (a candidate whose repository is playing is kept for the next look, the next lot of another repository goes first; with `orchestrate.worktrees: true` and more than one slot every lot of the repository plays in its own worktree — given alone, drawn by the fill or added by `--add`, with or without `--continue` — so the next lot of its repository can fill the free slot); a lot whose `uses:` resource is held by a lot `doing` or by an unfinished lot of a live wave (this one included) is not drawn; the project's `continue:` setting; a lot refused by the pre-check is skipped, with its cause in the journal (`continue : lot sauté — <cause>`, said once; a refusal of the repository, such as a dirty tree, is looked at again at the next look). The stops are those of the round (`continue : arrêt`): `--stop-after-current`, the usage limit, a question asked, two lots handed back in a row, `--until`, the budget. The budget a lot still playing has not spent yet stays reserved (its budget minus the tokens counted for it): the next lot must fit in the rest. When several slots are free at once, each lot taken counts before the next: its budget comes off the rest, and a lot that wants a `uses:` resource the fill has just taken waits for the next look. Each start is told in the journal: `continue : tire <project>:<lot> (créneau libre)`, then `<project>:<lot> : ajouté à la vague <wave>` as for `--add`; the lot is in `wave.json`. Without `--continue` nothing is drawn: lots given on the command line are the only ones played. The round draw stays for the first lots and for what the free-slot fill did not take (a refused lot that is clean again).
|
|
127
129
|
|
|
128
130
|
**Keeping a lot out of the draw (L390, `orchestrate.continue`)**: `--continue` draws the first ready lot of the plan, even a big one with no spec and no sub-task (maritime B6 « Profils verticaux, coupes (10) », effort L, drawn on 27-10 then withdrawn by the lead). A project says what its draw may not take, in its own `cadence.yaml`:
|
|
129
131
|
|
|
@@ -559,6 +561,10 @@ except a copy that is still needed, which stays and is said: a copy that a live
|
|
|
559
561
|
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
|
|
560
562
|
(bin, dist, package.json).
|
|
561
563
|
|
|
564
|
+
## Proposals the lot's own commits may have treated (L422)
|
|
565
|
+
|
|
566
|
+
The sub-tasks a review proposes (`[sous-tâche code] …`, `ux`, `maquette`) are returned to the lead in the final table and in `--status --detail <lot>`. When a fix pass runs after the review, it often treats them; 28-10, L230 was opened on proposals already corrected, 5 passes lost. The program now keeps, for each sub-task, the HEAD the review that issued it had read (`proposalHeads` in the lot's state; a later review that repeats the same line does not renew it) and, when it prints the line, looks for the files the text cites (`src/a.ts`, `src/a.ts:42`, `` `docs/z.md` ``; not web addresses nor numbers). If a commit of the lot (those the steps noted, or by default the ones git attributes to it: the HEAD of the review and these shas come from the same state of the branch, whereas the repository's HEAD does not see a lot not yet integrated and only finds rewritten commits once it was rebased) that is not in the history of that HEAD modified one of them (whole path or end of path), the line ends with `— peut-être déjà traitée (<sha>)`, the oldest such commit. It is a hint to check before opening a lot, not a verdict: nothing is removed from the proposals. Left unmarked: minors (already a precise file line), sub-tasks citing no file, states written before this change (no recorded HEAD), a HEAD the repository does not know, a git read that fails, `--status` (compact: the lines are not printed, no git read), and commits made in a neighbouring repository (`repos:`), which are not read.
|
|
567
|
+
|
|
562
568
|
## Express lane (L519)
|
|
563
569
|
|
|
564
570
|
A lot of **at most 0.1 day** (`estimate: 0.1` or less, no `screen:`, no `spec: true`) takes the express lane, with no key to set. The L517 study ([docs/mesures/temps-d-un-lot.md](mesures/temps-d-un-lot.md), lever 2) measures 15.5 min and 116 k counted tokens for such a lot, 44 % of them in review and preparation: the lane cuts about 4.9 min and 51 k tokens per lot. What changes:
|
|
@@ -570,6 +576,16 @@ A lot of **at most 0.1 day** (`estimate: 0.1` or less, no `screen:`, no `spec: t
|
|
|
570
576
|
|
|
571
577
|
A lot above 0.1 day, or with a screen or a spec sheet, keeps the full cycle. The threshold is `EXPRESS_MAX_ESTIMATE` in `src/orchestrate/express.ts`.
|
|
572
578
|
|
|
579
|
+
|
|
580
|
+
## Cost in euros, before and after a wave (L529)
|
|
581
|
+
|
|
582
|
+
With a `perf.prices` grid in the `cadence.yaml` of the launch folder (the one `cadence perf` reads, see [perf](perf.md)), the wave is priced twice:
|
|
583
|
+
|
|
584
|
+
- **before**: `--dry-run` prints, after the simulation of the lots (their `budget du lot` lines), one line per lot `a:L1 — estimation du lot : 3,15 € (budget de 750000 tokens au prix sonnet, 90 % en entrée)` and then `estimation de la vague : …`. The estimate is the lot's token budget (the p90 measured for the budget, see **Budget** below) priced at the model of the lot's writing step, split 90 % input, 10 % output (the split of a journal that only carries `counted`). The budget counts input, cache writes and output: **cache reads and the steps of another model (reviews) are not in the estimate**, so the real cost, which counts them, can exceed it.
|
|
585
|
+
- **after**: the final table and `--status` gain a `€` column, the real cost of each lot (every step at the price of its own model, the four counters of the step, as `cadence perf`), and the `vague …` line ends its token count with the total in euros. A lot with a step on a model without price in the grid reads `n/d`; the wave total then adds only the priced lots and says `(n/d pour N lots, modèle sans prix)`. A `local` step costs 0 €.
|
|
586
|
+
|
|
587
|
+
Without `perf.prices` nothing changes: no estimate, no column, no total. A malformed grid does not stop a simulation, a wave or the table (a wave already paid must still print its table): the command prints `orchestrate : coût en euros n/d : …` on stderr (`--status`: a `⚠` line) and goes on without euros.
|
|
588
|
+
|
|
573
589
|
## The edge-case probe (`orchestrate.probe`, L497)
|
|
574
590
|
|
|
575
591
|
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.
|
|
@@ -618,9 +634,9 @@ nothing below applies and the wave behaves as before; any other value is refused
|
|
|
618
634
|
(`orchestrate.worktrees doit être true ou false`).
|
|
619
635
|
|
|
620
636
|
- **Which lots.** The lots of one repository (as project; two lots that share a neighbour `repos:` are one group) go to worktrees when the
|
|
621
|
-
group has at least two lots, the repository is on a branch (not a detached `HEAD`) and no lot of the group declares `repos:`. Otherwise they
|
|
637
|
+
group has at least two lots or the session cap is above one (`--max-sessions`, L527), the repository is on a branch (not a detached `HEAD`) and no lot of the group declares `repos:`. Otherwise they
|
|
622
638
|
stay one after the other in the repository, with `orchestrate : <repository> : worktrees demandés mais <reason> : lots joués à la suite` in the
|
|
623
|
-
journal.
|
|
639
|
+
journal. With a cap above one, every lot of the repository has its own worktree — given alone, drawn by the free-slot fill of `--continue` or added by `--add`, with or without `--continue` — so a second lot of the repository can take a free slot while the first plays; with a cap of 1 a lot alone in its repository plays in it. A lot that already has its branch (a resume) keeps its worktree whatever the group.
|
|
624
640
|
- **When.** At the moment the lot takes its place under the cap, after its `raf start` — not at launch: a lot waiting for a place has neither a
|
|
625
641
|
worktree nor a branch. A lot that depends on another lot of the repository (`after`) waits until that one is `ready`, which in this mode only
|
|
626
642
|
happens **after** its integration, then starts from the tip of the repository's branch, which contains it. If the worktree or the branch cannot be
|
package/docs/overview.md
CHANGED
|
@@ -74,7 +74,7 @@ The two plugins are independent. `cadence@cadence` carries the rituals, which ca
|
|
|
74
74
|
| [docs/stabilite.md](stabilite.md) | what is guaranteed from 1.0.0 and what is not |
|
|
75
75
|
| [docs/qualite.md](qualite.md) | code-quality guard rails: ESLint (typescript-eslint, sonarjs), knip and jscpd compared to a versioned baseline by a ratchet (`npm run qualite`, `--init`, `--ecrire`, `--migrer`, `--contre`), in the wave's gate and the CI; the recipe for TypeScript, Python, Java and shell |
|
|
76
76
|
|
|
77
|
-
Also: [news](news.md) (changelog, UX, code and QA reviews, documentation that follows the code), [quality](qualite.md), [session](session.md), [corrections](corrections.md), [perf](perf.md), [skills and agents](skills.md), [cadence-hud](cadence-hud.md), [releasing](releasing.md), [overview](overview.md), [how it all works](fonctionnement.md) (four figures).
|
|
77
|
+
Also: [news](news.md) (changelog, UX, code and QA reviews, documentation that follows the code), [quality](qualite.md), [session](session.md), [corrections](corrections.md), [perf](perf.md), [skills and agents](skills.md), [cadence-hud](cadence-hud.md), [releasing](releasing.md), [overview](overview.md), [the notions, for a human](concepts.md), [how it all works](fonctionnement.md) (four figures).
|
|
78
78
|
|
|
79
79
|
<details>
|
|
80
80
|
<summary>The four tools in short</summary>
|