@roomi-fields/grillhouse 0.23.1 → 0.24.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/plugin.json +1 -1
- package/METACADRE.md +1 -1
- package/agents/explorateur.md +4 -2
- package/agents/questionneur.md +1 -1
- package/bin/grillhouse.mjs +3 -58
- package/cadre/templates/projet/CLAUDE.md +5 -1
- package/cadre/templates/projet/docs/agents/issue-tracker.md +4 -4
- package/charte.md +23 -6
- package/docs/ARCHITECTURE.md +127 -1
- package/hooks/register.tsx +3 -13
- package/package.json +13 -1
- package/scripts/bilan.mjs +134 -88
- package/scripts/circuit.mjs +1547 -2248
- package/scripts/composants-affectes.mjs +27 -108
- package/scripts/consommateurs-arbitres.mjs +15 -21
- package/scripts/consommateurs.d.ts +8 -0
- package/scripts/consommateurs.mjs +5 -1
- package/scripts/dette.d.ts +23 -0
- package/scripts/dette.mjs +76 -13
- package/scripts/droits.mjs +38 -44
- package/scripts/elements-du-lot.mjs +246 -0
- package/scripts/enveloppe/enveloppe.mjs +105 -232
- package/scripts/enveloppe/lancer.sh +79 -49
- package/scripts/enveloppe/paquets-du-plan.mjs +49 -0
- package/scripts/etapes.mjs +148 -213
- package/scripts/gardes-du-cadre.mjs +8 -6
- package/scripts/grillhouse-maj.mjs +31 -9
- package/scripts/index-interfaces.mjs +21 -1
- package/scripts/integration/integrer.mjs +2 -2
- package/scripts/interfaces-contre-code.mjs +25 -17
- package/scripts/migrations/0.23.0-config-vitest.mjs +26 -23
- package/scripts/migrations/0.23.2-copies-du-cadre.mjs +201 -0
- package/scripts/migrations/0.24.0-circuit-simplifie.mjs +231 -0
- package/scripts/migrations.mjs +41 -6
- package/scripts/paquets.d.ts +5 -0
- package/scripts/paquets.mjs +3 -0
- package/scripts/references-par-les-types.mjs +55 -36
- package/scripts/registre.mjs +7 -15
- package/scripts/resultats.mjs +283 -142
- package/scripts/resumes.mjs +1 -1
- package/scripts/session-start.sh +1 -2
- package/scripts/sources.mjs +28 -0
- package/scripts/sous-commandes.mjs +62 -0
- package/scripts/tableau.mjs +85 -191
- package/scripts/tests.mjs +19 -17
- package/scripts/verifier.mjs +5 -4
- package/scripts/verrou-de-machine.mjs +131 -24
- package/scripts/verrous/verrou.mjs +66 -5
- package/skills/developpeur/SKILL.md +60 -50
- package/skills/explorateur/SKILL.md +90 -64
- package/skills/grill/SKILL.md +1 -1
- package/skills/mesure/SKILL.md +2 -1
- package/skills/pitmaster/SKILL.md +132 -118
- package/skills/pitmaster/references/consigne-agent.md +54 -148
- package/skills/questionneur/SKILL.md +18 -18
- package/skills/relecteur/SKILL.md +69 -23
- package/skills/testwriter/SKILL.md +46 -35
- package/types/index.d.ts +1 -3
- package/agents/referent-technique.md +0 -9
- package/agents/regulateur.md +0 -11
- package/scripts/enveloppe/composant.mjs +0 -11
- package/scripts/etat-du-circuit.mjs +0 -104
- package/skills/referent-technique/SKILL.md +0 -145
- package/skills/regulateur/SKILL.md +0 -220
package/scripts/etapes.mjs
CHANGED
|
@@ -3,121 +3,81 @@
|
|
|
3
3
|
// list, which the circuit (scripts/circuit.mjs), the board (scripts/tableau.mjs), the bilan
|
|
4
4
|
// (scripts/bilan.mjs) and the texts read.
|
|
5
5
|
//
|
|
6
|
-
// - A step (ETAPES): its number (« 2 », «
|
|
6
|
+
// - A step (ETAPES): its number (« 2 », « 4.1 »), its title, who works there (`qui`: the role
|
|
7
7
|
// agents, or AUTO for a step the circuit leads itself; none for a step that only holds its
|
|
8
|
-
// sub-steps), its
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
// a questioning, the reviews, the same stop come back after a RELANCE of the regulator. The
|
|
23
|
-
// circuit stops each loop at its maximum and writes its count in its state; the board shows
|
|
24
|
-
// « <label> <n>/<max> » on the ticket's line from the second pass.
|
|
25
|
-
// - The arbitrage of a stop (ARBITRAGE) stands out of the sequence, under the stopped step: the
|
|
26
|
-
// regulator settles the stop, and the questionneur asks its questions of his decision before it
|
|
27
|
-
// is applied, as Amazon's bar raiser and a cockpit's challenge and response; it has no number.
|
|
8
|
+
// sub-steps), its sub-steps (`sous`), and the step of the circuit's state it is (`etat`: the
|
|
9
|
+
// `etape` of `.claude/worktrees/<ticket>.circuit.json`, the final pass being the checks once
|
|
10
|
+
// `finale`). Every step runs once for the whole ticket, as a merge request has one author of
|
|
11
|
+
// its tests and one of its code, one CI on the whole and one review: one session of the
|
|
12
|
+
// testwriter (2) and one of the developpeur (3) carry the whole plan.
|
|
13
|
+
// The plan (1) is read elsewhere in the state: by the work on the plan under way
|
|
14
|
+
// (`questionnement`, the explorateur's or the questionneur's session) and by its stop (`arrets`).
|
|
15
|
+
// SUITE is the tree in its order, each step before its sub-steps.
|
|
16
|
+
// - A step carries as many bounded loops as it needs (`boucles`), each spanning the step and its
|
|
17
|
+
// sub-steps: each its key (`cle`, which keys its count in the state's `boucles`), its label and
|
|
18
|
+
// its maximum (`max`, the pass that stops it): the testwriter's sessions after a refused proof,
|
|
19
|
+
// the developpeur's sessions with their checks, the reviews. The circuit stops each loop at its
|
|
20
|
+
// maximum and writes its count in its state; the board shows « <label> <n>/<max> » on the
|
|
21
|
+
// ticket's line from the second pass.
|
|
28
22
|
// - The stops of the circuit, each by its name and its exit code (ARRETS): the circuit ends on one
|
|
29
23
|
// with its code, and its header says when.
|
|
30
|
-
// - The
|
|
24
|
+
// - The gestures of the circuit (GESTES, below): what it does itself on a stop a rule settles,
|
|
25
|
+
// with no session.
|
|
26
|
+
// - The question of each other stop (MONTEES, below): what goes up to the supervisor, and who
|
|
27
|
+
// must answer it.
|
|
31
28
|
import { A_REPASSER } from './vitest-config/pression.mjs';
|
|
32
29
|
|
|
33
30
|
// Who works at a step the circuit leads itself, with no agent.
|
|
34
31
|
export const AUTO = 'auto';
|
|
35
32
|
|
|
36
|
-
// The rounds of a questioning, of the plan at 1.2 and of a decision at the arbitrage.
|
|
37
|
-
const TOURS = { cle: 'questionnement', libelle: 'tour', max: 4 };
|
|
38
|
-
|
|
39
33
|
export const ETAPES = [
|
|
40
|
-
{ numero: '0', titre: 'Exploration', qui: ['explorateur'], etat: null },
|
|
41
34
|
{
|
|
42
35
|
numero: '1',
|
|
43
|
-
titre: '
|
|
44
|
-
qui: [],
|
|
36
|
+
titre: 'Plan',
|
|
37
|
+
qui: ['explorateur', 'questionneur'],
|
|
45
38
|
etat: null,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
numero: '1.1',
|
|
49
|
-
titre: 'Relevé des composants',
|
|
50
|
-
qui: [AUTO],
|
|
51
|
-
etat: null,
|
|
52
|
-
releve: true,
|
|
53
|
-
arrets: ['composants-manquants'],
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
numero: '1.2',
|
|
57
|
-
titre: 'Questionnement',
|
|
58
|
-
qui: ['questionneur', 'referent-technique'],
|
|
59
|
-
quiCourt: 'questionneur ⇄ référent',
|
|
60
|
-
etat: null,
|
|
61
|
-
questionnement: 'plan',
|
|
62
|
-
arrets: ['questionnement'],
|
|
63
|
-
boucles: [TOURS],
|
|
64
|
-
},
|
|
65
|
-
],
|
|
39
|
+
questionnement: 'plan',
|
|
40
|
+
arrets: ['questionnement'],
|
|
66
41
|
},
|
|
67
42
|
{
|
|
68
43
|
numero: '2',
|
|
69
|
-
titre: '
|
|
70
|
-
qui: [],
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
{ cle: 'composant', libelle: 'composant', max: null },
|
|
75
|
-
{ cle: 'tests', libelle: 'essai', max: 3, sur: ['2.1', '2.2'] },
|
|
76
|
-
{ cle: 'code', libelle: 'essai', max: 3, sur: ['2.3', '2.4'] },
|
|
77
|
-
],
|
|
78
|
-
sous: [
|
|
79
|
-
{
|
|
80
|
-
numero: '2.1',
|
|
81
|
-
titre: 'Tests',
|
|
82
|
-
qui: ['testwriter'],
|
|
83
|
-
parComposant: true,
|
|
84
|
-
etat: 'testwriter',
|
|
85
|
-
},
|
|
86
|
-
{ numero: '2.2', titre: 'Preuve du rouge', qui: [AUTO], parComposant: true, etat: 'preuve' },
|
|
87
|
-
{
|
|
88
|
-
numero: '2.3',
|
|
89
|
-
titre: 'Code',
|
|
90
|
-
qui: ['developpeur'],
|
|
91
|
-
parComposant: true,
|
|
92
|
-
etat: 'developpeur',
|
|
93
|
-
},
|
|
94
|
-
{ numero: '2.4', titre: 'Contrôles', qui: [AUTO], parComposant: true, etat: 'controles' },
|
|
95
|
-
],
|
|
44
|
+
titre: 'Tests',
|
|
45
|
+
qui: ['testwriter'],
|
|
46
|
+
etat: 'testwriter',
|
|
47
|
+
boucles: [{ cle: 'tests', libelle: 'essai', max: 3 }],
|
|
48
|
+
sous: [{ numero: '2.1', titre: 'Preuve du rouge', qui: [AUTO], etat: 'preuve' }],
|
|
96
49
|
},
|
|
97
50
|
{
|
|
98
51
|
numero: '3',
|
|
99
|
-
titre: '
|
|
100
|
-
qui: [
|
|
101
|
-
etat: '
|
|
102
|
-
|
|
52
|
+
titre: 'Code',
|
|
53
|
+
qui: ['developpeur'],
|
|
54
|
+
etat: 'developpeur',
|
|
55
|
+
boucles: [{ cle: 'code', libelle: 'essai', max: 3 }],
|
|
56
|
+
sous: [{ numero: '3.1', titre: 'Contrôles', qui: [AUTO], etat: 'controles' }],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
numero: '4',
|
|
60
|
+
titre: 'Passe finale et relecture',
|
|
61
|
+
qui: [],
|
|
62
|
+
etat: null,
|
|
103
63
|
sous: [
|
|
64
|
+
{ numero: '4.1', titre: 'Passe finale', qui: [AUTO], etat: 'controles', finale: true },
|
|
104
65
|
{
|
|
105
|
-
numero: '
|
|
66
|
+
numero: '4.2',
|
|
106
67
|
titre: 'Régénération des références',
|
|
107
68
|
qui: [AUTO],
|
|
108
69
|
etat: 'references',
|
|
109
|
-
declaration: 'references',
|
|
110
70
|
arrets: ['references'],
|
|
111
71
|
},
|
|
72
|
+
{
|
|
73
|
+
numero: '4.3',
|
|
74
|
+
titre: 'Relecture',
|
|
75
|
+
qui: ['relecteur'],
|
|
76
|
+
etat: 'relecture',
|
|
77
|
+
boucles: [{ cle: 'relecture', libelle: 'tour', max: 3 }],
|
|
78
|
+
},
|
|
112
79
|
],
|
|
113
80
|
},
|
|
114
|
-
{
|
|
115
|
-
numero: '4',
|
|
116
|
-
titre: 'Relecture',
|
|
117
|
-
qui: ['relecteur'],
|
|
118
|
-
etat: 'relecture',
|
|
119
|
-
boucles: [{ cle: 'relecture', libelle: 'tour', max: 3 }],
|
|
120
|
-
},
|
|
121
81
|
{
|
|
122
82
|
numero: '5',
|
|
123
83
|
titre: 'Intégration',
|
|
@@ -133,29 +93,19 @@ export const ETAPES = [
|
|
|
133
93
|
// Every step and sub-step, in the order of the tree.
|
|
134
94
|
export const SUITE = ETAPES.flatMap(e => [e, ...(e.sous ?? [])]);
|
|
135
95
|
|
|
136
|
-
// The arbitrage of a stop, out of the sequence, under the stopped step.
|
|
137
|
-
export const ARBITRAGE = {
|
|
138
|
-
numero: null,
|
|
139
|
-
titre: "Arbitrage de l'arrêt",
|
|
140
|
-
qui: ['regulateur', 'questionneur'],
|
|
141
|
-
etat: null,
|
|
142
|
-
boucles: [{ cle: 'arret', libelle: 'arrêt', max: 3 }, TOURS],
|
|
143
|
-
};
|
|
144
|
-
|
|
145
96
|
// The bounded loop of key <cle>.
|
|
146
|
-
export const boucle = cle =>
|
|
147
|
-
[...SUITE, ARBITRAGE].flatMap(e => e.boucles ?? []).find(b => b.cle === cle) ?? null;
|
|
97
|
+
export const boucle = cle => SUITE.flatMap(e => e.boucles ?? []).find(b => b.cle === cle) ?? null;
|
|
148
98
|
|
|
149
|
-
// The loops that run at the step <etape>:
|
|
150
|
-
// each step that spans it, itself or its parent.
|
|
99
|
+
// The loops that run at the step <etape>: its own and its parent's.
|
|
151
100
|
export const bouclesDe = etape => {
|
|
152
|
-
if (etape === ARBITRAGE) return ARBITRAGE.boucles;
|
|
153
101
|
const parent = ETAPES.find(e => e === etape || e.sous?.includes(etape));
|
|
154
|
-
return [...new Set([parent, etape])]
|
|
155
|
-
.flatMap(e => e?.boucles ?? [])
|
|
156
|
-
.filter(b => (b.sur ? b.sur.includes(etape.numero) : true));
|
|
102
|
+
return [...new Set([parent, etape])].flatMap(e => e?.boucles ?? []);
|
|
157
103
|
};
|
|
158
104
|
|
|
105
|
+
// The agents who write the lot, the testwriter its tests and the developpeur its code: the roles a
|
|
106
|
+
// blocking finding of the reviewer names.
|
|
107
|
+
export const AGENTS_DU_LOT = ['testwriter', 'developpeur'];
|
|
108
|
+
|
|
159
109
|
// The exit code of each stop of the circuit.
|
|
160
110
|
export const ARRETS = {
|
|
161
111
|
lancement: 10,
|
|
@@ -166,46 +116,36 @@ export const ARRETS = {
|
|
|
166
116
|
'sans-livraison': 15,
|
|
167
117
|
'relecture-arret': 16,
|
|
168
118
|
integration: 17,
|
|
169
|
-
question: 18,
|
|
170
119
|
'hors-portee': 19,
|
|
171
120
|
besoin: 20,
|
|
172
|
-
'composants-manquants': 21,
|
|
173
121
|
questionnement: 22,
|
|
174
122
|
references: 23,
|
|
123
|
+
'hors-plan': 24,
|
|
175
124
|
'a-repasser': A_REPASSER,
|
|
176
125
|
};
|
|
177
126
|
|
|
178
|
-
// The role that
|
|
179
|
-
export const
|
|
127
|
+
// The role that writes the plan and answers its questions once, and the role that questions it.
|
|
128
|
+
export const EXPLORATEUR = 'explorateur';
|
|
180
129
|
export const QUESTIONNEUR = 'questionneur';
|
|
181
130
|
|
|
182
131
|
// A role in words.
|
|
183
|
-
const NOMS = {
|
|
184
|
-
'referent-technique': 'référent technique',
|
|
185
|
-
regulateur: 'régulateur',
|
|
186
|
-
developpeur: 'développeur',
|
|
187
|
-
};
|
|
132
|
+
const NOMS = { developpeur: 'développeur' };
|
|
188
133
|
export const nomDuRole = role => NOMS[role] ?? role;
|
|
189
134
|
|
|
190
|
-
// Who works at the step <e>, in words
|
|
191
|
-
|
|
192
|
-
export const quiDe = e => e.quiCourt ?? e.qui.map(nomDuRole).join(' ⇄ ');
|
|
135
|
+
// Who works at the step <e>, in words: its roles' names.
|
|
136
|
+
export const quiDe = e => e.qui.map(nomDuRole).join(' ⇄ ');
|
|
193
137
|
|
|
194
|
-
// The step <e> in words, «
|
|
138
|
+
// The step <e> in words, « 3 Code ».
|
|
195
139
|
export const libelle = e => `${e.numero} ${e.titre}`;
|
|
196
140
|
|
|
197
|
-
// The step of a circuit's state (`etape`, `finale`, its stop `raison`, its
|
|
198
|
-
// `questionnement`, an object or its `objet
|
|
199
|
-
//
|
|
200
|
-
|
|
201
|
-
export const etapeDuCircuit = ({ etape, finale, raison, questionnement, releve }) => {
|
|
141
|
+
// The step of a circuit's state (`etape`, `finale`, its stop `raison`, the work on its plan under
|
|
142
|
+
// way `questionnement`, an object or its `objet`), or null (« integre », an unknown step): the step
|
|
143
|
+
// whose stop or work on the plan it is, else the step of its `etape`.
|
|
144
|
+
export const etapeDuCircuit = ({ etape, finale, raison, questionnement }) => {
|
|
202
145
|
const objet = questionnement?.objet ?? questionnement ?? null;
|
|
203
146
|
return (
|
|
204
147
|
SUITE.find(
|
|
205
|
-
e =>
|
|
206
|
-
(raison && e.arrets?.includes(raison)) ||
|
|
207
|
-
(objet && e.questionnement === objet) ||
|
|
208
|
-
(!raison && !objet && releve && e.releve)
|
|
148
|
+
e => (raison && e.arrets?.includes(raison)) || (objet && e.questionnement === objet)
|
|
209
149
|
) ??
|
|
210
150
|
SUITE.find(
|
|
211
151
|
e =>
|
|
@@ -217,107 +157,102 @@ export const etapeDuCircuit = ({ etape, finale, raison, questionnement, releve }
|
|
|
217
157
|
);
|
|
218
158
|
};
|
|
219
159
|
|
|
220
|
-
// The step where the role agent <role> works,
|
|
221
|
-
// other agent.
|
|
160
|
+
// The step where the role agent <role> works, or null for any other agent.
|
|
222
161
|
export const etapeDuRole = role =>
|
|
223
|
-
role === AUTO ? null : (
|
|
224
|
-
|
|
225
|
-
// The step where a ticket's plan is questioned.
|
|
226
|
-
const QUESTIONNEMENT_DU_PLAN = SUITE.find(e => e.questionnement === 'plan');
|
|
162
|
+
role === AUTO ? null : (SUITE.find(e => e.qui.includes(role)) ?? null);
|
|
227
163
|
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
// sheriffs of Chromium quarantine a flaky test by a rule, not by a judgement. The circuit
|
|
236
|
-
// (scripts/circuit.mjs) tries its lines in their order on each stop, and on the regulator's
|
|
237
|
-
// decision: a gesture the table names, it applies itself, with no regulator; the regulator is
|
|
238
|
-
// launched for what no line settles, and for the line that sends to him. Each line: `genre`, the
|
|
239
|
-
// kind of stop as the circuit reads it in its structured results and its state; `geste`, what
|
|
240
|
-
// follows; `cas`, the case of BPScript 320.3 (2026-10-20) it would have settled, by its stop (A)
|
|
241
|
-
// or its decision (D) in the analysis of that ticket. The gestures (GESTES):
|
|
242
|
-
// - `superviseur`: the circuit ends on the stop, its reason saying why, for the supervisor, with
|
|
243
|
-
// no regulator, and the board shows it under its step after « ⤷ Arrêt · superviseur »;
|
|
244
|
-
// - `a-repasser`: the circuit ends at 75, which the supervisor plays again at rest;
|
|
245
|
-
// - `regulateur`: a session of the regulator settles the stop;
|
|
246
|
-
// - `developpeur-du-composant`: the red goes to the developpeur of the component that owns it,
|
|
247
|
-
// never to the one under way: it waits for that component's checks, or, at the final pass, the
|
|
248
|
-
// circuit relaunches that developpeur (the checks of scripts/circuit.mjs);
|
|
249
|
-
// - `testwriter`: the circuit plays the component again from its testwriter.
|
|
164
|
+
// The gestures of the circuit: what it does itself on a stop a rule settles, as a CI applies its
|
|
165
|
+
// rules (retry, regenerate, skip a job without object) without asking anyone, and as the sheriffs
|
|
166
|
+
// of Chromium quarantine a flaky test by a rule, not by a judgement. Each gesture: `genre`, its
|
|
167
|
+
// name as the circuit writes it at the ticket and in the log; `geste`, what the circuit does;
|
|
168
|
+
// `regle`, the rule that settles it; `cas`, the case of BPScript it settles (the analysis of 320.3,
|
|
169
|
+
// its stop A or its decision D, or that of 320.9). On each one, the circuit writes at the ticket
|
|
170
|
+
// `Circuit · geste : <genre> → <geste> (règle : <regle>)`, and the same line in the ticket's log.
|
|
250
171
|
export const GESTES = [
|
|
251
|
-
'superviseur',
|
|
252
|
-
'a-repasser',
|
|
253
|
-
'regulateur',
|
|
254
|
-
'developpeur-du-composant',
|
|
255
|
-
'testwriter',
|
|
256
|
-
];
|
|
257
|
-
|
|
258
|
-
export const TABLE_DES_ARRETS = [
|
|
259
172
|
{
|
|
260
|
-
// A component the survey of the ticket finds and its title misses (21): the circuit ends on
|
|
261
|
-
// it at 1.1, before any session.
|
|
262
|
-
genre: 'composants-manquants',
|
|
263
|
-
geste: 'superviseur',
|
|
264
|
-
cas: 'A3 : 020-loader mis au titre en cours de route ; A14 : 040-checker, nommé au critère 13 et absent du titre, rouge à la première passe finale',
|
|
265
|
-
},
|
|
266
|
-
{
|
|
267
|
-
// A questioning of the plan that does not converge at 1.2 (22), a disagreement or a fourth
|
|
268
|
-
// round still questioned.
|
|
269
|
-
genre: 'questionnement',
|
|
270
|
-
geste: 'superviseur',
|
|
271
|
-
cas: 'A14 : 040-checker nommé au critère 13 et absent du titre, que le plan questionné aurait relevé ; D15 : une consigne neuve sur le fond, hors du plan',
|
|
272
|
-
},
|
|
273
|
-
{
|
|
274
|
-
// The same stop (its name, step and component) after a RELANCE, the copy and the ticket's
|
|
275
|
-
// description unchanged since that decision.
|
|
276
|
-
genre: 'meme-arret-sans-fait-nouveau',
|
|
277
|
-
geste: 'superviseur',
|
|
278
|
-
cas: 'A8 → A9 : RELANCE --reprendre sans contexte, le même arrêt sur la même copie (D9) ; A11 → A13 : le même rouge de la passe finale trois fois (D13, D14)',
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
// Checks whose failures all depend on a duration under load (verifier's 75), the integration
|
|
282
|
-
// at 75, or the branch kept in the queue.
|
|
283
173
|
genre: 'a-repasser',
|
|
284
|
-
geste: '
|
|
285
|
-
|
|
174
|
+
geste: 'le circuit finit à 75, que le superviseur rejoue au repos par --reprendre',
|
|
175
|
+
regle: 'seul le code 75 du vérificateur dit la charge de la machine',
|
|
176
|
+
cas: 'A12, A17, A18 : un vrai rouge pris pour la charge du processeur (D14, D20, D21)',
|
|
286
177
|
},
|
|
287
178
|
{
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
cas: '
|
|
179
|
+
genre: 'rejeu',
|
|
180
|
+
geste: 'la commande joue une seconde fois',
|
|
181
|
+
regle:
|
|
182
|
+
'une commande des contrôles hors de la passe finale, ou l’intégration, à 75 rejoue une fois avant l’arrêt',
|
|
183
|
+
cas: 'A12 : un contrôle à 75, rejoué avant de conclure à la charge',
|
|
293
184
|
},
|
|
294
185
|
{
|
|
295
|
-
// A red that belongs to another component of the title than the one whose checks run.
|
|
296
|
-
genre: 'rouge-d-un-autre-composant',
|
|
297
|
-
geste: 'developpeur-du-composant',
|
|
298
|
-
cas: 'A4, A6, A8–A10 : la garde des mots de 030-binder rendue aux développeurs de 050, 130 et 900 (D5, D7, D9–D11)',
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
// A developpeur's sheet whose `renvoi` names the testwriter of a component of the title up to
|
|
302
|
-
// his own.
|
|
303
186
|
genre: 'renvoi-au-testwriter',
|
|
304
|
-
geste: 'testwriter',
|
|
187
|
+
geste: 'au testwriter, que la fiche du développeur nomme, puis la preuve et le développeur',
|
|
188
|
+
regle: 'le rouge qui reste est dans les tests du lot (`renvoi` de sa fiche)',
|
|
305
189
|
cas: 'A5, A7 : « Agent : testwriter » non lu, les tests périmés de 050 et de 130 (D6, D8) ; A2 (D2)',
|
|
306
190
|
},
|
|
307
191
|
{
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
192
|
+
genre: 'regeneration',
|
|
193
|
+
geste:
|
|
194
|
+
'à la régénération des références (4.2), puis la passe finale restreinte à ce qu’elle change',
|
|
195
|
+
regle:
|
|
196
|
+
'un rouge de la passe finale est celui d’une référence, même mêlé à d’autres : une que le projet déclare (`grillhouse.references`), ou un fichier que le cadre engendre (l’index des interfaces, les turbo.json, les rapports d’API) ; ou la passe abaisse la dette des gardes (`dette.mjs --abaisser`, depuis ses notes)',
|
|
197
|
+
cas: 'BP 320.9 : 292 min autour des références, dont 163 min d’attente pour régénérer à la main l’index des interfaces, le plafond et l’empreinte, des rouges de références mêlés à d’autres',
|
|
312
198
|
},
|
|
313
199
|
{
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
cas: '
|
|
200
|
+
genre: 'rien-a-livrer',
|
|
201
|
+
geste: 'aux contrôles, qui jugent le lot',
|
|
202
|
+
regle:
|
|
203
|
+
'un développeur qui ne change aucun fichier du plan n’a rien à livrer quand les contrôles sont verts ; rouges, l’arrêt monte (sans-livraison)',
|
|
204
|
+
cas: 'BP 320.9 : 995-tools n’a rien à livrer, 4 montées et 49 min (B5)',
|
|
319
205
|
},
|
|
320
206
|
];
|
|
321
207
|
|
|
322
|
-
// The
|
|
323
|
-
export const gesteDe = genre =>
|
|
208
|
+
// The gesture of name <genre>, or null.
|
|
209
|
+
export const gesteDe = genre => GESTES.find(g => g.genre === genre) ?? null;
|
|
210
|
+
|
|
211
|
+
// Who answers a question of the circuit: the supervisor, or the owner, whose question the
|
|
212
|
+
// supervisor carries.
|
|
213
|
+
export const SUPERVISEUR = 'superviseur';
|
|
214
|
+
export const RESPONSABLE = 'responsable';
|
|
215
|
+
|
|
216
|
+
// The commands by which the supervisor answers a question (scripts/circuit.mjs): resume, extend
|
|
217
|
+
// the plan, stop.
|
|
218
|
+
const REPONSES =
|
|
219
|
+
'Le superviseur répond par une commande du circuit : `--reprendre` (avec `--contexte`) ou `--depuis <testwriter|developpeur>` (avec `--contexte`), `--etendre <paquet>` (le plan gagne ce paquet, puis l’étape en cours reprend), ou `--arreter`.';
|
|
220
|
+
|
|
221
|
+
// The question of each stop no gesture settles, as a CI calls a person only for what no rule
|
|
222
|
+
// settles (the approval of a review): every stop of ARRETS but « a-repasser », a gesture. The
|
|
223
|
+
// circuit ends on the stop, its state carrying the question (`question`: `{ arret, fait, piece,
|
|
224
|
+
// question, qui }`: the fact, its piece, file:line or command and output, the question and who must
|
|
225
|
+
// answer it), for the supervisor, who answers by a command of the circuit and carries to the owner
|
|
226
|
+
// what is his (`qui` responsable: the reviewer's question on a real word of the language).
|
|
227
|
+
export const MONTEES = Object.fromEntries(
|
|
228
|
+
Object.entries({
|
|
229
|
+
lancement:
|
|
230
|
+
'Le lanceur s’arrête avant la séance : la machine se répare-t-elle, pour reprendre ?',
|
|
231
|
+
bloqué:
|
|
232
|
+
'La séance n’a plus bougé, et le circuit l’a arrêtée : reprendre l’étape, ou arrêter le circuit ?',
|
|
233
|
+
'sans-fiche':
|
|
234
|
+
'La séance finit deux fois sans fiche conforme : reprendre l’étape, ou arrêter le circuit ?',
|
|
235
|
+
preuve:
|
|
236
|
+
'La troisième preuve du rouge refuse le lot de tests : quel contexte donner au testwriter, ou le plan doit-il changer ?',
|
|
237
|
+
controles:
|
|
238
|
+
'Un rouge reste, que le circuit ne rend pas au développeur (hors du plan, sans fichier, à arbitrer), ou que trois séances n’ont pas levé : avec quel contexte le lever, ou le plan doit-il s’étendre ?',
|
|
239
|
+
'sans-livraison':
|
|
240
|
+
'Le développeur ne change rien et le rouge reste : avec quel contexte le lever, ou le plan doit-il changer ?',
|
|
241
|
+
'relecture-arret':
|
|
242
|
+
'La relecture ne rend pas le lot à un agent (un constat sans destinataire valide, un critère en cause, ou la troisième relecture rendue) : que devient le plan, et qui reprend ?',
|
|
243
|
+
integration:
|
|
244
|
+
'L’intégration refuse le lot, ou la file rouvre le ticket : que corrige le lot, et qui le reprend ?',
|
|
245
|
+
'hors-portee':
|
|
246
|
+
'L’agent se dit bloqué hors de sa portée : le plan s’étend-il au paquet qu’il nomme, ou un autre agent lève-t-il le reste ?',
|
|
247
|
+
besoin: 'Une réponse manque pour avancer : laquelle ?',
|
|
248
|
+
questionnement:
|
|
249
|
+
'Des questions du plan restent ouvertes après la réponse de l’explorateur : le plan change-t-il (`bd update`), ou reste-t-il tel quel ? `--reprendre` le fait passer tel qu’il est alors.',
|
|
250
|
+
references:
|
|
251
|
+
'La régénération des références change une référence du projet que le plan ne nomme pas, un fichier qu’aucune référence n’écrit, ou sa commande échoue : le plan les nomme-t-il, ou qui corrige le lot ?',
|
|
252
|
+
'hors-plan':
|
|
253
|
+
'La séance écrit hors du plan du ticket : le plan s’étend-il à ce paquet (`--etendre`), ou l’écriture est-elle refusée (`--reprendre` avec son contexte) ?',
|
|
254
|
+
}).map(([arret, question]) => [arret, { question: `${question} ${REPONSES}`, qui: SUPERVISEUR }])
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
// The question of the stop <arret>, `{ question, qui }`, or null for a gesture.
|
|
258
|
+
export const monteeDe = arret => MONTEES[arret] ?? null;
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
// - Each red guard is named with its code at the end; the exit code is 1 when one guard is red,
|
|
10
10
|
// 0 when all are green.
|
|
11
11
|
// - While the run names its results directory (`GRILLHOUSE_RESULTATS`, scripts/resultats.mjs),
|
|
12
|
-
// each guard writes its findings there in SARIF; a red guard that wrote no finding
|
|
13
|
-
// written for it, without location, its name (its
|
|
14
|
-
// a red no reader can place.
|
|
12
|
+
// each guard writes its findings there in SARIF; a red guard that wrote no finding (a note of
|
|
13
|
+
// the debt, `a-elaguer`, is none) has one written for it, without location, its name (its
|
|
14
|
+
// script's, without extension) and its code: a red no reader can place.
|
|
15
15
|
// - The build is not among them: Turborepo builds before this task (turbo.json).
|
|
16
16
|
import { spawnSync } from 'node:child_process';
|
|
17
17
|
import path from 'node:path';
|
|
18
18
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
19
|
-
import { ecrireSarif, lireSarif, RESULTATS } from './resultats.mjs';
|
|
19
|
+
import { A_ELAGUER, ecrireSarif, lireSarif, RESULTATS } from './resultats.mjs';
|
|
20
20
|
|
|
21
21
|
// A script of the package, beside this one, by its name.
|
|
22
22
|
const ici = nom => fileURLToPath(new URL(nom, import.meta.url));
|
|
@@ -47,13 +47,15 @@ export function jouerLesGardes({
|
|
|
47
47
|
dire = l => process.stdout.write(`${l}\n`),
|
|
48
48
|
}) {
|
|
49
49
|
const rouges = [];
|
|
50
|
+
// The findings under the results directory, the notes of the debt left out.
|
|
51
|
+
const nombre = () => lireSarif(env[RESULTATS]).constats.filter(k => k.genre !== A_ELAGUER).length;
|
|
50
52
|
for (const garde of gardes) {
|
|
51
|
-
const avant = env[RESULTATS] ?
|
|
53
|
+
const avant = env[RESULTATS] ? nombre() : 0;
|
|
52
54
|
const r = spawnSync(process.execPath, garde, { cwd: racine, env, stdio: 'inherit' });
|
|
53
55
|
if (r.status === 0) continue;
|
|
54
56
|
const code = `code ${r.status ?? r.signal}`;
|
|
55
57
|
rouges.push(`${libelle(garde)} (${code})`);
|
|
56
|
-
if (env[RESULTATS] &&
|
|
58
|
+
if (env[RESULTATS] && nombre() === avant) {
|
|
57
59
|
ecrireSarif({
|
|
58
60
|
garde: nomDeGarde(garde),
|
|
59
61
|
racine,
|
|
@@ -13,7 +13,14 @@
|
|
|
13
13
|
// - The migrations first (scripts/migrations.mjs): each migration of the package newer than the
|
|
14
14
|
// version the project recorded (`grillhouse.version` of its package.json; none recorded, every
|
|
15
15
|
// migration), in the order of their versions; each is replayable without effect, and the report
|
|
16
|
-
// names each one that changed something, with what it changed.
|
|
16
|
+
// names each one that changed something, with what it changed. What a migration leaves to the
|
|
17
|
+
// project (a copy of the frame the project modified, scripts/migrations/0.23.2-copies-du-cadre.mjs)
|
|
18
|
+
// is written on the error stream, with the command that does it, and the exit code is non-zero;
|
|
19
|
+
// the project keeps the version it recorded, so that the next update plays that migration again.
|
|
20
|
+
// Last, after the update and the regeneration, what stays to the project (`restes` of a
|
|
21
|
+
// migration played, scripts/migrations.mjs: in 0.24.0, a file that still calls a former copy of
|
|
22
|
+
// the frame) is reported on the standard output, « reste au projet », with no effect on the exit
|
|
23
|
+
// code nor on the version recorded.
|
|
17
24
|
// - The frame copies no file into a project: its scripts are the package's, its skills, agents,
|
|
18
25
|
// hooks of Claude Code, common charter and meta-frame the plugin's, which the package carries
|
|
19
26
|
// (scripts/cadre.mjs): the frame arrives in one piece, at the version npm installs.
|
|
@@ -31,7 +38,8 @@
|
|
|
31
38
|
// the frame's status line (`ligne-etat`, whatever its former form); a status line of the
|
|
32
39
|
// project's own stays. The settings keep their other keys, in their order.
|
|
33
40
|
// - `package.json`, when there is one: the version of the frame it is brought to
|
|
34
|
-
// (`grillhouse.version`, the package's version
|
|
41
|
+
// (`grillhouse.version`, the package's version once no migration leaves anything to do), the
|
|
42
|
+
// frame's npm scripts (`tableau`,
|
|
35
43
|
// `grillhouse:maj`), its `prepare` beginning with `grillhouse hooks` (the frame's git hooks at
|
|
36
44
|
// each `npm install`, as Husky's `prepare`; a `prepare` of the project's own follows it,
|
|
37
45
|
// `grillhouse hooks && …`), and `grillhouse:gardes` (scripts/gardes-du-cadre.mjs, the frame's controls), `grillhouse:dette:inscrire` and
|
|
@@ -120,7 +128,7 @@ import semver from 'semver';
|
|
|
120
128
|
import { CADRE, VERSION } from './cadre.mjs';
|
|
121
129
|
import { poserCrochets } from './crochets.mjs';
|
|
122
130
|
import { installerGreffons } from './greffons.mjs';
|
|
123
|
-
import { migrer } from './migrations.mjs';
|
|
131
|
+
import { migrer, restesAuProjet } from './migrations.mjs';
|
|
124
132
|
import { paquets } from './paquets.mjs';
|
|
125
133
|
|
|
126
134
|
const SCRIPTS = {
|
|
@@ -285,9 +293,10 @@ export function versionDuProjet(projet) {
|
|
|
285
293
|
|
|
286
294
|
/**
|
|
287
295
|
* Brings the project at `projet` to the frame's files at `source` (CADRE, scripts/cadre.mjs; a
|
|
288
|
-
* trial's own in the tests)
|
|
296
|
+
* trial's own in the tests); <inscrite> is the version it records (the package's; null records
|
|
297
|
+
* none, the project keeping its own). Returns what changed.
|
|
289
298
|
*/
|
|
290
|
-
export function mettreAJour(projet, source) {
|
|
299
|
+
export function mettreAJour(projet, source, { inscrite = VERSION } = {}) {
|
|
291
300
|
const bilan = {
|
|
292
301
|
dependances: [],
|
|
293
302
|
test: null,
|
|
@@ -301,7 +310,7 @@ export function mettreAJour(projet, source) {
|
|
|
301
310
|
const pkg = path.join(projet, 'package.json');
|
|
302
311
|
if (existsSync(pkg)) {
|
|
303
312
|
const p = lireJson(pkg, {});
|
|
304
|
-
p.grillhouse = { ...(p.grillhouse ?? {}), version:
|
|
313
|
+
if (inscrite !== null) p.grillhouse = { ...(p.grillhouse ?? {}), version: inscrite };
|
|
305
314
|
const pkgSource = lireJson(path.join(source, GABARIT), {});
|
|
306
315
|
const gardes = pkgSource.scripts?.['grillhouse:gardes'];
|
|
307
316
|
p.scripts = { ...(p.scripts ?? {}), ...SCRIPTS };
|
|
@@ -497,18 +506,31 @@ if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) {
|
|
|
497
506
|
process.exitCode = 2;
|
|
498
507
|
} else {
|
|
499
508
|
const projet = process.cwd();
|
|
500
|
-
const
|
|
501
|
-
const
|
|
509
|
+
const depuis = versionDuProjet(projet);
|
|
510
|
+
const migrations = migrer(projet, depuis);
|
|
511
|
+
const resteAFaire = migrations.some(m => m.aFaire.length > 0);
|
|
512
|
+
const b = mettreAJour(projet, CADRE, resteAFaire ? { inscrite: null } : {});
|
|
502
513
|
process.stdout.write(`Cadre ${VERSION}.\n`);
|
|
503
|
-
for (const { version, nom, lignes } of migrations) {
|
|
514
|
+
for (const { version, nom, lignes, aFaire } of migrations) {
|
|
504
515
|
process.stdout.write(
|
|
505
516
|
`Migration ${version} (${nom}) :\n${lignes.map(l => `- ${l}\n`).join('')}`
|
|
506
517
|
);
|
|
518
|
+
if (aFaire.length > 0) {
|
|
519
|
+
process.stderr.write(
|
|
520
|
+
`Migration ${version} (${nom}), à faire :\n${aFaire.map(l => `- ${l}\n`).join('')}`
|
|
521
|
+
);
|
|
522
|
+
process.exitCode = 1;
|
|
523
|
+
}
|
|
507
524
|
}
|
|
508
525
|
process.stdout.write(rapport(b));
|
|
509
526
|
for (const l of [...regenerer(projet), ...installerGreffons(projet)]) {
|
|
510
527
|
process.stderr.write(`${l}\n`);
|
|
511
528
|
process.exitCode = 1;
|
|
512
529
|
}
|
|
530
|
+
for (const { version, nom, lignes } of restesAuProjet(projet, depuis)) {
|
|
531
|
+
process.stdout.write(
|
|
532
|
+
`Migration ${version} (${nom}), reste au projet :\n${lignes.map(l => `- ${l}\n`).join('')}`
|
|
533
|
+
);
|
|
534
|
+
}
|
|
513
535
|
}
|
|
514
536
|
}
|
|
@@ -36,6 +36,7 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
|
36
36
|
import path from 'node:path';
|
|
37
37
|
import { pathToFileURL } from 'node:url';
|
|
38
38
|
import { composants, declares } from './consommateurs.mjs';
|
|
39
|
+
import { lireLaListe } from './enveloppe/paquets-du-plan.mjs';
|
|
39
40
|
import { DEBUT, FIN, marques } from './interfaces-contre-code.mjs';
|
|
40
41
|
import { ecrireSarif } from './resultats.mjs';
|
|
41
42
|
|
|
@@ -179,7 +180,10 @@ function rend(racine, rel) {
|
|
|
179
180
|
// What the components before <composant> publish, as the section the launcher writes after the
|
|
180
181
|
// instruction of a role agent (scripts/enveloppe/lancer.sh). <composant> is the component's path
|
|
181
182
|
// in the repository at <racine> (`packages/a`, `src/parser`), or `.` for a copy of the whole
|
|
182
|
-
// repository, which the section points to the index of the interfaces
|
|
183
|
+
// repository, which the section points to the index of the interfaces; or the plan of a session,
|
|
184
|
+
// several paths in the form of the envelope's list (`packages/a:packages/b`, `lireLaListe`), one
|
|
185
|
+
// part of the section per package of the plan, its providers under it, as one session works the
|
|
186
|
+
// whole plan of a ticket (grillhouse-3uv.95.6). Its providers are the
|
|
183
187
|
// components whose `## Consommateurs` section names it; for each, its line in the index of the
|
|
184
188
|
// interfaces (its heading, its first sentence, its interface), the names of the elements its
|
|
185
189
|
// `## Consommateurs` line declares for the component, never their sentence, which the index of the
|
|
@@ -187,7 +191,23 @@ function rend(racine, rel) {
|
|
|
187
191
|
// or one line saying the frame or the rubric is missing. A declaration of `*`, an import of the
|
|
188
192
|
// whole component, names no element: its line says the elements are in the index. Each interface
|
|
189
193
|
// and each frame is read once.
|
|
194
|
+
/** @param {string} racine @param {string} composant @returns {string} */
|
|
190
195
|
export function publie(racine, composant) {
|
|
196
|
+
const plan = lireLaListe(composant);
|
|
197
|
+
if (plan.length > 1) {
|
|
198
|
+
const parties = plan.map(c =>
|
|
199
|
+
publie(racine, c)
|
|
200
|
+
.split('\n')
|
|
201
|
+
.slice(2)
|
|
202
|
+
.map(l => (l.startsWith('### ') ? `#${l}` : l))
|
|
203
|
+
);
|
|
204
|
+
return [
|
|
205
|
+
TITRE_PUBLIE,
|
|
206
|
+
'',
|
|
207
|
+
'Ton plan porte plusieurs paquets : pour chacun, ce que publient les composants dont il dépend.',
|
|
208
|
+
...plan.flatMap((c, i) => ['', `### Pour \`${path.basename(c)}\``, '', ...parties[i]]),
|
|
209
|
+
].join('\n');
|
|
210
|
+
}
|
|
191
211
|
if (composant === '.') {
|
|
192
212
|
return [
|
|
193
213
|
TITRE_PUBLIE,
|