@sublang/playbook 11.0.0 → 12.0.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/docs/cli.md +9 -6
- package/docs/configuration.md +15 -1
- package/package.json +22 -3
- package/reference/sdlc/code.playbook/code.fsm.d.ts +22 -19
- package/reference/sdlc/code.playbook/code.fsm.js +116 -52
- package/reference/sdlc/code.playbook/code.fsm.ts +149 -64
- package/reference/sdlc/code.playbook/code.gears.md +40 -20
- package/reference/sdlc/code.playbook/code.playbook.js +23 -2
- package/reference/sdlc/code.playbook/code.playbook.ts +23 -2
- package/reference/sdlc/code.playbook/playbook.config.template.yaml +18 -2
- package/reference/sdlc/decide.playbook/decide.fsm.d.ts +13 -6
- package/reference/sdlc/decide.playbook/decide.fsm.js +54 -27
- package/reference/sdlc/decide.playbook/decide.fsm.ts +68 -29
- package/reference/sdlc/decide.playbook/decide.gears.md +25 -19
- package/reference/sdlc/decide.playbook/decide.playbook.js +11 -3
- package/reference/sdlc/decide.playbook/decide.playbook.ts +11 -3
- package/reference/sdlc/decide.playbook/decide.registry.js +1 -1
- package/reference/sdlc/decide.playbook/decide.registry.ts +1 -1
- package/reference/sdlc/dev.md +52 -0
- package/reference/sdlc/dev.playbook/dev.fsm.d.ts +261 -0
- package/reference/sdlc/dev.playbook/dev.fsm.js +723 -0
- package/reference/sdlc/dev.playbook/dev.fsm.ts +988 -0
- package/reference/sdlc/dev.playbook/dev.gears.md +91 -0
- package/reference/sdlc/dev.playbook/dev.playbook.d.ts +21 -0
- package/reference/sdlc/dev.playbook/dev.playbook.js +143 -0
- package/reference/sdlc/dev.playbook/dev.playbook.ts +246 -0
- package/reference/sdlc/dev.playbook/dev.registry.d.ts +40 -0
- package/reference/sdlc/dev.playbook/dev.registry.js +64 -0
- package/reference/sdlc/dev.playbook/dev.registry.ts +120 -0
- package/reference/sdlc/review.playbook/review.fsm.d.ts +15 -2
- package/reference/sdlc/review.playbook/review.fsm.js +77 -27
- package/reference/sdlc/review.playbook/review.fsm.ts +96 -30
- package/reference/sdlc/review.playbook/review.gears.md +52 -26
- package/reference/sdlc/review.playbook/review.playbook.js +17 -7
- package/reference/sdlc/review.playbook/review.playbook.ts +17 -7
- package/reference/sdlc/review.playbook/review.registry.js +1 -1
- package/reference/sdlc/review.playbook/review.registry.ts +1 -1
- package/slc/link.md +12 -5
- package/slc/text2gears.md +3 -0
- package/src/xstate-playbook-runtime.js +5 -2
- package/src/xstate-playbook-runtime.ts +5 -2
- package/src/xstate-runtime.js +13 -1
- package/src/xstate-runtime.ts +13 -1
|
@@ -44,7 +44,6 @@ export type PlayerInput = {
|
|
|
44
44
|
readonly callerInput: string;
|
|
45
45
|
readonly runResults: string;
|
|
46
46
|
readonly irNumber?: string;
|
|
47
|
-
readonly irTask?: string;
|
|
48
47
|
readonly pendingBossQuestion?: PendingBossQuestion;
|
|
49
48
|
readonly bossReply?: string;
|
|
50
49
|
};
|
|
@@ -60,18 +59,20 @@ export type PlayerOutput =
|
|
|
60
59
|
readonly coderOutput: string;
|
|
61
60
|
readonly latestCommit: string;
|
|
62
61
|
readonly irNumber: string;
|
|
63
|
-
readonly irTask: string;
|
|
64
62
|
}
|
|
65
63
|
| {
|
|
66
64
|
readonly guard: 'moreTasks';
|
|
67
65
|
readonly coderOutput: string;
|
|
68
66
|
readonly latestCommit: string;
|
|
67
|
+
readonly irNumber: string;
|
|
69
68
|
readonly irTask: string;
|
|
70
69
|
}
|
|
71
70
|
| {
|
|
72
71
|
readonly guard: 'finalTask';
|
|
73
72
|
readonly coderOutput: string;
|
|
74
73
|
readonly latestCommit: string;
|
|
74
|
+
readonly irNumber: string;
|
|
75
|
+
readonly irTask: string;
|
|
75
76
|
}
|
|
76
77
|
| {
|
|
77
78
|
readonly guard: 'needsBossReply';
|
|
@@ -86,8 +87,13 @@ export type PlaybookInput = {
|
|
|
86
87
|
};
|
|
87
88
|
|
|
88
89
|
export type ReviewOutput = {
|
|
89
|
-
readonly approvedCommit: 'latest';
|
|
90
90
|
readonly noUnsettledFindings: true;
|
|
91
|
+
/**
|
|
92
|
+
* Exact repository revision at which the review scope was evaluated:
|
|
93
|
+
* the last review-fix commit when one landed, otherwise the clean
|
|
94
|
+
* round's receipt-observed HEAD (DR-045). Always present.
|
|
95
|
+
*/
|
|
96
|
+
readonly evaluatedRevision: string;
|
|
91
97
|
};
|
|
92
98
|
|
|
93
99
|
export type CompactError = {
|
|
@@ -98,17 +104,17 @@ export type CompactError = {
|
|
|
98
104
|
export type CodePlaybookOutput =
|
|
99
105
|
| {
|
|
100
106
|
readonly status: 'complete';
|
|
101
|
-
/** Exact identity of the
|
|
107
|
+
/** Exact identity of the last CODE-owned commit. */
|
|
102
108
|
readonly lastCodeCommit: string;
|
|
103
|
-
/** Exact
|
|
104
|
-
readonly
|
|
109
|
+
/** Exact repository revision the final passing review evaluated. */
|
|
110
|
+
readonly finalEvaluatedRevision: string;
|
|
111
|
+
/** Every phase's review passed with no unsettled findings. */
|
|
112
|
+
readonly allReviewsPassed: true;
|
|
105
113
|
}
|
|
106
114
|
| {
|
|
107
115
|
readonly status: 'review-failed';
|
|
108
|
-
/** Exact identity of the
|
|
116
|
+
/** Exact identity of the last CODE-owned commit. */
|
|
109
117
|
readonly lastCodeCommit: string;
|
|
110
|
-
/** Exact Coder final text produced after that commit. */
|
|
111
|
-
readonly lastCodeOutput: string;
|
|
112
118
|
readonly error: CompactError;
|
|
113
119
|
};
|
|
114
120
|
|
|
@@ -123,7 +129,7 @@ export type CodingContext = {
|
|
|
123
129
|
readonly latestCommit?: string;
|
|
124
130
|
readonly irNumber?: string;
|
|
125
131
|
readonly irTask?: string;
|
|
126
|
-
readonly
|
|
132
|
+
readonly evaluatedRevision?: string;
|
|
127
133
|
readonly phase?: CodePhase;
|
|
128
134
|
readonly completion?: 'complete' | 'review-failed';
|
|
129
135
|
readonly reviewError?: CompactError;
|
|
@@ -140,69 +146,86 @@ export type CodingEvent =
|
|
|
140
146
|
readonly questionId?: 'runFirstPhase' | 'runIrTask';
|
|
141
147
|
};
|
|
142
148
|
|
|
149
|
+
const APPENDED_PHASE_PROMPT = [
|
|
150
|
+
'Keep to the original intent and follow what it asks.',
|
|
151
|
+
'Do not re-run tests or builds whose inputs have not changed since any previous reported run.',
|
|
152
|
+
"Make the phase's minimal changes and then one new commit, following @specs/packages/git.md; never amend an existing commit.",
|
|
153
|
+
'Make the commit message explain concisely what changed and why, including relevant verification.',
|
|
154
|
+
'Identify every new commit you make.',
|
|
155
|
+
'Coder is <coder-llm>.',
|
|
156
|
+
];
|
|
157
|
+
|
|
143
158
|
const FIRST_PHASE_PROMPT = [
|
|
144
159
|
'> <caller-input>',
|
|
145
160
|
'> <run-results>',
|
|
146
161
|
'',
|
|
147
|
-
'
|
|
148
|
-
'If
|
|
149
|
-
'
|
|
162
|
+
'First determine whether the coding request starts a new coding intent or continues an existing IR with unfinished work.',
|
|
163
|
+
'If the request may continue an existing IR but does not identify it unambiguously, ask Boss before changing files.',
|
|
164
|
+
'',
|
|
165
|
+
'For a new coding intent, assess whether it can be completed well in one commit.',
|
|
166
|
+
'If it can, implement and test it, update the affected specs, and ensure @specs/map.md remains accurate.',
|
|
167
|
+
'If it cannot, decompose it into tasks sized to exactly one commit each, add a new IR under @specs/intents, and do not implement any IR task in this phase.',
|
|
150
168
|
'Plan affected spec updates before, with, or after their corresponding code changes, either as standalone IR tasks or as explicit work within related tasks.',
|
|
151
169
|
'',
|
|
170
|
+
'For an existing IR, read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.',
|
|
171
|
+
'Do not implement a later task in this phase.',
|
|
172
|
+
"Mark the IR's progress and deliverables when relevant.",
|
|
173
|
+
'If the IR will be finished after this phase, double-check that all acceptance criteria are met.',
|
|
174
|
+
'',
|
|
152
175
|
'Consult @specs/map.md for relevant context and @specs/meta.md for spec requirements, if needed.',
|
|
153
176
|
'',
|
|
154
|
-
|
|
155
|
-
"Make the phase's minimal changes and then one new commit, following @specs/packages/git.md; never amend an existing commit.",
|
|
156
|
-
'Make the commit message explain concisely what changed and why, including relevant verification.',
|
|
157
|
-
'Coder is <coder-llm>; format the model token in conventional human form.',
|
|
177
|
+
...APPENDED_PHASE_PROMPT,
|
|
158
178
|
].join('\n');
|
|
159
179
|
|
|
160
180
|
const IR_TASK_PROMPT = [
|
|
161
|
-
'> <
|
|
181
|
+
'> <caller-input>',
|
|
182
|
+
'> <ir-number>',
|
|
162
183
|
'> <run-results>',
|
|
163
184
|
'',
|
|
164
|
-
'Read IR
|
|
185
|
+
'Read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.',
|
|
165
186
|
'Do not implement a later task in this phase.',
|
|
166
187
|
"Mark the IR's progress and deliverables when relevant.",
|
|
167
188
|
'If the IR will be finished after this phase, double-check that all acceptance criteria are met.',
|
|
168
189
|
'',
|
|
169
|
-
|
|
170
|
-
"Make the phase's minimal changes and then one new commit, following @specs/packages/git.md; never amend an existing commit.",
|
|
171
|
-
'Make the commit message explain concisely what changed and why, including relevant verification.',
|
|
172
|
-
'Coder is <coder-llm>; format the model token in conventional human form.',
|
|
190
|
+
...APPENDED_PHASE_PROMPT,
|
|
173
191
|
].join('\n');
|
|
174
192
|
|
|
193
|
+
const NEEDS_BOSS_REPLY_RESULT =
|
|
194
|
+
"The acting agent's prose surfaces a clarifying question for Boss that the agent cannot answer alone. Output shall include `question: <verbatim question text from the acting agent's prose>`.";
|
|
195
|
+
|
|
175
196
|
const FIRST_PHASE_RESULTS = {
|
|
176
197
|
directCommit:
|
|
177
198
|
'Coder completed and committed the direct implementation phase. Output shall include `coderOutput: <verbatim final text>` and `latestCommit: <commit identity>`.',
|
|
178
199
|
irCommit:
|
|
179
|
-
'Coder created and committed a new IR without implementing an IR task. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`,
|
|
180
|
-
|
|
181
|
-
|
|
200
|
+
'Coder created and committed a new IR without implementing an IR task. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, and `irNumber` identifying the created IR.',
|
|
201
|
+
moreTasks:
|
|
202
|
+
'Coder continued an existing IR, completed and committed exactly its next unfinished task, and at least one task remains. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, `irNumber` identifying the continued IR, and `irTask` naming the implemented task.',
|
|
203
|
+
finalTask:
|
|
204
|
+
'Coder continued an existing IR and completed and committed its final task. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, `irNumber` identifying the continued IR, and `irTask` naming the implemented task.',
|
|
205
|
+
needsBossReply: NEEDS_BOSS_REPLY_RESULT,
|
|
182
206
|
} as const;
|
|
183
207
|
|
|
184
208
|
const IR_TASK_RESULTS = {
|
|
185
209
|
moreTasks:
|
|
186
|
-
|
|
210
|
+
"Coder completed and committed exactly the IR's next unfinished task and at least one task remains. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, `irNumber` identifying the continued IR, and `irTask` naming the implemented task.",
|
|
187
211
|
finalTask:
|
|
188
|
-
|
|
189
|
-
needsBossReply:
|
|
190
|
-
"The acting agent's prose surfaces a clarifying question for Boss that the agent cannot answer alone. Output shall include `question: <verbatim question text from the acting agent's prose>`.",
|
|
212
|
+
"Coder completed and committed the IR's final task. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, `irNumber` identifying the continued IR, and `irTask` naming the implemented task.",
|
|
213
|
+
needsBossReply: NEEDS_BOSS_REPLY_RESULT,
|
|
191
214
|
} as const;
|
|
192
215
|
|
|
193
216
|
const STATE_DESCRIPTIONS = {
|
|
194
217
|
ready: 'Waiting for a coding intent.',
|
|
195
218
|
runFirstPhase:
|
|
196
|
-
'Coder is
|
|
219
|
+
'Coder is running the first coding phase: a direct implementation, a new intent record, or an existing intent-record task.',
|
|
197
220
|
reviewFirstCommit:
|
|
198
|
-
'The REVIEW playbook is checking the
|
|
221
|
+
'The REVIEW playbook is checking the direct or new-IR phase commit.',
|
|
199
222
|
runIrTask: 'Coder is implementing exactly one unfinished intent-record task.',
|
|
200
223
|
reviewIrTask: 'The REVIEW playbook is checking the latest task commit.',
|
|
201
224
|
awaitBossReply: 'Waiting for Boss to answer Coder.',
|
|
202
225
|
failed: 'The coding workflow failed and is waiting for a new coding intent.',
|
|
203
226
|
reportedReviewFailure:
|
|
204
227
|
'The coding workflow reported a REVIEW failure and the last code-owned commit.',
|
|
205
|
-
done:
|
|
228
|
+
done: "The coding workflow completed after every phase's REVIEW passed with no unsettled findings.",
|
|
206
229
|
} as const;
|
|
207
230
|
|
|
208
231
|
function playbookMeta<StateId extends keyof typeof STATE_DESCRIPTIONS>(
|
|
@@ -251,6 +274,14 @@ function hasCommittedOutput(event: unknown): boolean {
|
|
|
251
274
|
);
|
|
252
275
|
}
|
|
253
276
|
|
|
277
|
+
function hasIrTaskOutput(event: unknown): boolean {
|
|
278
|
+
return (
|
|
279
|
+
hasCommittedOutput(event) &&
|
|
280
|
+
outputString(event, 'irNumber') !== undefined &&
|
|
281
|
+
outputString(event, 'irTask') !== undefined
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
|
|
254
285
|
function isDirectCommit({ event }: { event: unknown }): boolean {
|
|
255
286
|
return (
|
|
256
287
|
outputGuard(event, 'directCommit') &&
|
|
@@ -262,23 +293,21 @@ function isIrCommit({ event }: { event: unknown }): boolean {
|
|
|
262
293
|
return (
|
|
263
294
|
outputGuard(event, 'irCommit') &&
|
|
264
295
|
hasCommittedOutput(event) &&
|
|
265
|
-
outputString(event, 'irNumber') !== undefined
|
|
266
|
-
outputString(event, 'irTask') !== undefined
|
|
296
|
+
outputString(event, 'irNumber') !== undefined
|
|
267
297
|
);
|
|
268
298
|
}
|
|
269
299
|
|
|
270
300
|
function isMoreTasks({ event }: { event: unknown }): boolean {
|
|
271
301
|
return (
|
|
272
302
|
outputGuard(event, 'moreTasks') &&
|
|
273
|
-
|
|
274
|
-
outputString(event, 'irTask') !== undefined
|
|
303
|
+
hasIrTaskOutput(event)
|
|
275
304
|
);
|
|
276
305
|
}
|
|
277
306
|
|
|
278
307
|
function isFinalTask({ event }: { event: unknown }): boolean {
|
|
279
308
|
return (
|
|
280
309
|
outputGuard(event, 'finalTask') &&
|
|
281
|
-
|
|
310
|
+
hasIrTaskOutput(event)
|
|
282
311
|
);
|
|
283
312
|
}
|
|
284
313
|
|
|
@@ -294,12 +323,19 @@ function reviewOutput(event: unknown): unknown {
|
|
|
294
323
|
}
|
|
295
324
|
|
|
296
325
|
function isReviewApprovedValue(value: unknown): value is ReviewOutput {
|
|
326
|
+
if (!isRecord(value)) return false;
|
|
327
|
+
if (
|
|
328
|
+
Reflect.ownKeys(value).some(
|
|
329
|
+
(key) =>
|
|
330
|
+
typeof key !== 'string' ||
|
|
331
|
+
(key !== 'noUnsettledFindings' && key !== 'evaluatedRevision'),
|
|
332
|
+
)
|
|
333
|
+
) {
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
297
336
|
return (
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
['approvedCommit', 'noUnsettledFindings'].sort().join('\0') &&
|
|
301
|
-
value.approvedCommit === 'latest' &&
|
|
302
|
-
value.noUnsettledFindings === true
|
|
337
|
+
value.noUnsettledFindings === true &&
|
|
338
|
+
isNonEmptyString(value.evaluatedRevision)
|
|
303
339
|
);
|
|
304
340
|
}
|
|
305
341
|
|
|
@@ -485,17 +521,27 @@ function quoteRelay(label: string, value: string): string {
|
|
|
485
521
|
);
|
|
486
522
|
}
|
|
487
523
|
|
|
488
|
-
function
|
|
524
|
+
function reviewScopeLine(context: CodingContext): string {
|
|
525
|
+
return (
|
|
526
|
+
`> Review scope: the commit ${context.latestCommit ?? ''} ` +
|
|
527
|
+
'from this coding phase and its resulting repository state.'
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function newIntentReviewText(context: CodingContext): string {
|
|
489
532
|
return [
|
|
490
|
-
quoteRelay('
|
|
533
|
+
quoteRelay('Original intent', context.callerInput ?? ''),
|
|
534
|
+
reviewScopeLine(context),
|
|
491
535
|
quoteRelay('Coder output', context.coderOutput ?? ''),
|
|
492
536
|
].join('\n');
|
|
493
537
|
}
|
|
494
538
|
|
|
495
539
|
function irTaskReviewText(context: CodingContext): string {
|
|
496
540
|
return [
|
|
497
|
-
quoteRelay('
|
|
541
|
+
quoteRelay('Original intent', context.callerInput ?? ''),
|
|
542
|
+
reviewScopeLine(context),
|
|
498
543
|
quoteRelay('Coder output', context.coderOutput ?? ''),
|
|
544
|
+
quoteRelay('Current IR task', context.irTask ?? ''),
|
|
499
545
|
].join('\n');
|
|
500
546
|
}
|
|
501
547
|
|
|
@@ -556,7 +602,7 @@ const machineSetup = setup({
|
|
|
556
602
|
latestCommit: undefined,
|
|
557
603
|
irNumber: undefined,
|
|
558
604
|
irTask: undefined,
|
|
559
|
-
|
|
605
|
+
evaluatedRevision: undefined,
|
|
560
606
|
phase: undefined,
|
|
561
607
|
completion: undefined,
|
|
562
608
|
reviewError: undefined,
|
|
@@ -576,8 +622,7 @@ const machineSetup = setup({
|
|
|
576
622
|
coderOutput: outputString(event, 'coderOutput'),
|
|
577
623
|
latestCommit: outputString(event, 'latestCommit'),
|
|
578
624
|
irNumber: outputString(event, 'irNumber'),
|
|
579
|
-
irTask:
|
|
580
|
-
nextIrTask: undefined,
|
|
625
|
+
irTask: undefined,
|
|
581
626
|
phase: 'ir-created' as const,
|
|
582
627
|
pendingBossQuestion: undefined,
|
|
583
628
|
bossReply: undefined,
|
|
@@ -585,7 +630,8 @@ const machineSetup = setup({
|
|
|
585
630
|
rememberMoreTasks: assign(({ event }) => ({
|
|
586
631
|
coderOutput: outputString(event, 'coderOutput'),
|
|
587
632
|
latestCommit: outputString(event, 'latestCommit'),
|
|
588
|
-
|
|
633
|
+
irNumber: outputString(event, 'irNumber'),
|
|
634
|
+
irTask: outputString(event, 'irTask'),
|
|
589
635
|
phase: 'ir-task-more' as const,
|
|
590
636
|
pendingBossQuestion: undefined,
|
|
591
637
|
bossReply: undefined,
|
|
@@ -593,15 +639,12 @@ const machineSetup = setup({
|
|
|
593
639
|
rememberFinalTask: assign(({ event }) => ({
|
|
594
640
|
coderOutput: outputString(event, 'coderOutput'),
|
|
595
641
|
latestCommit: outputString(event, 'latestCommit'),
|
|
596
|
-
|
|
642
|
+
irNumber: outputString(event, 'irNumber'),
|
|
643
|
+
irTask: outputString(event, 'irTask'),
|
|
597
644
|
phase: 'ir-task-final' as const,
|
|
598
645
|
pendingBossQuestion: undefined,
|
|
599
646
|
bossReply: undefined,
|
|
600
647
|
})),
|
|
601
|
-
advanceToNextIrTask: assign(({ context }) => ({
|
|
602
|
-
irTask: context.nextIrTask,
|
|
603
|
-
nextIrTask: undefined,
|
|
604
|
-
})),
|
|
605
648
|
rememberPendingQuestion: assign(({ context, event }) => {
|
|
606
649
|
const question = outputString(event, 'question');
|
|
607
650
|
const output = playerOutput(event);
|
|
@@ -629,9 +672,14 @@ const machineSetup = setup({
|
|
|
629
672
|
pendingBossQuestion: undefined,
|
|
630
673
|
bossReply: undefined,
|
|
631
674
|
}),
|
|
632
|
-
completeSuccessfully: assign({
|
|
633
|
-
|
|
634
|
-
|
|
675
|
+
completeSuccessfully: assign(({ event }) => {
|
|
676
|
+
const output = reviewOutput(event);
|
|
677
|
+
const approved = isReviewApprovedValue(output) ? output : undefined;
|
|
678
|
+
return {
|
|
679
|
+
completion: 'complete' as const,
|
|
680
|
+
evaluatedRevision: approved?.evaluatedRevision,
|
|
681
|
+
reviewError: undefined,
|
|
682
|
+
};
|
|
635
683
|
}),
|
|
636
684
|
completeWithReviewFailure: assign(({ event }) => ({
|
|
637
685
|
completion: 'review-failed' as const,
|
|
@@ -669,12 +717,10 @@ export const codingMachine = machineSetup.createMachine({
|
|
|
669
717
|
if (!isNonEmptyString(lastCodeCommit)) {
|
|
670
718
|
throw new Error('CODE reached a final state without a commit identity');
|
|
671
719
|
}
|
|
672
|
-
const lastCodeOutput = context.coderOutput ?? '';
|
|
673
720
|
if (context.completion === 'review-failed') {
|
|
674
721
|
return {
|
|
675
722
|
status: 'review-failed',
|
|
676
723
|
lastCodeCommit,
|
|
677
|
-
lastCodeOutput,
|
|
678
724
|
error:
|
|
679
725
|
context.reviewError ?? {
|
|
680
726
|
name: 'Error',
|
|
@@ -682,7 +728,18 @@ export const codingMachine = machineSetup.createMachine({
|
|
|
682
728
|
},
|
|
683
729
|
};
|
|
684
730
|
}
|
|
685
|
-
|
|
731
|
+
const finalEvaluatedRevision = context.evaluatedRevision;
|
|
732
|
+
if (!isNonEmptyString(finalEvaluatedRevision)) {
|
|
733
|
+
throw new Error(
|
|
734
|
+
'CODE completed without an evaluated repository revision',
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
return {
|
|
738
|
+
status: 'complete',
|
|
739
|
+
lastCodeCommit,
|
|
740
|
+
finalEvaluatedRevision,
|
|
741
|
+
allReviewsPassed: true,
|
|
742
|
+
};
|
|
686
743
|
},
|
|
687
744
|
states: {
|
|
688
745
|
ready: {
|
|
@@ -747,6 +804,36 @@ export const codingMachine = machineSetup.createMachine({
|
|
|
747
804
|
'rememberIrCommit',
|
|
748
805
|
],
|
|
749
806
|
},
|
|
807
|
+
{
|
|
808
|
+
guard: 'isMoreTasks',
|
|
809
|
+
target: 'reviewIrTask',
|
|
810
|
+
actions: [
|
|
811
|
+
{
|
|
812
|
+
type: 'playbook.acceptedOutcome',
|
|
813
|
+
params: {
|
|
814
|
+
source: 'runFirstPhase',
|
|
815
|
+
target: 'reviewIrTask',
|
|
816
|
+
acceptedOutcome: 'moreTasks',
|
|
817
|
+
},
|
|
818
|
+
},
|
|
819
|
+
'rememberMoreTasks',
|
|
820
|
+
],
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
guard: 'isFinalTask',
|
|
824
|
+
target: 'reviewIrTask',
|
|
825
|
+
actions: [
|
|
826
|
+
{
|
|
827
|
+
type: 'playbook.acceptedOutcome',
|
|
828
|
+
params: {
|
|
829
|
+
source: 'runFirstPhase',
|
|
830
|
+
target: 'reviewIrTask',
|
|
831
|
+
acceptedOutcome: 'finalTask',
|
|
832
|
+
},
|
|
833
|
+
},
|
|
834
|
+
'rememberFinalTask',
|
|
835
|
+
],
|
|
836
|
+
},
|
|
750
837
|
{
|
|
751
838
|
guard: 'needsBossReply',
|
|
752
839
|
target: 'awaitBossReply',
|
|
@@ -781,7 +868,7 @@ export const codingMachine = machineSetup.createMachine({
|
|
|
781
868
|
stateId: 'reviewFirstCommit',
|
|
782
869
|
sourceItem: 'CODE-2',
|
|
783
870
|
playbookId: 'review',
|
|
784
|
-
text:
|
|
871
|
+
text: newIntentReviewText(context),
|
|
785
872
|
}),
|
|
786
873
|
onDone: [
|
|
787
874
|
{
|
|
@@ -826,7 +913,6 @@ export const codingMachine = machineSetup.createMachine({
|
|
|
826
913
|
...(context.irNumber === undefined
|
|
827
914
|
? {}
|
|
828
915
|
: { irNumber: context.irNumber }),
|
|
829
|
-
...(context.irTask === undefined ? {} : { irTask: context.irTask }),
|
|
830
916
|
...(context.pendingBossQuestion === undefined
|
|
831
917
|
? {}
|
|
832
918
|
: { pendingBossQuestion: context.pendingBossQuestion }),
|
|
@@ -905,7 +991,6 @@ export const codingMachine = machineSetup.createMachine({
|
|
|
905
991
|
{
|
|
906
992
|
guard: 'reviewApprovedMoreTasks',
|
|
907
993
|
target: 'runIrTask',
|
|
908
|
-
actions: 'advanceToNextIrTask',
|
|
909
994
|
},
|
|
910
995
|
{
|
|
911
996
|
guard: 'reviewApprovedFinalTask',
|
|
@@ -16,65 +16,85 @@ When the first coding phase begins, Captain shall prompt Coder:
|
|
|
16
16
|
> > <caller-input>
|
|
17
17
|
> > <run-results>
|
|
18
18
|
>
|
|
19
|
-
>
|
|
20
|
-
> If
|
|
21
|
-
>
|
|
19
|
+
> First determine whether the coding request starts a new coding intent or continues an existing IR with unfinished work.
|
|
20
|
+
> If the request may continue an existing IR but does not identify it unambiguously, ask Boss before changing files.
|
|
21
|
+
>
|
|
22
|
+
> For a new coding intent, assess whether it can be completed well in one commit.
|
|
23
|
+
> If it can, implement and test it, update the affected specs, and ensure @specs/map.md remains accurate.
|
|
24
|
+
> If it cannot, decompose it into tasks sized to exactly one commit each, add a new IR under @specs/intents, and do not implement any IR task in this phase.
|
|
22
25
|
> Plan affected spec updates before, with, or after their corresponding code changes, either as standalone IR tasks or as explicit work within related tasks.
|
|
23
26
|
>
|
|
27
|
+
> For an existing IR, read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.
|
|
28
|
+
> Do not implement a later task in this phase.
|
|
29
|
+
> Mark the IR's progress and deliverables when relevant.
|
|
30
|
+
> If the IR will be finished after this phase, double-check that all acceptance criteria are met.
|
|
31
|
+
>
|
|
24
32
|
> Consult @specs/map.md for relevant context and @specs/meta.md for spec requirements, if needed.
|
|
25
33
|
>
|
|
34
|
+
> Keep to the original intent and follow what it asks.
|
|
26
35
|
> Do not re-run tests or builds whose inputs have not changed since any previous reported run.
|
|
27
36
|
> Make the phase's minimal changes and then one new commit, following @specs/packages/git.md; never amend an existing commit.
|
|
28
37
|
> Make the commit message explain concisely what changed and why, including relevant verification.
|
|
29
|
-
>
|
|
38
|
+
> Identify every new commit you make.
|
|
39
|
+
> Coder is <coder-llm>.
|
|
30
40
|
|
|
31
41
|
Results:
|
|
32
42
|
- `directCommit`: Coder completed and committed the direct implementation phase. Output shall include `coderOutput: <verbatim final text>` and `latestCommit: <commit identity>`.
|
|
33
|
-
- `irCommit`: Coder created and committed a new IR without implementing an IR task. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`,
|
|
43
|
+
- `irCommit`: Coder created and committed a new IR without implementing an IR task. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, and `irNumber` identifying the created IR.
|
|
44
|
+
- `moreTasks`: Coder continued an existing IR, completed and committed exactly its next unfinished task, and at least one task remains. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, `irNumber` identifying the continued IR, and `irTask` naming the implemented task.
|
|
45
|
+
- `finalTask`: Coder continued an existing IR and completed and committed its final task. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, `irNumber` identifying the continued IR, and `irTask` naming the implemented task.
|
|
34
46
|
|
|
35
47
|
### CODE-2
|
|
36
48
|
|
|
37
|
-
When
|
|
49
|
+
When a direct implementation or new-IR phase has one new commit, Captain shall call playbook `review`:
|
|
38
50
|
|
|
39
|
-
> >
|
|
51
|
+
> > Original intent: <caller-input>
|
|
52
|
+
> > Review scope: the commit <code-commit> from this coding phase and its resulting repository state.
|
|
40
53
|
> > Coder output: <coder-output>
|
|
41
54
|
|
|
42
55
|
Workflow outcomes:
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
56
|
+
- A nested `review` passes the phase only when its result applies to the supplied review scope, returns the exact evaluated repository revision, and affirmatively establishes that no unsettled findings remain.
|
|
57
|
+
- A pass after a direct implementation phase completes `code` with the exact last `code`-owned commit, the exact final evaluated repository revision, and the fact that every phase's review passed with no unsettled findings.
|
|
58
|
+
- A pass after a new-IR phase continues with the next unfinished IR-task phase.
|
|
59
|
+
- An authored `review` abort or failure, or a terminal result that does not establish that the supplied scope was evaluated with no unsettled findings, terminates `code` with the failure and the last `code`-owned commit.
|
|
46
60
|
- Any other nested-call error parks `code` as failed and retains the control-plane error.
|
|
47
61
|
|
|
48
62
|
### CODE-3
|
|
49
63
|
|
|
50
|
-
When a
|
|
64
|
+
When a later IR-task phase begins, Captain shall prompt Coder:
|
|
51
65
|
|
|
52
|
-
> > <
|
|
66
|
+
> > <caller-input>
|
|
67
|
+
> > <ir-number>
|
|
53
68
|
> > <run-results>
|
|
54
69
|
>
|
|
55
|
-
> Read IR
|
|
70
|
+
> Read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.
|
|
56
71
|
> Do not implement a later task in this phase.
|
|
57
72
|
> Mark the IR's progress and deliverables when relevant.
|
|
58
73
|
> If the IR will be finished after this phase, double-check that all acceptance criteria are met.
|
|
59
74
|
>
|
|
75
|
+
> Keep to the original intent and follow what it asks.
|
|
60
76
|
> Do not re-run tests or builds whose inputs have not changed since any previous reported run.
|
|
61
77
|
> Make the phase's minimal changes and then one new commit, following @specs/packages/git.md; never amend an existing commit.
|
|
62
78
|
> Make the commit message explain concisely what changed and why, including relevant verification.
|
|
63
|
-
>
|
|
79
|
+
> Identify every new commit you make.
|
|
80
|
+
> Coder is <coder-llm>.
|
|
64
81
|
|
|
65
82
|
Results:
|
|
66
|
-
- `moreTasks`: Coder completed and committed the
|
|
67
|
-
- `finalTask`: Coder completed and committed the final
|
|
83
|
+
- `moreTasks`: Coder completed and committed exactly the IR's next unfinished task and at least one task remains. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, `irNumber` identifying the continued IR, and `irTask` naming the implemented task.
|
|
84
|
+
- `finalTask`: Coder completed and committed the IR's final task. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, `irNumber` identifying the continued IR, and `irTask` naming the implemented task.
|
|
68
85
|
|
|
69
86
|
### CODE-4
|
|
70
87
|
|
|
71
88
|
When an IR-task phase has one new commit, Captain shall call playbook `review`:
|
|
72
89
|
|
|
73
|
-
> >
|
|
90
|
+
> > Original intent: <caller-input>
|
|
91
|
+
> > Review scope: the commit <code-commit> from this coding phase and its resulting repository state.
|
|
74
92
|
> > Coder output: <coder-output>
|
|
93
|
+
> > Current IR task: <ir-task>
|
|
75
94
|
|
|
76
95
|
Workflow outcomes:
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
-
|
|
96
|
+
- A nested `review` passes the phase only when its result applies to the supplied review scope, returns the exact evaluated repository revision, and affirmatively establishes that no unsettled findings remain.
|
|
97
|
+
- A pass after a nonfinal IR-task phase continues with the next unfinished IR-task phase.
|
|
98
|
+
- A pass after the final IR-task phase completes `code` with the exact last `code`-owned commit, the exact final evaluated repository revision, and the fact that every phase's review passed with no unsettled findings.
|
|
99
|
+
- An authored `review` abort or failure, or a terminal result that does not establish that the supplied scope was evaluated with no unsettled findings, terminates `code` with the failure and the last `code`-owned commit.
|
|
80
100
|
- Any other nested-call error parks `code` as failed and retains the control-plane error.
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
// Role metadata: Coder→coder (canonical local role)
|
|
7
7
|
// Boss event: deterministic START_CODE entry; exact Boss text becomes
|
|
8
8
|
// callerInput; pending Coder questions retain BOSS_REPLY
|
|
9
|
-
// Adjudication: LLM judge per player state; coderOutput is carried verbatim
|
|
9
|
+
// Adjudication: LLM judge per player state; coderOutput is carried verbatim;
|
|
10
|
+
// the first phase decides among four semantic outcomes
|
|
10
11
|
// Nested call: literal review target through the shared bridge
|
|
11
12
|
// Compat: artifact schema 3 / runtime ABI 1
|
|
12
13
|
import { createXStatePlaybookRuntime, snapshotJsonValue, } from '@sublang/playbook/xstate-runtime';
|
|
@@ -102,7 +103,7 @@ const runtimeSpec = {
|
|
|
102
103
|
roleStates: {
|
|
103
104
|
runFirstPhase: {
|
|
104
105
|
role: 'coder',
|
|
105
|
-
label: 'Coder is
|
|
106
|
+
label: 'Coder is running the first coding phase: a direct implementation, a new intent record, or an existing intent-record task.',
|
|
106
107
|
},
|
|
107
108
|
runIrTask: {
|
|
108
109
|
role: 'coder',
|
|
@@ -120,6 +121,23 @@ const runtimeSpec = {
|
|
|
120
121
|
repositoryDisposition: 'one-descendant-commit',
|
|
121
122
|
},
|
|
122
123
|
irCommit: {
|
|
124
|
+
fields: {
|
|
125
|
+
coderOutput: 'presentation',
|
|
126
|
+
latestCommit: 'effect',
|
|
127
|
+
irNumber: 'semantic',
|
|
128
|
+
},
|
|
129
|
+
repositoryDisposition: 'one-descendant-commit',
|
|
130
|
+
},
|
|
131
|
+
moreTasks: {
|
|
132
|
+
fields: {
|
|
133
|
+
coderOutput: 'presentation',
|
|
134
|
+
latestCommit: 'effect',
|
|
135
|
+
irNumber: 'semantic',
|
|
136
|
+
irTask: 'semantic',
|
|
137
|
+
},
|
|
138
|
+
repositoryDisposition: 'one-descendant-commit',
|
|
139
|
+
},
|
|
140
|
+
finalTask: {
|
|
123
141
|
fields: {
|
|
124
142
|
coderOutput: 'presentation',
|
|
125
143
|
latestCommit: 'effect',
|
|
@@ -138,6 +156,7 @@ const runtimeSpec = {
|
|
|
138
156
|
fields: {
|
|
139
157
|
coderOutput: 'presentation',
|
|
140
158
|
latestCommit: 'effect',
|
|
159
|
+
irNumber: 'semantic',
|
|
141
160
|
irTask: 'semantic',
|
|
142
161
|
},
|
|
143
162
|
repositoryDisposition: 'one-descendant-commit',
|
|
@@ -146,6 +165,8 @@ const runtimeSpec = {
|
|
|
146
165
|
fields: {
|
|
147
166
|
coderOutput: 'presentation',
|
|
148
167
|
latestCommit: 'effect',
|
|
168
|
+
irNumber: 'semantic',
|
|
169
|
+
irTask: 'semantic',
|
|
149
170
|
},
|
|
150
171
|
repositoryDisposition: 'one-descendant-commit',
|
|
151
172
|
},
|