@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.
Files changed (43) hide show
  1. package/docs/cli.md +9 -6
  2. package/docs/configuration.md +15 -1
  3. package/package.json +22 -3
  4. package/reference/sdlc/code.playbook/code.fsm.d.ts +22 -19
  5. package/reference/sdlc/code.playbook/code.fsm.js +116 -52
  6. package/reference/sdlc/code.playbook/code.fsm.ts +149 -64
  7. package/reference/sdlc/code.playbook/code.gears.md +40 -20
  8. package/reference/sdlc/code.playbook/code.playbook.js +23 -2
  9. package/reference/sdlc/code.playbook/code.playbook.ts +23 -2
  10. package/reference/sdlc/code.playbook/playbook.config.template.yaml +18 -2
  11. package/reference/sdlc/decide.playbook/decide.fsm.d.ts +13 -6
  12. package/reference/sdlc/decide.playbook/decide.fsm.js +54 -27
  13. package/reference/sdlc/decide.playbook/decide.fsm.ts +68 -29
  14. package/reference/sdlc/decide.playbook/decide.gears.md +25 -19
  15. package/reference/sdlc/decide.playbook/decide.playbook.js +11 -3
  16. package/reference/sdlc/decide.playbook/decide.playbook.ts +11 -3
  17. package/reference/sdlc/decide.playbook/decide.registry.js +1 -1
  18. package/reference/sdlc/decide.playbook/decide.registry.ts +1 -1
  19. package/reference/sdlc/dev.md +52 -0
  20. package/reference/sdlc/dev.playbook/dev.fsm.d.ts +261 -0
  21. package/reference/sdlc/dev.playbook/dev.fsm.js +723 -0
  22. package/reference/sdlc/dev.playbook/dev.fsm.ts +988 -0
  23. package/reference/sdlc/dev.playbook/dev.gears.md +91 -0
  24. package/reference/sdlc/dev.playbook/dev.playbook.d.ts +21 -0
  25. package/reference/sdlc/dev.playbook/dev.playbook.js +143 -0
  26. package/reference/sdlc/dev.playbook/dev.playbook.ts +246 -0
  27. package/reference/sdlc/dev.playbook/dev.registry.d.ts +40 -0
  28. package/reference/sdlc/dev.playbook/dev.registry.js +64 -0
  29. package/reference/sdlc/dev.playbook/dev.registry.ts +120 -0
  30. package/reference/sdlc/review.playbook/review.fsm.d.ts +15 -2
  31. package/reference/sdlc/review.playbook/review.fsm.js +77 -27
  32. package/reference/sdlc/review.playbook/review.fsm.ts +96 -30
  33. package/reference/sdlc/review.playbook/review.gears.md +52 -26
  34. package/reference/sdlc/review.playbook/review.playbook.js +17 -7
  35. package/reference/sdlc/review.playbook/review.playbook.ts +17 -7
  36. package/reference/sdlc/review.playbook/review.registry.js +1 -1
  37. package/reference/sdlc/review.playbook/review.registry.ts +1 -1
  38. package/slc/link.md +12 -5
  39. package/slc/text2gears.md +3 -0
  40. package/src/xstate-playbook-runtime.js +5 -2
  41. package/src/xstate-playbook-runtime.ts +5 -2
  42. package/src/xstate-runtime.js +13 -1
  43. 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 latest CODE-owned commit. */
107
+ /** Exact identity of the last CODE-owned commit. */
102
108
  readonly lastCodeCommit: string;
103
- /** Exact Coder final text produced after that commit. */
104
- readonly lastCodeOutput: string;
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 latest CODE-owned commit. */
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 nextIrTask?: string;
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
- 'Assess whether the coding intent can be completed well in one commit.',
148
- 'If yes, implement and test it, update the affected specs, and ensure @specs/map.md remains accurate.',
149
- 'Otherwise, 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.',
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
- 'Do not re-run tests or builds whose inputs have not changed since any previous reported run.',
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
- '> <ir-task>',
181
+ '> <caller-input>',
182
+ '> <ir-number>',
162
183
  '> <run-results>',
163
184
  '',
164
- 'Read IR-<#> and implement exactly the next unfinished task, including corresponding tests or specs if any.',
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
- 'Do not re-run tests or builds whose inputs have not changed since any previous reported run.',
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>`, `irNumber`, and `irTask` naming the exact next unfinished task.',
180
- needsBossReply:
181
- "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>`.",
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
- 'Coder completed and committed the current IR task and at least one task remains. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, and `irTask` naming the exact next unfinished task.',
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
- 'Coder completed and committed the final IR task. Output shall include `coderOutput: <verbatim final text>` and `latestCommit: <commit identity>`.',
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 implementing one direct phase or committing a new intent record.',
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 first phase commit.',
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: 'The coding workflow completed after REVIEW found no unsettled findings.',
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
- hasCommittedOutput(event) &&
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
- hasCommittedOutput(event)
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
- isRecord(value) &&
299
- Object.keys(value).sort().join('\0') ===
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 initialReviewText(context: CodingContext): string {
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('Initial intent', context.callerInput ?? ''),
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('IR task', context.irTask ?? ''),
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
- nextIrTask: undefined,
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: outputString(event, '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
- nextIrTask: outputString(event, 'irTask'),
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
- nextIrTask: undefined,
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
- completion: 'complete',
634
- reviewError: undefined,
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
- return { status: 'complete', lastCodeCommit, lastCodeOutput };
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: initialReviewText(context),
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
- > Assess whether the coding intent can be completed well in one commit.
20
- > If yes, implement and test it, update the affected specs, and ensure @specs/map.md remains accurate.
21
- > Otherwise, 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.
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
- > Coder is <coder-llm>; format the model token in conventional human form.
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>`, `irNumber`, and `irTask` naming the exact next unfinished task.
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 the first phase has one new commit, Captain shall call playbook `review`:
49
+ When a direct implementation or new-IR phase has one new commit, Captain shall call playbook `review`:
38
50
 
39
- > > Initial intent: <caller-input>
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
- - Exact approval after a direct implementation phase completes `code`.
44
- - Exact approval after a new-IR phase continues with its next unfinished IR task.
45
- - An authored `review` abort, error, or invalid approval terminates `code` with the failure and last `code`-owned commit.
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 reviewed IR has a next unfinished task, Captain shall prompt Coder:
64
+ When a later IR-task phase begins, Captain shall prompt Coder:
51
65
 
52
- > > <ir-task>
66
+ > > <caller-input>
67
+ > > <ir-number>
53
68
  > > <run-results>
54
69
  >
55
- > Read IR-<#> and implement exactly the next unfinished task, including corresponding tests or specs if any.
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
- > Coder is <coder-llm>; format the model token in conventional human form.
79
+ > Identify every new commit you make.
80
+ > Coder is <coder-llm>.
64
81
 
65
82
  Results:
66
- - `moreTasks`: Coder completed and committed the current IR task and at least one task remains. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, and `irTask` naming the exact next unfinished task.
67
- - `finalTask`: Coder completed and committed the final IR task. Output shall include `coderOutput: <verbatim final text>` and `latestCommit: <commit identity>`.
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
- > > IR task: <ir-task>
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
- - Exact approval after a nonfinal IR-task phase continues with its next unfinished IR task.
78
- - Exact approval after the final IR-task phase completes `code`.
79
- - An authored `review` abort, error, or invalid approval terminates `code` with the failure and last `code`-owned commit.
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 implementing one direct phase or committing a new intent record.',
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
  },