@sublang/playbook 0.1.2 → 0.2.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/README.md +27 -18
- package/package.json +23 -23
- package/{code.fsm.d.ts → reference/sdlc/code.playbook/code.fsm.d.ts} +18 -0
- package/{code.fsm.introspect.d.ts → reference/sdlc/code.playbook/code.fsm.introspect.d.ts} +24 -0
- package/{code.fsm.introspect.js → reference/sdlc/code.playbook/code.fsm.introspect.js} +28 -1
- package/{code.fsm.introspect.ts → reference/sdlc/code.playbook/code.fsm.introspect.ts} +73 -6
- package/{code.fsm.js → reference/sdlc/code.playbook/code.fsm.js} +252 -103
- package/{code.fsm.ts → reference/sdlc/code.playbook/code.fsm.ts} +315 -107
- package/{code.gears.md → reference/sdlc/code.playbook/code.gears.md} +4 -3
- package/{code.playbook.d.ts → reference/sdlc/code.playbook/code.playbook.d.ts} +14 -2
- package/{code.playbook.js → reference/sdlc/code.playbook/code.playbook.js} +172 -79
- package/{code.playbook.ts → reference/sdlc/code.playbook/code.playbook.ts} +263 -72
- package/{tmux-play.config.yaml → reference/sdlc/code.playbook/tmux-play.config.yaml} +8 -0
- package/{tmux-play.production.config.yaml → reference/sdlc/code.playbook/tmux-play.production.config.yaml} +6 -0
- /package/{bin → reference/sdlc/code.playbook/bin}/playbook-code.js +0 -0
- /package/{code.tmux-play.d.ts → reference/sdlc/code.playbook/code.tmux-play.d.ts} +0 -0
- /package/{code.tmux-play.js → reference/sdlc/code.playbook/code.tmux-play.js} +0 -0
- /package/{code.tmux-play.ts → reference/sdlc/code.playbook/code.tmux-play.ts} +0 -0
|
@@ -40,6 +40,14 @@ type WorkflowKind = 'singleCommit' | 'iteration' | 'specSummary';
|
|
|
40
40
|
type ChangeOrigin = 'bossIntent' | 'irTask';
|
|
41
41
|
type ReviewSubject = 'commit' | 'changes';
|
|
42
42
|
type AfterReview = 'continueIr' | 'summarizeSpecs' | 'done';
|
|
43
|
+
type ResumableStateId = Exclude<JumpableStateId, 'ready' | 'failed'>;
|
|
44
|
+
|
|
45
|
+
type PendingBossQuestion = {
|
|
46
|
+
resumeStateId: ResumableStateId;
|
|
47
|
+
sourceItem: string;
|
|
48
|
+
player: Player;
|
|
49
|
+
question: string;
|
|
50
|
+
};
|
|
43
51
|
|
|
44
52
|
export type CaptainInput = {
|
|
45
53
|
player: Player;
|
|
@@ -58,6 +66,8 @@ export type CaptainInput = {
|
|
|
58
66
|
challenges?: string;
|
|
59
67
|
coderPlayer?: string;
|
|
60
68
|
reviewerPlayer?: string;
|
|
69
|
+
pendingBossQuestion?: PendingBossQuestion;
|
|
70
|
+
bossReply?: string;
|
|
61
71
|
};
|
|
62
72
|
|
|
63
73
|
export type CaptainOutput = {
|
|
@@ -67,6 +77,7 @@ export type CaptainOutput = {
|
|
|
67
77
|
reviews?: string;
|
|
68
78
|
challenges?: string;
|
|
69
79
|
summary?: string;
|
|
80
|
+
question?: string;
|
|
70
81
|
[k: string]: unknown;
|
|
71
82
|
};
|
|
72
83
|
|
|
@@ -88,6 +99,8 @@ export type CodingContext = CodingInput & {
|
|
|
88
99
|
challenges?: string;
|
|
89
100
|
lastResult?: CaptainOutput;
|
|
90
101
|
lastError?: unknown;
|
|
102
|
+
pendingBossQuestion?: PendingBossQuestion;
|
|
103
|
+
bossReply?: string;
|
|
91
104
|
};
|
|
92
105
|
|
|
93
106
|
export type CodingEvent =
|
|
@@ -99,7 +112,8 @@ export type CodingEvent =
|
|
|
99
112
|
targetId: JumpableStateId;
|
|
100
113
|
intent?: string;
|
|
101
114
|
irNumber?: string;
|
|
102
|
-
}
|
|
115
|
+
}
|
|
116
|
+
| { type: 'BOSS_REPLY'; answer: string };
|
|
103
117
|
|
|
104
118
|
const jumpableStateIds = [
|
|
105
119
|
'ready',
|
|
@@ -125,6 +139,28 @@ const jumpableStateIds = [
|
|
|
125
139
|
'failed',
|
|
126
140
|
] as const satisfies readonly JumpableStateId[];
|
|
127
141
|
|
|
142
|
+
const resumableStateIds = [
|
|
143
|
+
'planAndImplement',
|
|
144
|
+
'respondToReview',
|
|
145
|
+
'continueIr',
|
|
146
|
+
'summarizeSpecs',
|
|
147
|
+
'reviewBossCommitSpecs',
|
|
148
|
+
'reviewBossCommitCode',
|
|
149
|
+
'reviewBossCommitMixed',
|
|
150
|
+
'reviewIrTaskCommitSpecs',
|
|
151
|
+
'reviewIrTaskCommitCode',
|
|
152
|
+
'reviewIrTaskCommitMixed',
|
|
153
|
+
'reviewChangesSpecs',
|
|
154
|
+
'reviewChangesCode',
|
|
155
|
+
'reviewChangesMixed',
|
|
156
|
+
'reviewChangesAndChallengesSpecs',
|
|
157
|
+
'reviewChangesAndChallengesCode',
|
|
158
|
+
'reviewChangesAndChallengesMixed',
|
|
159
|
+
'adjudicateChallenges',
|
|
160
|
+
'commitCoderInitial',
|
|
161
|
+
'commitJoint',
|
|
162
|
+
] as const satisfies readonly ResumableStateId[];
|
|
163
|
+
|
|
128
164
|
const outputOf = (event: unknown): CaptainOutput | undefined =>
|
|
129
165
|
(event as { output?: CaptainOutput }).output;
|
|
130
166
|
|
|
@@ -160,6 +196,10 @@ const rememberCaptainError = assign({
|
|
|
160
196
|
lastError: ({ event }: { event: unknown }) => (event as { error?: unknown }).error,
|
|
161
197
|
});
|
|
162
198
|
|
|
199
|
+
const rememberEmptyBossReplyError = assign({
|
|
200
|
+
lastError: () => new Error('BOSS_REPLY received empty answer'),
|
|
201
|
+
});
|
|
202
|
+
|
|
163
203
|
const rememberBossInput = assign({
|
|
164
204
|
intent: ({ context, event }: { context: CodingContext; event: unknown }) =>
|
|
165
205
|
(event as { intent?: string }).intent ?? context.intent,
|
|
@@ -167,15 +207,185 @@ const rememberBossInput = assign({
|
|
|
167
207
|
(event as { irNumber?: string }).irNumber ?? context.irNumber,
|
|
168
208
|
});
|
|
169
209
|
|
|
170
|
-
|
|
210
|
+
type CaptainInputFactory = (context: Partial<CodingContext>) => CaptainInput;
|
|
211
|
+
|
|
212
|
+
const needsBossReplyDescription =
|
|
213
|
+
"The player's prose surfaces a clarifying question for Boss that the player cannot answer alone. Output shall include `question: <verbatim question text from the player's prose>`.";
|
|
214
|
+
|
|
215
|
+
const bossReplyInputFields = (context: Partial<CodingContext>) => ({
|
|
216
|
+
pendingBossQuestion: context.pendingBossQuestion,
|
|
217
|
+
bossReply: context.bossReply,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const withNeedsBossReply = <T extends Record<string, string>>(result: T) => ({
|
|
221
|
+
...result,
|
|
222
|
+
needsBossReply: needsBossReplyDescription,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const captainStateMetadata = {
|
|
226
|
+
planAndImplement: { sourceItem: 'CODE-1', player: 'Coder' },
|
|
227
|
+
respondToReview: { sourceItem: 'CODE-2', player: 'Coder' },
|
|
228
|
+
continueIr: { sourceItem: 'CODE-3', player: 'Coder' },
|
|
229
|
+
summarizeSpecs: { sourceItem: 'CODE-4', player: 'Coder' },
|
|
230
|
+
reviewBossCommitSpecs: { sourceItem: 'CODE-5', player: 'Reviewer' },
|
|
231
|
+
reviewBossCommitCode: { sourceItem: 'CODE-6', player: 'Reviewer' },
|
|
232
|
+
reviewBossCommitMixed: { sourceItem: 'CODE-7', player: 'Reviewer' },
|
|
233
|
+
reviewIrTaskCommitSpecs: { sourceItem: 'CODE-8', player: 'Reviewer' },
|
|
234
|
+
reviewIrTaskCommitCode: { sourceItem: 'CODE-9', player: 'Reviewer' },
|
|
235
|
+
reviewIrTaskCommitMixed: { sourceItem: 'CODE-10', player: 'Reviewer' },
|
|
236
|
+
reviewChangesSpecs: { sourceItem: 'CODE-11', player: 'Reviewer' },
|
|
237
|
+
reviewChangesCode: { sourceItem: 'CODE-12', player: 'Reviewer' },
|
|
238
|
+
reviewChangesMixed: { sourceItem: 'CODE-13', player: 'Reviewer' },
|
|
239
|
+
reviewChangesAndChallengesSpecs: { sourceItem: 'CODE-15', player: 'Reviewer' },
|
|
240
|
+
reviewChangesAndChallengesCode: { sourceItem: 'CODE-16', player: 'Reviewer' },
|
|
241
|
+
reviewChangesAndChallengesMixed: { sourceItem: 'CODE-17', player: 'Reviewer' },
|
|
242
|
+
adjudicateChallenges: { sourceItem: 'CODE-14', player: 'Reviewer' },
|
|
243
|
+
commitCoderInitial: { sourceItem: 'CODE-18', player: 'Committer' },
|
|
244
|
+
commitJoint: { sourceItem: 'CODE-19', player: 'Committer' },
|
|
245
|
+
} as const satisfies Record<
|
|
246
|
+
ResumableStateId,
|
|
247
|
+
{ sourceItem: string; player: Player }
|
|
248
|
+
>;
|
|
249
|
+
|
|
250
|
+
const planAndImplementInput: CaptainInputFactory = (context) => ({
|
|
251
|
+
player: 'Coder',
|
|
252
|
+
sourceItem: 'CODE-1',
|
|
253
|
+
intent: context.intent,
|
|
254
|
+
...bossReplyInputFields(context),
|
|
255
|
+
prompt: [
|
|
256
|
+
'Assess whether this can be completed in a single commit, following best practices.',
|
|
257
|
+
'If yes, implement and test, updating both code and specs; otherwise, decompose into tasks as a new IR under @specs/iterations.',
|
|
258
|
+
'Consult @specs/map.md for relevant context if needed; ensure it reflects the changes.',
|
|
259
|
+
'Do not commit.',
|
|
260
|
+
].join('\n'),
|
|
261
|
+
result: withNeedsBossReply({
|
|
262
|
+
singleCommitReady:
|
|
263
|
+
'Coder produced uncommitted single-commit changes (Initial Changes).',
|
|
264
|
+
irDrafted:
|
|
265
|
+
'Coder decomposed the intent into a new IR and drafted it uncommitted (Initial Changes).',
|
|
266
|
+
}),
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const continueIrInput: CaptainInputFactory = (context) => ({
|
|
270
|
+
player: 'Coder',
|
|
271
|
+
sourceItem: 'CODE-3',
|
|
272
|
+
irNumber: context.irNumber,
|
|
273
|
+
...bossReplyInputFields(context),
|
|
274
|
+
prompt: [
|
|
275
|
+
'Continue to implement IR-<#> if not all deliverables and tasks are done.',
|
|
276
|
+
'Implement one task at a time (including corresponding tests if any).',
|
|
277
|
+
'Stop after each task for review — do not commit yet.',
|
|
278
|
+
'If relevant, mark progress in the IR.',
|
|
279
|
+
].join('\n'),
|
|
280
|
+
result: withNeedsBossReply({
|
|
281
|
+
taskReady:
|
|
282
|
+
'Coder produced uncommitted changes for the next IR task (Initial Changes). Output shall include `taskDescription: <one-line description of the task just implemented>`.',
|
|
283
|
+
iterationDone: 'All IR deliverables and tasks are done.',
|
|
284
|
+
}),
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
const summarizeSpecsInput: CaptainInputFactory = (context) => ({
|
|
288
|
+
player: 'Coder',
|
|
289
|
+
sourceItem: 'CODE-4',
|
|
290
|
+
irNumber: context.irNumber,
|
|
291
|
+
...bossReplyInputFields(context),
|
|
292
|
+
prompt: [
|
|
293
|
+
'Read IR-<#> and corresponding commits.',
|
|
294
|
+
'According to @specs/meta.md, add or update spec items to fully capture:',
|
|
295
|
+
'',
|
|
296
|
+
'- the user requirements in @specs/user,',
|
|
297
|
+
'- the system behavior in @specs/dev, and',
|
|
298
|
+
'- the integration/system test cases in @specs/test.',
|
|
299
|
+
'',
|
|
300
|
+
'The spec items should be the *minimal* set needed to reimplement code without the IR.',
|
|
301
|
+
'The set should be complete and coherent.',
|
|
302
|
+
'Avoid implementation specifics.',
|
|
303
|
+
'Avoid redundant spec items.',
|
|
304
|
+
'Consult @specs/map.md for relevant context and update it to reflect your changes.',
|
|
305
|
+
].join('\n'),
|
|
306
|
+
result: withNeedsBossReply({
|
|
307
|
+
specsReady: 'Coder produced uncommitted spec updates (Initial Changes).',
|
|
308
|
+
noSpecChanges: 'Existing specs already capture the iteration.',
|
|
309
|
+
}),
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
const setPendingBossQuestion = (resumeStateId: ResumableStateId) =>
|
|
313
|
+
assign({
|
|
314
|
+
pendingBossQuestion: ({
|
|
315
|
+
context,
|
|
316
|
+
event,
|
|
317
|
+
}: {
|
|
318
|
+
context: CodingContext;
|
|
319
|
+
event: unknown;
|
|
320
|
+
}) => {
|
|
321
|
+
const input = captainStateMetadata[resumeStateId];
|
|
322
|
+
return {
|
|
323
|
+
resumeStateId,
|
|
324
|
+
sourceItem: input.sourceItem,
|
|
325
|
+
player: input.player,
|
|
326
|
+
question: outputOf(event)?.question ?? '',
|
|
327
|
+
};
|
|
328
|
+
},
|
|
329
|
+
bossReply: () => undefined,
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
const rememberBossReply = assign({
|
|
333
|
+
bossReply: ({ event }: { event: unknown }) =>
|
|
334
|
+
(event as { answer?: string }).answer ?? '',
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
const clearBossReplyContext = assign({
|
|
338
|
+
pendingBossQuestion: () => undefined,
|
|
339
|
+
bossReply: () => undefined,
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
const actionsArray = (actions: unknown) =>
|
|
343
|
+
actions === undefined ? [] : Array.isArray(actions) ? actions : [actions];
|
|
344
|
+
|
|
345
|
+
const withClearBossReplyContext = <T extends { actions?: unknown }>(transition: T): T => ({
|
|
346
|
+
...transition,
|
|
347
|
+
actions: [clearBossReplyContext, ...actionsArray(transition.actions)],
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
const bossInterrupts = (
|
|
351
|
+
ids: readonly JumpableStateId[],
|
|
352
|
+
extraActions: readonly unknown[] = [],
|
|
353
|
+
) =>
|
|
171
354
|
ids.map((id) => ({
|
|
172
355
|
target: `#${id}` as const,
|
|
173
356
|
guard: ({ event }: { event: CodingEvent }) =>
|
|
174
357
|
event.type === 'BOSS_INTERRUPT' && event.targetId === id,
|
|
175
358
|
reenter: true,
|
|
176
|
-
actions: rememberBossInput,
|
|
359
|
+
actions: [...extraActions, rememberBossInput],
|
|
177
360
|
}));
|
|
178
361
|
|
|
362
|
+
const resumableStates = (ids: readonly ResumableStateId[]) =>
|
|
363
|
+
ids.map((id) => ({
|
|
364
|
+
target: `#${id}` as const,
|
|
365
|
+
guard: ({ context, event }: { context: CodingContext; event: CodingEvent }) =>
|
|
366
|
+
event.type === 'BOSS_REPLY' &&
|
|
367
|
+
context.pendingBossQuestion?.resumeStateId === id,
|
|
368
|
+
reenter: true,
|
|
369
|
+
actions: rememberBossReply,
|
|
370
|
+
}));
|
|
371
|
+
|
|
372
|
+
const bossReplyIsEmpty = ({ event }: { event: CodingEvent }) =>
|
|
373
|
+
event.type === 'BOSS_REPLY' && event.answer.trim() === '';
|
|
374
|
+
|
|
375
|
+
const withNeedsBossReplyTransition = <
|
|
376
|
+
T extends readonly { guard?: unknown; target?: unknown; actions?: unknown }[],
|
|
377
|
+
>(
|
|
378
|
+
resumeStateId: ResumableStateId,
|
|
379
|
+
transitions: T,
|
|
380
|
+
) => [
|
|
381
|
+
...transitions.map((transition) => withClearBossReplyContext(transition)),
|
|
382
|
+
{
|
|
383
|
+
guard: guardIs('needsBossReply'),
|
|
384
|
+
target: '#awaitBossReply',
|
|
385
|
+
actions: [rememberCaptainOutput, setPendingBossQuestion(resumeStateId)],
|
|
386
|
+
},
|
|
387
|
+
];
|
|
388
|
+
|
|
179
389
|
const captainError = {
|
|
180
390
|
target: '#failed',
|
|
181
391
|
actions: rememberCaptainError,
|
|
@@ -217,6 +427,21 @@ const readyEvents = {
|
|
|
217
427
|
},
|
|
218
428
|
};
|
|
219
429
|
|
|
430
|
+
const awaitBossReplyEvents = {
|
|
431
|
+
START_CODING: withClearBossReplyContext(readyEvents.START_CODING),
|
|
432
|
+
CONTINUE_IR: withClearBossReplyContext(readyEvents.CONTINUE_IR),
|
|
433
|
+
SUMMARIZE_IR: withClearBossReplyContext(readyEvents.SUMMARIZE_IR),
|
|
434
|
+
BOSS_INTERRUPT: bossInterrupts(jumpableStateIds, [clearBossReplyContext]),
|
|
435
|
+
BOSS_REPLY: [
|
|
436
|
+
{
|
|
437
|
+
guard: bossReplyIsEmpty,
|
|
438
|
+
target: '#failed',
|
|
439
|
+
actions: [clearBossReplyContext, rememberEmptyBossReplyError],
|
|
440
|
+
},
|
|
441
|
+
...resumableStates(resumableStateIds),
|
|
442
|
+
],
|
|
443
|
+
};
|
|
444
|
+
|
|
220
445
|
const captainPlaceholder = fromPromise<CaptainOutput, CaptainInput>(async () => {
|
|
221
446
|
throw new Error('captain actor must be provided by the runner');
|
|
222
447
|
});
|
|
@@ -250,31 +475,20 @@ export const codingMachine = setup({
|
|
|
250
475
|
on: readyEvents,
|
|
251
476
|
},
|
|
252
477
|
|
|
478
|
+
awaitBossReply: {
|
|
479
|
+
id: 'awaitBossReply',
|
|
480
|
+
description: 'Waiting for Boss to answer a player question.',
|
|
481
|
+
on: awaitBossReplyEvents,
|
|
482
|
+
},
|
|
483
|
+
|
|
253
484
|
planAndImplement: {
|
|
254
485
|
id: 'planAndImplement',
|
|
255
486
|
description:
|
|
256
487
|
'CODE-1: Coder assesses a Boss intent and either implements a single-commit change or drafts an IR.',
|
|
257
488
|
invoke: {
|
|
258
489
|
src: 'captain',
|
|
259
|
-
input: ({ context }): CaptainInput => (
|
|
260
|
-
|
|
261
|
-
sourceItem: 'CODE-1',
|
|
262
|
-
intent: context.intent,
|
|
263
|
-
prompt: [
|
|
264
|
-
'Assess whether this can be completed in a single commit, following best practices.',
|
|
265
|
-
'If yes, implement and test, updating both code and specs; otherwise, decompose into tasks as a new IR under @specs/iterations.',
|
|
266
|
-
'Consult @specs/map.md for relevant context if needed; ensure it reflects the changes.',
|
|
267
|
-
'Do not commit.',
|
|
268
|
-
].join('\n'),
|
|
269
|
-
result: {
|
|
270
|
-
singleCommitReady:
|
|
271
|
-
'Coder produced uncommitted single-commit changes (Initial Changes).',
|
|
272
|
-
irDrafted:
|
|
273
|
-
'Coder decomposed the intent into a new IR and drafted it uncommitted (Initial Changes).',
|
|
274
|
-
needsBossInput: 'Progress requires additional Boss input.',
|
|
275
|
-
},
|
|
276
|
-
}),
|
|
277
|
-
onDone: [
|
|
490
|
+
input: ({ context }): CaptainInput => planAndImplementInput(context),
|
|
491
|
+
onDone: withNeedsBossReplyTransition('planAndImplement', [
|
|
278
492
|
{
|
|
279
493
|
guard: guardIs('singleCommitReady'),
|
|
280
494
|
target: '#commitCoderInitial',
|
|
@@ -299,8 +513,7 @@ export const codingMachine = setup({
|
|
|
299
513
|
}),
|
|
300
514
|
],
|
|
301
515
|
},
|
|
302
|
-
|
|
303
|
-
],
|
|
516
|
+
]),
|
|
304
517
|
onError: captainError,
|
|
305
518
|
},
|
|
306
519
|
},
|
|
@@ -313,6 +526,7 @@ export const codingMachine = setup({
|
|
|
313
526
|
input: ({ context }): CaptainInput => ({
|
|
314
527
|
player: 'Coder',
|
|
315
528
|
sourceItem: 'CODE-2',
|
|
529
|
+
...bossReplyInputFields(context),
|
|
316
530
|
reviews: context.reviews,
|
|
317
531
|
prompt: [
|
|
318
532
|
'For each review item below for the above changes, challenge or accept it, with strong reasoning, solid evidence, and comprehensive thinking.',
|
|
@@ -335,9 +549,10 @@ export const codingMachine = setup({
|
|
|
335
549
|
'Coder challenged one or more review items without producing any code edits. Output shall include `challenges: <numbered rebuttals, one per challenged item>`.',
|
|
336
550
|
accepted:
|
|
337
551
|
'Coder accepted the review outcome without further edits.',
|
|
552
|
+
needsBossReply: needsBossReplyDescription,
|
|
338
553
|
},
|
|
339
554
|
}),
|
|
340
|
-
onDone: [
|
|
555
|
+
onDone: withNeedsBossReplyTransition('respondToReview', [
|
|
341
556
|
{
|
|
342
557
|
guard: guardIs('changesMadeSpecs'),
|
|
343
558
|
target: '#reviewChangesSpecs',
|
|
@@ -402,7 +617,7 @@ export const codingMachine = setup({
|
|
|
402
617
|
target: '#done',
|
|
403
618
|
actions: rememberCaptainOutput,
|
|
404
619
|
},
|
|
405
|
-
],
|
|
620
|
+
]),
|
|
406
621
|
onError: captainError,
|
|
407
622
|
},
|
|
408
623
|
},
|
|
@@ -413,24 +628,8 @@ export const codingMachine = setup({
|
|
|
413
628
|
'CODE-3: Coder continues an IR after the previous task or IR draft passed review.',
|
|
414
629
|
invoke: {
|
|
415
630
|
src: 'captain',
|
|
416
|
-
input: ({ context }): CaptainInput => (
|
|
417
|
-
|
|
418
|
-
sourceItem: 'CODE-3',
|
|
419
|
-
irNumber: context.irNumber,
|
|
420
|
-
prompt: [
|
|
421
|
-
'Continue to implement IR-<#> if not all deliverables and tasks are done.',
|
|
422
|
-
'Implement one task at a time (including corresponding tests if any).',
|
|
423
|
-
'Stop after each task for review — do not commit yet.',
|
|
424
|
-
'If relevant, mark progress in the IR.',
|
|
425
|
-
].join('\n'),
|
|
426
|
-
result: {
|
|
427
|
-
taskReady:
|
|
428
|
-
'Coder produced uncommitted changes for the next IR task (Initial Changes). Output shall include `taskDescription: <one-line description of the task just implemented>`.',
|
|
429
|
-
iterationDone: 'All IR deliverables and tasks are done.',
|
|
430
|
-
needsBossInput: 'Progress requires additional Boss input.',
|
|
431
|
-
},
|
|
432
|
-
}),
|
|
433
|
-
onDone: [
|
|
631
|
+
input: ({ context }): CaptainInput => continueIrInput(context),
|
|
632
|
+
onDone: withNeedsBossReplyTransition('continueIr', [
|
|
434
633
|
{
|
|
435
634
|
guard: guardIs('taskReady'),
|
|
436
635
|
target: '#commitCoderInitial',
|
|
@@ -454,8 +653,7 @@ export const codingMachine = setup({
|
|
|
454
653
|
}),
|
|
455
654
|
],
|
|
456
655
|
},
|
|
457
|
-
|
|
458
|
-
],
|
|
656
|
+
]),
|
|
459
657
|
onError: captainError,
|
|
460
658
|
},
|
|
461
659
|
},
|
|
@@ -465,31 +663,8 @@ export const codingMachine = setup({
|
|
|
465
663
|
description: 'CODE-4: Coder summarizes a completed IR into minimal spec items.',
|
|
466
664
|
invoke: {
|
|
467
665
|
src: 'captain',
|
|
468
|
-
input: ({ context }): CaptainInput => (
|
|
469
|
-
|
|
470
|
-
sourceItem: 'CODE-4',
|
|
471
|
-
irNumber: context.irNumber,
|
|
472
|
-
prompt: [
|
|
473
|
-
'Read IR-<#> and corresponding commits.',
|
|
474
|
-
'According to @specs/meta.md, add or update spec items to fully capture:',
|
|
475
|
-
'',
|
|
476
|
-
'- the user requirements in @specs/user,',
|
|
477
|
-
'- the system behavior in @specs/dev, and',
|
|
478
|
-
'- the integration/system test cases in @specs/test.',
|
|
479
|
-
'',
|
|
480
|
-
'The spec items should be the *minimal* set needed to reimplement code without the IR.',
|
|
481
|
-
'The set should be complete and coherent.',
|
|
482
|
-
'Avoid implementation specifics.',
|
|
483
|
-
'Avoid redundant spec items.',
|
|
484
|
-
'Consult @specs/map.md for relevant context and update it to reflect your changes.',
|
|
485
|
-
].join('\n'),
|
|
486
|
-
result: {
|
|
487
|
-
specsReady: 'Coder produced uncommitted spec updates (Initial Changes).',
|
|
488
|
-
noSpecChanges: 'Existing specs already capture the iteration.',
|
|
489
|
-
needsBossInput: 'Spec summarization requires additional Boss input.',
|
|
490
|
-
},
|
|
491
|
-
}),
|
|
492
|
-
onDone: [
|
|
666
|
+
input: ({ context }): CaptainInput => summarizeSpecsInput(context),
|
|
667
|
+
onDone: withNeedsBossReplyTransition('summarizeSpecs', [
|
|
493
668
|
{
|
|
494
669
|
guard: guardIs('specsReady'),
|
|
495
670
|
target: '#commitCoderInitial',
|
|
@@ -502,9 +677,12 @@ export const codingMachine = setup({
|
|
|
502
677
|
}),
|
|
503
678
|
],
|
|
504
679
|
},
|
|
505
|
-
{
|
|
506
|
-
|
|
507
|
-
|
|
680
|
+
{
|
|
681
|
+
guard: guardIs('noSpecChanges'),
|
|
682
|
+
target: '#done',
|
|
683
|
+
actions: rememberCaptainOutput,
|
|
684
|
+
},
|
|
685
|
+
]),
|
|
508
686
|
onError: captainError,
|
|
509
687
|
},
|
|
510
688
|
},
|
|
@@ -518,6 +696,7 @@ export const codingMachine = setup({
|
|
|
518
696
|
input: ({ context }): CaptainInput => ({
|
|
519
697
|
player: 'Reviewer',
|
|
520
698
|
sourceItem: 'CODE-5',
|
|
699
|
+
...bossReplyInputFields(context),
|
|
521
700
|
intent: context.intent,
|
|
522
701
|
prompt: [
|
|
523
702
|
'Review the latest commit.',
|
|
@@ -536,9 +715,10 @@ export const codingMachine = setup({
|
|
|
536
715
|
noFindings: 'The spec-only commit has no review findings.',
|
|
537
716
|
hasFindings:
|
|
538
717
|
'The review produced findings for Coder. Output shall include `reviews: <numbered list of findings, no duplication>`.',
|
|
718
|
+
needsBossReply: needsBossReplyDescription,
|
|
539
719
|
},
|
|
540
720
|
}),
|
|
541
|
-
onDone: [
|
|
721
|
+
onDone: withNeedsBossReplyTransition('reviewBossCommitSpecs', [
|
|
542
722
|
{ guard: noFindingsAfter('continueIr'), target: '#continueIr', actions: rememberCaptainOutput },
|
|
543
723
|
{ guard: noFindingsAfter('summarizeSpecs'), target: '#summarizeSpecs', actions: rememberCaptainOutput },
|
|
544
724
|
{ guard: noFindingsAfter('done'), target: '#done', actions: rememberCaptainOutput },
|
|
@@ -547,7 +727,7 @@ export const codingMachine = setup({
|
|
|
547
727
|
target: '#respondToReview',
|
|
548
728
|
actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'commit' as const })],
|
|
549
729
|
},
|
|
550
|
-
],
|
|
730
|
+
]),
|
|
551
731
|
onError: captainError,
|
|
552
732
|
},
|
|
553
733
|
},
|
|
@@ -561,6 +741,7 @@ export const codingMachine = setup({
|
|
|
561
741
|
input: ({ context }): CaptainInput => ({
|
|
562
742
|
player: 'Reviewer',
|
|
563
743
|
sourceItem: 'CODE-6',
|
|
744
|
+
...bossReplyInputFields(context),
|
|
564
745
|
intent: context.intent,
|
|
565
746
|
prompt: [
|
|
566
747
|
'Review the latest commit.',
|
|
@@ -574,9 +755,10 @@ export const codingMachine = setup({
|
|
|
574
755
|
noFindings: 'The code-only commit has no review findings.',
|
|
575
756
|
hasFindings:
|
|
576
757
|
'The review produced findings for Coder. Output shall include `reviews: <numbered list of findings, no duplication>`.',
|
|
758
|
+
needsBossReply: needsBossReplyDescription,
|
|
577
759
|
},
|
|
578
760
|
}),
|
|
579
|
-
onDone: [
|
|
761
|
+
onDone: withNeedsBossReplyTransition('reviewBossCommitCode', [
|
|
580
762
|
{ guard: noFindingsAfter('continueIr'), target: '#continueIr', actions: rememberCaptainOutput },
|
|
581
763
|
{ guard: noFindingsAfter('summarizeSpecs'), target: '#summarizeSpecs', actions: rememberCaptainOutput },
|
|
582
764
|
{ guard: noFindingsAfter('done'), target: '#done', actions: rememberCaptainOutput },
|
|
@@ -585,7 +767,7 @@ export const codingMachine = setup({
|
|
|
585
767
|
target: '#respondToReview',
|
|
586
768
|
actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'commit' as const })],
|
|
587
769
|
},
|
|
588
|
-
],
|
|
770
|
+
]),
|
|
589
771
|
onError: captainError,
|
|
590
772
|
},
|
|
591
773
|
},
|
|
@@ -599,6 +781,7 @@ export const codingMachine = setup({
|
|
|
599
781
|
input: ({ context }): CaptainInput => ({
|
|
600
782
|
player: 'Reviewer',
|
|
601
783
|
sourceItem: 'CODE-7',
|
|
784
|
+
...bossReplyInputFields(context),
|
|
602
785
|
intent: context.intent,
|
|
603
786
|
prompt: [
|
|
604
787
|
'Review the latest commit.',
|
|
@@ -619,9 +802,10 @@ export const codingMachine = setup({
|
|
|
619
802
|
noFindings: 'The mixed commit has no review findings.',
|
|
620
803
|
hasFindings:
|
|
621
804
|
'The review produced findings for Coder. Output shall include `reviews: <numbered list of findings, no duplication>`.',
|
|
805
|
+
needsBossReply: needsBossReplyDescription,
|
|
622
806
|
},
|
|
623
807
|
}),
|
|
624
|
-
onDone: [
|
|
808
|
+
onDone: withNeedsBossReplyTransition('reviewBossCommitMixed', [
|
|
625
809
|
{ guard: noFindingsAfter('continueIr'), target: '#continueIr', actions: rememberCaptainOutput },
|
|
626
810
|
{ guard: noFindingsAfter('summarizeSpecs'), target: '#summarizeSpecs', actions: rememberCaptainOutput },
|
|
627
811
|
{ guard: noFindingsAfter('done'), target: '#done', actions: rememberCaptainOutput },
|
|
@@ -630,7 +814,7 @@ export const codingMachine = setup({
|
|
|
630
814
|
target: '#respondToReview',
|
|
631
815
|
actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'commit' as const })],
|
|
632
816
|
},
|
|
633
|
-
],
|
|
817
|
+
]),
|
|
634
818
|
onError: captainError,
|
|
635
819
|
},
|
|
636
820
|
},
|
|
@@ -644,6 +828,7 @@ export const codingMachine = setup({
|
|
|
644
828
|
input: ({ context }): CaptainInput => ({
|
|
645
829
|
player: 'Reviewer',
|
|
646
830
|
sourceItem: 'CODE-8',
|
|
831
|
+
...bossReplyInputFields(context),
|
|
647
832
|
irNumber: context.irNumber,
|
|
648
833
|
taskDescription: context.taskDescription,
|
|
649
834
|
prompt: [
|
|
@@ -663,9 +848,10 @@ export const codingMachine = setup({
|
|
|
663
848
|
noFindings: 'The IR-task spec-only commit has no review findings.',
|
|
664
849
|
hasFindings:
|
|
665
850
|
'The review produced findings for Coder. Output shall include `reviews: <numbered list of findings, no duplication>`.',
|
|
851
|
+
needsBossReply: needsBossReplyDescription,
|
|
666
852
|
},
|
|
667
853
|
}),
|
|
668
|
-
onDone: [
|
|
854
|
+
onDone: withNeedsBossReplyTransition('reviewIrTaskCommitSpecs', [
|
|
669
855
|
{ guard: noFindingsAfter('continueIr'), target: '#continueIr', actions: rememberCaptainOutput },
|
|
670
856
|
{ guard: noFindingsAfter('summarizeSpecs'), target: '#summarizeSpecs', actions: rememberCaptainOutput },
|
|
671
857
|
{ guard: noFindingsAfter('done'), target: '#done', actions: rememberCaptainOutput },
|
|
@@ -674,7 +860,7 @@ export const codingMachine = setup({
|
|
|
674
860
|
target: '#respondToReview',
|
|
675
861
|
actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'commit' as const })],
|
|
676
862
|
},
|
|
677
|
-
],
|
|
863
|
+
]),
|
|
678
864
|
onError: captainError,
|
|
679
865
|
},
|
|
680
866
|
},
|
|
@@ -688,6 +874,7 @@ export const codingMachine = setup({
|
|
|
688
874
|
input: ({ context }): CaptainInput => ({
|
|
689
875
|
player: 'Reviewer',
|
|
690
876
|
sourceItem: 'CODE-9',
|
|
877
|
+
...bossReplyInputFields(context),
|
|
691
878
|
irNumber: context.irNumber,
|
|
692
879
|
taskDescription: context.taskDescription,
|
|
693
880
|
prompt: [
|
|
@@ -702,9 +889,10 @@ export const codingMachine = setup({
|
|
|
702
889
|
noFindings: 'The IR-task code-only commit has no review findings.',
|
|
703
890
|
hasFindings:
|
|
704
891
|
'The review produced findings for Coder. Output shall include `reviews: <numbered list of findings, no duplication>`.',
|
|
892
|
+
needsBossReply: needsBossReplyDescription,
|
|
705
893
|
},
|
|
706
894
|
}),
|
|
707
|
-
onDone: [
|
|
895
|
+
onDone: withNeedsBossReplyTransition('reviewIrTaskCommitCode', [
|
|
708
896
|
{ guard: noFindingsAfter('continueIr'), target: '#continueIr', actions: rememberCaptainOutput },
|
|
709
897
|
{ guard: noFindingsAfter('summarizeSpecs'), target: '#summarizeSpecs', actions: rememberCaptainOutput },
|
|
710
898
|
{ guard: noFindingsAfter('done'), target: '#done', actions: rememberCaptainOutput },
|
|
@@ -713,7 +901,7 @@ export const codingMachine = setup({
|
|
|
713
901
|
target: '#respondToReview',
|
|
714
902
|
actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'commit' as const })],
|
|
715
903
|
},
|
|
716
|
-
],
|
|
904
|
+
]),
|
|
717
905
|
onError: captainError,
|
|
718
906
|
},
|
|
719
907
|
},
|
|
@@ -727,6 +915,7 @@ export const codingMachine = setup({
|
|
|
727
915
|
input: ({ context }): CaptainInput => ({
|
|
728
916
|
player: 'Reviewer',
|
|
729
917
|
sourceItem: 'CODE-10',
|
|
918
|
+
...bossReplyInputFields(context),
|
|
730
919
|
irNumber: context.irNumber,
|
|
731
920
|
taskDescription: context.taskDescription,
|
|
732
921
|
prompt: [
|
|
@@ -748,9 +937,10 @@ export const codingMachine = setup({
|
|
|
748
937
|
noFindings: 'The IR-task mixed commit has no review findings.',
|
|
749
938
|
hasFindings:
|
|
750
939
|
'The review produced findings for Coder. Output shall include `reviews: <numbered list of findings, no duplication>`.',
|
|
940
|
+
needsBossReply: needsBossReplyDescription,
|
|
751
941
|
},
|
|
752
942
|
}),
|
|
753
|
-
onDone: [
|
|
943
|
+
onDone: withNeedsBossReplyTransition('reviewIrTaskCommitMixed', [
|
|
754
944
|
{ guard: noFindingsAfter('continueIr'), target: '#continueIr', actions: rememberCaptainOutput },
|
|
755
945
|
{ guard: noFindingsAfter('summarizeSpecs'), target: '#summarizeSpecs', actions: rememberCaptainOutput },
|
|
756
946
|
{ guard: noFindingsAfter('done'), target: '#done', actions: rememberCaptainOutput },
|
|
@@ -759,7 +949,7 @@ export const codingMachine = setup({
|
|
|
759
949
|
target: '#respondToReview',
|
|
760
950
|
actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'commit' as const })],
|
|
761
951
|
},
|
|
762
|
-
],
|
|
952
|
+
]),
|
|
763
953
|
onError: captainError,
|
|
764
954
|
},
|
|
765
955
|
},
|
|
@@ -770,9 +960,10 @@ export const codingMachine = setup({
|
|
|
770
960
|
'CODE-11: Reviewer reviews uncommitted Coder changes that touch only @specs/{user,dev,test}/ with no accompanying rebuttals.',
|
|
771
961
|
invoke: {
|
|
772
962
|
src: 'captain',
|
|
773
|
-
input: (): CaptainInput => ({
|
|
963
|
+
input: ({ context }): CaptainInput => ({
|
|
774
964
|
player: 'Reviewer',
|
|
775
965
|
sourceItem: 'CODE-11',
|
|
966
|
+
...bossReplyInputFields(context),
|
|
776
967
|
prompt: [
|
|
777
968
|
'Review the unstaged/untracked changes.',
|
|
778
969
|
'Understand the intent.',
|
|
@@ -790,9 +981,10 @@ export const codingMachine = setup({
|
|
|
790
981
|
noFindings: 'The uncommitted spec-only changes are ready to commit.',
|
|
791
982
|
hasFindings:
|
|
792
983
|
'The review produced findings for Coder. Output shall include `reviews: <numbered list of findings, no duplication>`.',
|
|
984
|
+
needsBossReply: needsBossReplyDescription,
|
|
793
985
|
},
|
|
794
986
|
}),
|
|
795
|
-
onDone: [
|
|
987
|
+
onDone: withNeedsBossReplyTransition('reviewChangesSpecs', [
|
|
796
988
|
{
|
|
797
989
|
guard: guardIs('noFindings'),
|
|
798
990
|
target: '#commitJoint',
|
|
@@ -803,7 +995,7 @@ export const codingMachine = setup({
|
|
|
803
995
|
target: '#respondToReview',
|
|
804
996
|
actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'changes' as const })],
|
|
805
997
|
},
|
|
806
|
-
],
|
|
998
|
+
]),
|
|
807
999
|
onError: captainError,
|
|
808
1000
|
},
|
|
809
1001
|
},
|
|
@@ -814,9 +1006,10 @@ export const codingMachine = setup({
|
|
|
814
1006
|
'CODE-12: Reviewer reviews uncommitted Coder changes that touch only files outside @specs/{user,dev,test}/ with no accompanying rebuttals.',
|
|
815
1007
|
invoke: {
|
|
816
1008
|
src: 'captain',
|
|
817
|
-
input: (): CaptainInput => ({
|
|
1009
|
+
input: ({ context }): CaptainInput => ({
|
|
818
1010
|
player: 'Reviewer',
|
|
819
1011
|
sourceItem: 'CODE-12',
|
|
1012
|
+
...bossReplyInputFields(context),
|
|
820
1013
|
prompt: [
|
|
821
1014
|
'Review the unstaged/untracked changes.',
|
|
822
1015
|
'Understand the intent.',
|
|
@@ -829,9 +1022,10 @@ export const codingMachine = setup({
|
|
|
829
1022
|
noFindings: 'The uncommitted code-only changes are ready to commit.',
|
|
830
1023
|
hasFindings:
|
|
831
1024
|
'The review produced findings for Coder. Output shall include `reviews: <numbered list of findings, no duplication>`.',
|
|
1025
|
+
needsBossReply: needsBossReplyDescription,
|
|
832
1026
|
},
|
|
833
1027
|
}),
|
|
834
|
-
onDone: [
|
|
1028
|
+
onDone: withNeedsBossReplyTransition('reviewChangesCode', [
|
|
835
1029
|
{
|
|
836
1030
|
guard: guardIs('noFindings'),
|
|
837
1031
|
target: '#commitJoint',
|
|
@@ -842,7 +1036,7 @@ export const codingMachine = setup({
|
|
|
842
1036
|
target: '#respondToReview',
|
|
843
1037
|
actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'changes' as const })],
|
|
844
1038
|
},
|
|
845
|
-
],
|
|
1039
|
+
]),
|
|
846
1040
|
onError: captainError,
|
|
847
1041
|
},
|
|
848
1042
|
},
|
|
@@ -853,9 +1047,10 @@ export const codingMachine = setup({
|
|
|
853
1047
|
'CODE-13: Reviewer reviews uncommitted Coder changes that touch both @specs/{user,dev,test}/ and other files with no accompanying rebuttals.',
|
|
854
1048
|
invoke: {
|
|
855
1049
|
src: 'captain',
|
|
856
|
-
input: (): CaptainInput => ({
|
|
1050
|
+
input: ({ context }): CaptainInput => ({
|
|
857
1051
|
player: 'Reviewer',
|
|
858
1052
|
sourceItem: 'CODE-13',
|
|
1053
|
+
...bossReplyInputFields(context),
|
|
859
1054
|
prompt: [
|
|
860
1055
|
'Review the unstaged/untracked changes.',
|
|
861
1056
|
'Understand the intent.',
|
|
@@ -875,9 +1070,10 @@ export const codingMachine = setup({
|
|
|
875
1070
|
noFindings: 'The uncommitted mixed changes are ready to commit.',
|
|
876
1071
|
hasFindings:
|
|
877
1072
|
'The review produced findings for Coder. Output shall include `reviews: <numbered list of findings, no duplication>`.',
|
|
1073
|
+
needsBossReply: needsBossReplyDescription,
|
|
878
1074
|
},
|
|
879
1075
|
}),
|
|
880
|
-
onDone: [
|
|
1076
|
+
onDone: withNeedsBossReplyTransition('reviewChangesMixed', [
|
|
881
1077
|
{
|
|
882
1078
|
guard: guardIs('noFindings'),
|
|
883
1079
|
target: '#commitJoint',
|
|
@@ -888,7 +1084,7 @@ export const codingMachine = setup({
|
|
|
888
1084
|
target: '#respondToReview',
|
|
889
1085
|
actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'changes' as const })],
|
|
890
1086
|
},
|
|
891
|
-
],
|
|
1087
|
+
]),
|
|
892
1088
|
onError: captainError,
|
|
893
1089
|
},
|
|
894
1090
|
},
|
|
@@ -902,6 +1098,7 @@ export const codingMachine = setup({
|
|
|
902
1098
|
input: ({ context }): CaptainInput => ({
|
|
903
1099
|
player: 'Reviewer',
|
|
904
1100
|
sourceItem: 'CODE-15',
|
|
1101
|
+
...bossReplyInputFields(context),
|
|
905
1102
|
reviews: context.reviews,
|
|
906
1103
|
challenges: context.challenges,
|
|
907
1104
|
prompt: [
|
|
@@ -923,9 +1120,10 @@ export const codingMachine = setup({
|
|
|
923
1120
|
'The new spec-only changes are ready to commit and every rebuttal was accepted (or no items remained open).',
|
|
924
1121
|
needsRevision:
|
|
925
1122
|
'The combined round needs more work: the review produced findings, one or more rebuttals were rejected, or both. Output shall include `reviews: <numbered list of any new findings or rejected rebuttals to address>`.',
|
|
1123
|
+
needsBossReply: needsBossReplyDescription,
|
|
926
1124
|
},
|
|
927
1125
|
}),
|
|
928
|
-
onDone: [
|
|
1126
|
+
onDone: withNeedsBossReplyTransition('reviewChangesAndChallengesSpecs', [
|
|
929
1127
|
{
|
|
930
1128
|
guard: guardIs('approved'),
|
|
931
1129
|
target: '#commitJoint',
|
|
@@ -936,7 +1134,7 @@ export const codingMachine = setup({
|
|
|
936
1134
|
target: '#respondToReview',
|
|
937
1135
|
actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'changes' as const })],
|
|
938
1136
|
},
|
|
939
|
-
],
|
|
1137
|
+
]),
|
|
940
1138
|
onError: captainError,
|
|
941
1139
|
},
|
|
942
1140
|
},
|
|
@@ -950,6 +1148,7 @@ export const codingMachine = setup({
|
|
|
950
1148
|
input: ({ context }): CaptainInput => ({
|
|
951
1149
|
player: 'Reviewer',
|
|
952
1150
|
sourceItem: 'CODE-16',
|
|
1151
|
+
...bossReplyInputFields(context),
|
|
953
1152
|
reviews: context.reviews,
|
|
954
1153
|
challenges: context.challenges,
|
|
955
1154
|
prompt: [
|
|
@@ -966,9 +1165,10 @@ export const codingMachine = setup({
|
|
|
966
1165
|
'The new code-only changes are ready to commit and every rebuttal was accepted (or no items remained open).',
|
|
967
1166
|
needsRevision:
|
|
968
1167
|
'The combined round needs more work: the review produced findings, one or more rebuttals were rejected, or both. Output shall include `reviews: <numbered list of any new findings or rejected rebuttals to address>`.',
|
|
1168
|
+
needsBossReply: needsBossReplyDescription,
|
|
969
1169
|
},
|
|
970
1170
|
}),
|
|
971
|
-
onDone: [
|
|
1171
|
+
onDone: withNeedsBossReplyTransition('reviewChangesAndChallengesCode', [
|
|
972
1172
|
{
|
|
973
1173
|
guard: guardIs('approved'),
|
|
974
1174
|
target: '#commitJoint',
|
|
@@ -979,7 +1179,7 @@ export const codingMachine = setup({
|
|
|
979
1179
|
target: '#respondToReview',
|
|
980
1180
|
actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'changes' as const })],
|
|
981
1181
|
},
|
|
982
|
-
],
|
|
1182
|
+
]),
|
|
983
1183
|
onError: captainError,
|
|
984
1184
|
},
|
|
985
1185
|
},
|
|
@@ -993,6 +1193,7 @@ export const codingMachine = setup({
|
|
|
993
1193
|
input: ({ context }): CaptainInput => ({
|
|
994
1194
|
player: 'Reviewer',
|
|
995
1195
|
sourceItem: 'CODE-17',
|
|
1196
|
+
...bossReplyInputFields(context),
|
|
996
1197
|
reviews: context.reviews,
|
|
997
1198
|
challenges: context.challenges,
|
|
998
1199
|
prompt: [
|
|
@@ -1016,9 +1217,10 @@ export const codingMachine = setup({
|
|
|
1016
1217
|
'The new mixed changes are ready to commit and every rebuttal was accepted (or no items remained open).',
|
|
1017
1218
|
needsRevision:
|
|
1018
1219
|
'The combined round needs more work: the review produced findings, one or more rebuttals were rejected, or both. Output shall include `reviews: <numbered list of any new findings or rejected rebuttals to address>`.',
|
|
1220
|
+
needsBossReply: needsBossReplyDescription,
|
|
1019
1221
|
},
|
|
1020
1222
|
}),
|
|
1021
|
-
onDone: [
|
|
1223
|
+
onDone: withNeedsBossReplyTransition('reviewChangesAndChallengesMixed', [
|
|
1022
1224
|
{
|
|
1023
1225
|
guard: guardIs('approved'),
|
|
1024
1226
|
target: '#commitJoint',
|
|
@@ -1029,7 +1231,7 @@ export const codingMachine = setup({
|
|
|
1029
1231
|
target: '#respondToReview',
|
|
1030
1232
|
actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'changes' as const })],
|
|
1031
1233
|
},
|
|
1032
|
-
],
|
|
1234
|
+
]),
|
|
1033
1235
|
onError: captainError,
|
|
1034
1236
|
},
|
|
1035
1237
|
},
|
|
@@ -1042,6 +1244,7 @@ export const codingMachine = setup({
|
|
|
1042
1244
|
input: ({ context }): CaptainInput => ({
|
|
1043
1245
|
player: 'Reviewer',
|
|
1044
1246
|
sourceItem: 'CODE-14',
|
|
1247
|
+
...bossReplyInputFields(context),
|
|
1045
1248
|
reviews: context.reviews,
|
|
1046
1249
|
challenges: context.challenges,
|
|
1047
1250
|
prompt: [
|
|
@@ -1053,9 +1256,10 @@ export const codingMachine = setup({
|
|
|
1053
1256
|
challengeRejected:
|
|
1054
1257
|
'Reviewer rejected the rebuttal — Coder must respond again.',
|
|
1055
1258
|
noOpenItems: 'No review items remain open.',
|
|
1259
|
+
needsBossReply: needsBossReplyDescription,
|
|
1056
1260
|
},
|
|
1057
1261
|
}),
|
|
1058
|
-
onDone: [
|
|
1262
|
+
onDone: withNeedsBossReplyTransition('adjudicateChallenges', [
|
|
1059
1263
|
{
|
|
1060
1264
|
guard: ({ context, event }) =>
|
|
1061
1265
|
(outputOf(event)?.guard === 'challengeAccepted' ||
|
|
@@ -1096,7 +1300,7 @@ export const codingMachine = setup({
|
|
|
1096
1300
|
target: '#respondToReview',
|
|
1097
1301
|
actions: rememberCaptainOutput,
|
|
1098
1302
|
},
|
|
1099
|
-
],
|
|
1303
|
+
]),
|
|
1100
1304
|
onError: captainError,
|
|
1101
1305
|
},
|
|
1102
1306
|
},
|
|
@@ -1110,6 +1314,7 @@ export const codingMachine = setup({
|
|
|
1110
1314
|
input: ({ context }): CaptainInput => ({
|
|
1111
1315
|
player: 'Committer',
|
|
1112
1316
|
sourceItem: 'CODE-18',
|
|
1317
|
+
...bossReplyInputFields(context),
|
|
1113
1318
|
coderPlayer: context.coderPlayer,
|
|
1114
1319
|
prompt: [
|
|
1115
1320
|
'Make a commit of the changes that belong in the repo, following @specs/dev/git.md (reread if necessary).',
|
|
@@ -1121,9 +1326,10 @@ export const codingMachine = setup({
|
|
|
1121
1326
|
committedMixed: 'Committed changes that span both @specs/{user,dev,test}/ and other files.',
|
|
1122
1327
|
noRelevantChanges: 'There are no relevant changes to commit.',
|
|
1123
1328
|
needsBossInput: 'Committing requires additional Boss input.',
|
|
1329
|
+
needsBossReply: needsBossReplyDescription,
|
|
1124
1330
|
},
|
|
1125
1331
|
}),
|
|
1126
|
-
onDone: [
|
|
1332
|
+
onDone: withNeedsBossReplyTransition('commitCoderInitial', [
|
|
1127
1333
|
{
|
|
1128
1334
|
guard: guardAndOrigin('committedSpecs', 'bossIntent'),
|
|
1129
1335
|
target: '#reviewBossCommitSpecs',
|
|
@@ -1156,7 +1362,7 @@ export const codingMachine = setup({
|
|
|
1156
1362
|
},
|
|
1157
1363
|
{ guard: guardIs('noRelevantChanges'), target: '#ready', actions: rememberCaptainOutput },
|
|
1158
1364
|
{ guard: guardIs('needsBossInput'), target: '#ready', actions: rememberCaptainOutput },
|
|
1159
|
-
],
|
|
1365
|
+
]),
|
|
1160
1366
|
onError: captainError,
|
|
1161
1367
|
},
|
|
1162
1368
|
},
|
|
@@ -1170,6 +1376,7 @@ export const codingMachine = setup({
|
|
|
1170
1376
|
input: ({ context }): CaptainInput => ({
|
|
1171
1377
|
player: 'Committer',
|
|
1172
1378
|
sourceItem: 'CODE-19',
|
|
1379
|
+
...bossReplyInputFields(context),
|
|
1173
1380
|
coderPlayer: context.coderPlayer,
|
|
1174
1381
|
reviewerPlayer: context.reviewerPlayer,
|
|
1175
1382
|
prompt: [
|
|
@@ -1180,9 +1387,10 @@ export const codingMachine = setup({
|
|
|
1180
1387
|
committed: 'Relevant changes were committed.',
|
|
1181
1388
|
noRelevantChanges: 'There are no relevant changes to commit.',
|
|
1182
1389
|
needsBossInput: 'Committing requires additional Boss input.',
|
|
1390
|
+
needsBossReply: needsBossReplyDescription,
|
|
1183
1391
|
},
|
|
1184
1392
|
}),
|
|
1185
|
-
onDone: [
|
|
1393
|
+
onDone: withNeedsBossReplyTransition('commitJoint', [
|
|
1186
1394
|
{
|
|
1187
1395
|
guard: ({ context, event }) =>
|
|
1188
1396
|
outputOf(event)?.guard === 'committed' && context.afterReview === 'continueIr',
|
|
@@ -1203,7 +1411,7 @@ export const codingMachine = setup({
|
|
|
1203
1411
|
},
|
|
1204
1412
|
{ guard: guardIs('noRelevantChanges'), target: '#done', actions: rememberCaptainOutput },
|
|
1205
1413
|
{ guard: guardIs('needsBossInput'), target: '#ready', actions: rememberCaptainOutput },
|
|
1206
|
-
],
|
|
1414
|
+
]),
|
|
1207
1415
|
onError: captainError,
|
|
1208
1416
|
},
|
|
1209
1417
|
},
|