@sublang/playbook 0.8.0 → 1.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 (55) hide show
  1. package/README.md +243 -193
  2. package/package.json +52 -17
  3. package/reference/sdlc/captain.md +102 -0
  4. package/reference/sdlc/captain.playbook/captain.fsm.d.ts +227 -0
  5. package/reference/sdlc/captain.playbook/captain.fsm.js +628 -0
  6. package/reference/sdlc/captain.playbook/captain.fsm.ts +851 -0
  7. package/reference/sdlc/captain.playbook/captain.gears.md +60 -0
  8. package/reference/sdlc/captain.playbook/captain.playbook.d.ts +23 -0
  9. package/reference/sdlc/captain.playbook/captain.playbook.js +1053 -0
  10. package/reference/sdlc/captain.playbook/captain.playbook.ts +1144 -0
  11. package/reference/sdlc/code.playbook/bin/playbook.js +580 -0
  12. package/reference/sdlc/code.playbook/bin/run.js +893 -0
  13. package/reference/sdlc/code.playbook/code.fsm.d.ts +11 -4
  14. package/reference/sdlc/code.playbook/code.fsm.introspect.d.ts +2 -2
  15. package/reference/sdlc/code.playbook/code.fsm.introspect.js +1 -1
  16. package/reference/sdlc/code.playbook/code.fsm.introspect.ts +6 -6
  17. package/reference/sdlc/code.playbook/code.fsm.js +334 -102
  18. package/reference/sdlc/code.playbook/code.fsm.ts +470 -182
  19. package/reference/sdlc/code.playbook/code.gears.md +11 -10
  20. package/reference/sdlc/code.playbook/code.playbook.d.ts +18 -9
  21. package/reference/sdlc/code.playbook/code.playbook.js +1098 -202
  22. package/reference/sdlc/code.playbook/code.playbook.ts +1440 -258
  23. package/reference/sdlc/code.playbook/code.registry.d.ts +17 -5
  24. package/reference/sdlc/code.playbook/code.registry.js +49 -34
  25. package/reference/sdlc/code.playbook/code.registry.ts +75 -41
  26. package/reference/sdlc/code.playbook/playbook-captain.d.ts +16 -8
  27. package/reference/sdlc/code.playbook/playbook-captain.js +1005 -240
  28. package/reference/sdlc/code.playbook/playbook-captain.ts +1310 -301
  29. package/reference/sdlc/code.playbook/playbook.config.template.yaml +68 -0
  30. package/reference/sdlc/discuss.playbook/discuss.fsm.d.ts +396 -0
  31. package/reference/sdlc/discuss.playbook/discuss.fsm.js +2066 -0
  32. package/reference/sdlc/discuss.playbook/discuss.fsm.ts +2464 -0
  33. package/reference/sdlc/discuss.playbook/discuss.gears.md +251 -0
  34. package/reference/sdlc/discuss.playbook/discuss.playbook.d.ts +113 -0
  35. package/reference/sdlc/discuss.playbook/discuss.playbook.js +1514 -0
  36. package/reference/sdlc/discuss.playbook/discuss.playbook.ts +1926 -0
  37. package/reference/sdlc/discuss.playbook/discuss.registry.d.ts +58 -0
  38. package/reference/sdlc/discuss.playbook/discuss.registry.js +97 -0
  39. package/reference/sdlc/discuss.playbook/discuss.registry.ts +153 -0
  40. package/slc/gears2fsm.md +557 -57
  41. package/slc/link.md +1097 -80
  42. package/slc/optimize.md +88 -0
  43. package/slc/text2gears.md +247 -5
  44. package/src/runtime.d.ts +145 -3
  45. package/src/runtime.ts +200 -2
  46. package/src/xstate-runtime.d.ts +94 -0
  47. package/src/xstate-runtime.js +1247 -0
  48. package/src/xstate-runtime.ts +1802 -0
  49. package/reference/sdlc/code.playbook/bin/playbook-code.js +0 -487
  50. package/reference/sdlc/code.playbook/code.tmux-play.d.ts +0 -4
  51. package/reference/sdlc/code.playbook/code.tmux-play.js +0 -11
  52. package/reference/sdlc/code.playbook/code.tmux-play.ts +0 -29
  53. package/reference/sdlc/code.playbook/playbook-code.config.template.yaml +0 -72
  54. package/reference/sdlc/code.playbook/tmux-play.config.yaml +0 -55
  55. package/reference/sdlc/code.playbook/tmux-play.production.config.yaml +0 -38
@@ -3,9 +3,9 @@
3
3
  // XState v5's generics do not flow through helpers declared outside the
4
4
  // machine (e.g., shared guard/action factories, the `readyEvents` block),
5
5
  // so strict checking emits structural-mismatch noise without surfacing real
6
- // bugs. The runner overrides `captain` via `.provide({ actors: { ... } })`
6
+ // bugs. The runner overrides `player` via `.provide({ actors: { ... } })`
7
7
  // and re-asserts the public surface (`CodingContext`, `CodingEvent`,
8
- // `CaptainInput`, `CaptainOutput`) at the boundary.
8
+ // `PlayerInput`, `PlayerOutput`) at the boundary.
9
9
  // @ts-nocheck
10
10
  import { assign, fromPromise, setup } from 'xstate';
11
11
  const jumpableStateIds = [
@@ -52,18 +52,50 @@ const resumableStateIds = [
52
52
  'commitCoderInitial',
53
53
  'commitJoint',
54
54
  ];
55
+ const stateDescriptions = {
56
+ ready: 'Idle hub: waits for Boss to start or resume a coding sub-procedure.',
57
+ awaitBossReply: 'Waiting for Boss to answer a player question.',
58
+ planAndImplement: 'CODE-1: Coder assesses a Boss intent and either implements a single-commit change or drafts an IR.',
59
+ respondToReview: 'CODE-2: Coder addresses or challenges Reviewer findings.',
60
+ continueIr: 'CODE-3: Coder continues an IR after the previous task or IR draft passed review.',
61
+ summarizeSpecs: 'CODE-4: Coder summarizes a completed IR into minimal spec items.',
62
+ reviewBossCommitSpecs: 'CODE-5: Reviewer reviews a Boss-intent commit whose changes are only in @specs/{user,dev,test}/.',
63
+ reviewBossCommitCode: 'CODE-6: Reviewer reviews a Boss-intent commit whose changes are only outside @specs/{user,dev,test}/.',
64
+ reviewBossCommitMixed: 'CODE-7: Reviewer reviews a Boss-intent commit whose changes span both @specs/{user,dev,test}/ and other files.',
65
+ reviewIrTaskCommitSpecs: 'CODE-8: Reviewer reviews an IR-task commit whose changes are only in @specs/{user,dev,test}/.',
66
+ reviewIrTaskCommitCode: 'CODE-9: Reviewer reviews an IR-task commit whose changes are only outside @specs/{user,dev,test}/.',
67
+ reviewIrTaskCommitMixed: 'CODE-10: Reviewer reviews an IR-task commit whose changes span both @specs/{user,dev,test}/ and other files.',
68
+ reviewChangesSpecs: 'CODE-11: Reviewer reviews uncommitted Coder changes that touch only @specs/{user,dev,test}/ with no accompanying rebuttals.',
69
+ reviewChangesCode: 'CODE-12: Reviewer reviews uncommitted Coder changes that touch only files outside @specs/{user,dev,test}/ with no accompanying rebuttals.',
70
+ reviewChangesMixed: 'CODE-13: Reviewer reviews uncommitted Coder changes that touch both @specs/{user,dev,test}/ and other files with no accompanying rebuttals.',
71
+ reviewChangesAndChallengesSpecs: 'CODE-15: Reviewer reviews uncommitted Coder changes that touch only @specs/{user,dev,test}/ and adjudicates accompanying rebuttals in one round.',
72
+ reviewChangesAndChallengesCode: 'CODE-16: Reviewer reviews uncommitted Coder changes that touch only files outside @specs/{user,dev,test}/ and adjudicates accompanying rebuttals in one round.',
73
+ reviewChangesAndChallengesMixed: 'CODE-17: Reviewer reviews uncommitted Coder changes that touch both @specs/{user,dev,test}/ and other files and adjudicates accompanying rebuttals in one round.',
74
+ adjudicateChallenges: 'CODE-14: Reviewer adjudicates Coder rebuttals against the prior review when Coder produced no code edits this round.',
75
+ commitCoderInitial: 'CODE-18: Committer commits Coder Initial Changes when Reviewer has not played since the last commit.',
76
+ commitJoint: 'CODE-19: Committer commits changes when both Coder and Reviewer have played since the last commit.',
77
+ failed: 'Captures the last Captain error so the runner can report it. Boss may resume from here.',
78
+ done: 'The selected coding workflow has completed.',
79
+ };
80
+ const playbookMeta = (stateId) => ({
81
+ playbook: {
82
+ stateId,
83
+ description: stateDescriptions[stateId],
84
+ },
85
+ });
55
86
  const outputOf = (event) => event.output;
56
87
  const guardIs = (guard) => ({ event }) => outputOf(event)?.guard === guard;
57
88
  const guardAndOrigin = (guard, origin) => ({ context, event }) => outputOf(event)?.guard === guard && context.changeOrigin === origin;
58
89
  const acceptedAfter = (subject) => ({ context, event }) => outputOf(event)?.guard === 'accepted' && context.reviewSubject === subject;
59
- const noFindingsAfter = (afterReview) => ({ context, event }) => outputOf(event)?.guard === 'noFindings' && context.afterReview === afterReview;
90
+ const noFindingsAfter = (afterReview) => ({ context, event }) => outputOf(event)?.guard === 'noFindings' &&
91
+ context.afterReview === afterReview;
60
92
  const rememberCaptainOutput = assign({
61
93
  lastResult: ({ event }) => outputOf(event),
62
94
  lastError: () => undefined,
63
95
  irNumber: ({ context, event }) => outputOf(event)?.irNumber ?? context.irNumber,
64
- taskDescription: ({ context, event }) => outputOf(event)?.taskDescription ?? context.taskDescription,
96
+ taskDescription: ({ context, event, }) => outputOf(event)?.taskDescription ?? context.taskDescription,
65
97
  reviews: ({ context, event }) => outputOf(event)?.reviews ?? context.reviews,
66
- challenges: ({ context, event }) => outputOf(event)?.challenges ?? context.challenges,
98
+ challenges: ({ context, event, }) => outputOf(event)?.challenges ?? context.challenges,
67
99
  });
68
100
  const rememberCaptainError = assign({
69
101
  lastError: ({ event }) => event.error,
@@ -75,7 +107,7 @@ const rememberBossInput = assign({
75
107
  intent: ({ context, event }) => event.intent ?? context.intent,
76
108
  irNumber: ({ context, event }) => event.irNumber ?? context.irNumber,
77
109
  });
78
- const needsBossReplyDescription = "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>`.";
110
+ const needsBossReplyDescription = "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>`.";
79
111
  const bossReplyInputFields = (context) => ({
80
112
  pendingBossQuestion: context.pendingBossQuestion,
81
113
  bossReply: context.bossReply,
@@ -98,14 +130,21 @@ const captainStateMetadata = {
98
130
  reviewChangesSpecs: { sourceItem: 'CODE-11', player: 'Reviewer' },
99
131
  reviewChangesCode: { sourceItem: 'CODE-12', player: 'Reviewer' },
100
132
  reviewChangesMixed: { sourceItem: 'CODE-13', player: 'Reviewer' },
101
- reviewChangesAndChallengesSpecs: { sourceItem: 'CODE-15', player: 'Reviewer' },
133
+ reviewChangesAndChallengesSpecs: {
134
+ sourceItem: 'CODE-15',
135
+ player: 'Reviewer',
136
+ },
102
137
  reviewChangesAndChallengesCode: { sourceItem: 'CODE-16', player: 'Reviewer' },
103
- reviewChangesAndChallengesMixed: { sourceItem: 'CODE-17', player: 'Reviewer' },
138
+ reviewChangesAndChallengesMixed: {
139
+ sourceItem: 'CODE-17',
140
+ player: 'Reviewer',
141
+ },
104
142
  adjudicateChallenges: { sourceItem: 'CODE-14', player: 'Reviewer' },
105
143
  commitCoderInitial: { sourceItem: 'CODE-18', player: 'Committer' },
106
144
  commitJoint: { sourceItem: 'CODE-19', player: 'Committer' },
107
145
  };
108
146
  const planAndImplementInput = (context) => ({
147
+ stateId: 'planAndImplement',
109
148
  player: 'Coder',
110
149
  sourceItem: 'CODE-1',
111
150
  intent: context.intent,
@@ -123,6 +162,7 @@ const planAndImplementInput = (context) => ({
123
162
  }),
124
163
  });
125
164
  const continueIrInput = (context) => ({
165
+ stateId: 'continueIr',
126
166
  player: 'Coder',
127
167
  sourceItem: 'CODE-3',
128
168
  irNumber: context.irNumber,
@@ -139,6 +179,7 @@ const continueIrInput = (context) => ({
139
179
  }),
140
180
  });
141
181
  const summarizeSpecsInput = (context) => ({
182
+ stateId: 'summarizeSpecs',
142
183
  player: 'Coder',
143
184
  sourceItem: 'CODE-4',
144
185
  irNumber: context.irNumber,
@@ -166,6 +207,7 @@ const setPendingBossQuestion = (resumeStateId) => assign({
166
207
  pendingBossQuestion: ({ context, event, }) => {
167
208
  const input = captainStateMetadata[resumeStateId];
168
209
  return {
210
+ questionId: resumeStateId,
169
211
  resumeStateId,
170
212
  sourceItem: input.sourceItem,
171
213
  player: input.player,
@@ -194,8 +236,10 @@ const bossInterrupts = (ids, extraActions = []) => ids.map((id) => ({
194
236
  }));
195
237
  const resumableStates = (ids) => ids.map((id) => ({
196
238
  target: `#${id}`,
197
- guard: ({ context, event }) => event.type === 'BOSS_REPLY' &&
198
- context.pendingBossQuestion?.resumeStateId === id,
239
+ guard: ({ context, event, }) => event.type === 'BOSS_REPLY' &&
240
+ context.pendingBossQuestion?.resumeStateId === id &&
241
+ (event.questionId === undefined ||
242
+ event.questionId === context.pendingBossQuestion.questionId),
199
243
  reenter: true,
200
244
  actions: rememberBossReply,
201
245
  }));
@@ -261,13 +305,13 @@ const awaitBossReplyEvents = {
261
305
  ...resumableStates(resumableStateIds),
262
306
  ],
263
307
  };
264
- const captainPlaceholder = fromPromise(async () => {
265
- throw new Error('captain actor must be provided by the runner');
308
+ const playerPlaceholder = fromPromise(async () => {
309
+ throw new Error('player actor must be provided by the runner');
266
310
  });
267
311
  export const codingMachine = setup({
268
312
  types: {},
269
313
  actors: {
270
- captain: captainPlaceholder,
314
+ player: playerPlaceholder,
271
315
  },
272
316
  }).createMachine({
273
317
  id: 'coding',
@@ -285,19 +329,25 @@ export const codingMachine = setup({
285
329
  states: {
286
330
  ready: {
287
331
  id: 'ready',
288
- description: 'Idle hub: waits for Boss to start or resume a coding sub-procedure.',
332
+ description: stateDescriptions.ready,
333
+ meta: playbookMeta('ready'),
334
+ tags: ['playbook.parked'],
289
335
  on: readyEvents,
290
336
  },
291
337
  awaitBossReply: {
292
338
  id: 'awaitBossReply',
293
- description: 'Waiting for Boss to answer a player question.',
339
+ description: stateDescriptions.awaitBossReply,
340
+ meta: playbookMeta('awaitBossReply'),
341
+ tags: ['playbook.parked'],
294
342
  on: awaitBossReplyEvents,
295
343
  },
296
344
  planAndImplement: {
297
345
  id: 'planAndImplement',
298
- description: 'CODE-1: Coder assesses a Boss intent and either implements a single-commit change or drafts an IR.',
346
+ description: stateDescriptions.planAndImplement,
347
+ meta: playbookMeta('planAndImplement'),
348
+ tags: ['playbook.busy'],
299
349
  invoke: {
300
- src: 'captain',
350
+ src: 'player',
301
351
  input: ({ context }) => planAndImplementInput(context),
302
352
  onDone: withNeedsBossReplyTransition('planAndImplement', [
303
353
  {
@@ -330,10 +380,13 @@ export const codingMachine = setup({
330
380
  },
331
381
  respondToReview: {
332
382
  id: 'respondToReview',
333
- description: 'CODE-2: Coder addresses or challenges Reviewer findings.',
383
+ description: stateDescriptions.respondToReview,
384
+ meta: playbookMeta('respondToReview'),
385
+ tags: ['playbook.busy'],
334
386
  invoke: {
335
- src: 'captain',
387
+ src: 'player',
336
388
  input: ({ context }) => ({
389
+ stateId: 'respondToReview',
337
390
  player: 'Coder',
338
391
  sourceItem: 'CODE-2',
339
392
  ...bossReplyInputFields(context),
@@ -422,9 +475,11 @@ export const codingMachine = setup({
422
475
  },
423
476
  continueIr: {
424
477
  id: 'continueIr',
425
- description: 'CODE-3: Coder continues an IR after the previous task or IR draft passed review.',
478
+ description: stateDescriptions.continueIr,
479
+ meta: playbookMeta('continueIr'),
480
+ tags: ['playbook.busy'],
426
481
  invoke: {
427
- src: 'captain',
482
+ src: 'player',
428
483
  input: ({ context }) => continueIrInput(context),
429
484
  onDone: withNeedsBossReplyTransition('continueIr', [
430
485
  {
@@ -456,9 +511,11 @@ export const codingMachine = setup({
456
511
  },
457
512
  summarizeSpecs: {
458
513
  id: 'summarizeSpecs',
459
- description: 'CODE-4: Coder summarizes a completed IR into minimal spec items.',
514
+ description: stateDescriptions.summarizeSpecs,
515
+ meta: playbookMeta('summarizeSpecs'),
516
+ tags: ['playbook.busy'],
460
517
  invoke: {
461
- src: 'captain',
518
+ src: 'player',
462
519
  input: ({ context }) => summarizeSpecsInput(context),
463
520
  onDone: withNeedsBossReplyTransition('summarizeSpecs', [
464
521
  {
@@ -484,10 +541,13 @@ export const codingMachine = setup({
484
541
  },
485
542
  reviewBossCommitSpecs: {
486
543
  id: 'reviewBossCommitSpecs',
487
- description: 'CODE-5: Reviewer reviews a Boss-intent commit whose changes are only in @specs/{user,dev,test}/.',
544
+ description: stateDescriptions.reviewBossCommitSpecs,
545
+ meta: playbookMeta('reviewBossCommitSpecs'),
546
+ tags: ['playbook.busy'],
488
547
  invoke: {
489
- src: 'captain',
548
+ src: 'player',
490
549
  input: ({ context }) => ({
550
+ stateId: 'reviewBossCommitSpecs',
491
551
  player: 'Reviewer',
492
552
  sourceItem: 'CODE-5',
493
553
  ...bossReplyInputFields(context),
@@ -515,13 +575,28 @@ export const codingMachine = setup({
515
575
  },
516
576
  }),
517
577
  onDone: withNeedsBossReplyTransition('reviewBossCommitSpecs', [
518
- { guard: noFindingsAfter('continueIr'), target: '#continueIr', actions: rememberCaptainOutput },
519
- { guard: noFindingsAfter('summarizeSpecs'), target: '#summarizeSpecs', actions: rememberCaptainOutput },
520
- { guard: noFindingsAfter('done'), target: '#done', actions: rememberCaptainOutput },
578
+ {
579
+ guard: noFindingsAfter('continueIr'),
580
+ target: '#continueIr',
581
+ actions: rememberCaptainOutput,
582
+ },
583
+ {
584
+ guard: noFindingsAfter('summarizeSpecs'),
585
+ target: '#summarizeSpecs',
586
+ actions: rememberCaptainOutput,
587
+ },
588
+ {
589
+ guard: noFindingsAfter('done'),
590
+ target: '#done',
591
+ actions: rememberCaptainOutput,
592
+ },
521
593
  {
522
594
  guard: guardIs('hasFindings'),
523
595
  target: '#respondToReview',
524
- actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'commit' })],
596
+ actions: [
597
+ rememberCaptainOutput,
598
+ assign({ reviewSubject: () => 'commit' }),
599
+ ],
525
600
  },
526
601
  ]),
527
602
  onError: captainError,
@@ -529,10 +604,13 @@ export const codingMachine = setup({
529
604
  },
530
605
  reviewBossCommitCode: {
531
606
  id: 'reviewBossCommitCode',
532
- description: 'CODE-6: Reviewer reviews a Boss-intent commit whose changes are only outside @specs/{user,dev,test}/.',
607
+ description: stateDescriptions.reviewBossCommitCode,
608
+ meta: playbookMeta('reviewBossCommitCode'),
609
+ tags: ['playbook.busy'],
533
610
  invoke: {
534
- src: 'captain',
611
+ src: 'player',
535
612
  input: ({ context }) => ({
613
+ stateId: 'reviewBossCommitCode',
536
614
  player: 'Reviewer',
537
615
  sourceItem: 'CODE-6',
538
616
  ...bossReplyInputFields(context),
@@ -554,13 +632,28 @@ export const codingMachine = setup({
554
632
  },
555
633
  }),
556
634
  onDone: withNeedsBossReplyTransition('reviewBossCommitCode', [
557
- { guard: noFindingsAfter('continueIr'), target: '#continueIr', actions: rememberCaptainOutput },
558
- { guard: noFindingsAfter('summarizeSpecs'), target: '#summarizeSpecs', actions: rememberCaptainOutput },
559
- { guard: noFindingsAfter('done'), target: '#done', actions: rememberCaptainOutput },
635
+ {
636
+ guard: noFindingsAfter('continueIr'),
637
+ target: '#continueIr',
638
+ actions: rememberCaptainOutput,
639
+ },
640
+ {
641
+ guard: noFindingsAfter('summarizeSpecs'),
642
+ target: '#summarizeSpecs',
643
+ actions: rememberCaptainOutput,
644
+ },
645
+ {
646
+ guard: noFindingsAfter('done'),
647
+ target: '#done',
648
+ actions: rememberCaptainOutput,
649
+ },
560
650
  {
561
651
  guard: guardIs('hasFindings'),
562
652
  target: '#respondToReview',
563
- actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'commit' })],
653
+ actions: [
654
+ rememberCaptainOutput,
655
+ assign({ reviewSubject: () => 'commit' }),
656
+ ],
564
657
  },
565
658
  ]),
566
659
  onError: captainError,
@@ -568,10 +661,13 @@ export const codingMachine = setup({
568
661
  },
569
662
  reviewBossCommitMixed: {
570
663
  id: 'reviewBossCommitMixed',
571
- description: 'CODE-7: Reviewer reviews a Boss-intent commit whose changes span both @specs/{user,dev,test}/ and other files.',
664
+ description: stateDescriptions.reviewBossCommitMixed,
665
+ meta: playbookMeta('reviewBossCommitMixed'),
666
+ tags: ['playbook.busy'],
572
667
  invoke: {
573
- src: 'captain',
668
+ src: 'player',
574
669
  input: ({ context }) => ({
670
+ stateId: 'reviewBossCommitMixed',
575
671
  player: 'Reviewer',
576
672
  sourceItem: 'CODE-7',
577
673
  ...bossReplyInputFields(context),
@@ -579,6 +675,8 @@ export const codingMachine = setup({
579
675
  prompt: [
580
676
  'Review the latest commit.',
581
677
  'Refer to the commit message.',
678
+ 'Flag any issues or improvements (numbered; no duplication).',
679
+ "Think thoroughly — don't just approve or reject.",
582
680
  'Verify any affected spec items are:',
583
681
  '',
584
682
  '- Complete & coherent: sufficient for you to reimplement code.',
@@ -587,8 +685,6 @@ export const codingMachine = setup({
587
685
  '- Well organized: spec packages are finely scoped, with high cohesion and low coupling.',
588
686
  '',
589
687
  'Flag anything missing, redundant, over-specified, or under-specified.',
590
- 'Flag any issues or improvements (numbered; no duplication).',
591
- "Think thoroughly — don't just approve or reject.",
592
688
  'For context discovery, @specs/map.md indexes all spec files and @specs/meta.md describes the spec format.',
593
689
  'Verify @specs/map.md reflects the changes.',
594
690
  "If the change is ready to commit or push, don't raise nitpicks.",
@@ -601,13 +697,28 @@ export const codingMachine = setup({
601
697
  },
602
698
  }),
603
699
  onDone: withNeedsBossReplyTransition('reviewBossCommitMixed', [
604
- { guard: noFindingsAfter('continueIr'), target: '#continueIr', actions: rememberCaptainOutput },
605
- { guard: noFindingsAfter('summarizeSpecs'), target: '#summarizeSpecs', actions: rememberCaptainOutput },
606
- { guard: noFindingsAfter('done'), target: '#done', actions: rememberCaptainOutput },
700
+ {
701
+ guard: noFindingsAfter('continueIr'),
702
+ target: '#continueIr',
703
+ actions: rememberCaptainOutput,
704
+ },
705
+ {
706
+ guard: noFindingsAfter('summarizeSpecs'),
707
+ target: '#summarizeSpecs',
708
+ actions: rememberCaptainOutput,
709
+ },
710
+ {
711
+ guard: noFindingsAfter('done'),
712
+ target: '#done',
713
+ actions: rememberCaptainOutput,
714
+ },
607
715
  {
608
716
  guard: guardIs('hasFindings'),
609
717
  target: '#respondToReview',
610
- actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'commit' })],
718
+ actions: [
719
+ rememberCaptainOutput,
720
+ assign({ reviewSubject: () => 'commit' }),
721
+ ],
611
722
  },
612
723
  ]),
613
724
  onError: captainError,
@@ -615,10 +726,13 @@ export const codingMachine = setup({
615
726
  },
616
727
  reviewIrTaskCommitSpecs: {
617
728
  id: 'reviewIrTaskCommitSpecs',
618
- description: 'CODE-8: Reviewer reviews an IR-task commit whose changes are only in @specs/{user,dev,test}/.',
729
+ description: stateDescriptions.reviewIrTaskCommitSpecs,
730
+ meta: playbookMeta('reviewIrTaskCommitSpecs'),
731
+ tags: ['playbook.busy'],
619
732
  invoke: {
620
- src: 'captain',
733
+ src: 'player',
621
734
  input: ({ context }) => ({
735
+ stateId: 'reviewIrTaskCommitSpecs',
622
736
  player: 'Reviewer',
623
737
  sourceItem: 'CODE-8',
624
738
  ...bossReplyInputFields(context),
@@ -647,13 +761,28 @@ export const codingMachine = setup({
647
761
  },
648
762
  }),
649
763
  onDone: withNeedsBossReplyTransition('reviewIrTaskCommitSpecs', [
650
- { guard: noFindingsAfter('continueIr'), target: '#continueIr', actions: rememberCaptainOutput },
651
- { guard: noFindingsAfter('summarizeSpecs'), target: '#summarizeSpecs', actions: rememberCaptainOutput },
652
- { guard: noFindingsAfter('done'), target: '#done', actions: rememberCaptainOutput },
764
+ {
765
+ guard: noFindingsAfter('continueIr'),
766
+ target: '#continueIr',
767
+ actions: rememberCaptainOutput,
768
+ },
769
+ {
770
+ guard: noFindingsAfter('summarizeSpecs'),
771
+ target: '#summarizeSpecs',
772
+ actions: rememberCaptainOutput,
773
+ },
774
+ {
775
+ guard: noFindingsAfter('done'),
776
+ target: '#done',
777
+ actions: rememberCaptainOutput,
778
+ },
653
779
  {
654
780
  guard: guardIs('hasFindings'),
655
781
  target: '#respondToReview',
656
- actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'commit' })],
782
+ actions: [
783
+ rememberCaptainOutput,
784
+ assign({ reviewSubject: () => 'commit' }),
785
+ ],
657
786
  },
658
787
  ]),
659
788
  onError: captainError,
@@ -661,10 +790,13 @@ export const codingMachine = setup({
661
790
  },
662
791
  reviewIrTaskCommitCode: {
663
792
  id: 'reviewIrTaskCommitCode',
664
- description: 'CODE-9: Reviewer reviews an IR-task commit whose changes are only outside @specs/{user,dev,test}/.',
793
+ description: stateDescriptions.reviewIrTaskCommitCode,
794
+ meta: playbookMeta('reviewIrTaskCommitCode'),
795
+ tags: ['playbook.busy'],
665
796
  invoke: {
666
- src: 'captain',
797
+ src: 'player',
667
798
  input: ({ context }) => ({
799
+ stateId: 'reviewIrTaskCommitCode',
668
800
  player: 'Reviewer',
669
801
  sourceItem: 'CODE-9',
670
802
  ...bossReplyInputFields(context),
@@ -687,13 +819,28 @@ export const codingMachine = setup({
687
819
  },
688
820
  }),
689
821
  onDone: withNeedsBossReplyTransition('reviewIrTaskCommitCode', [
690
- { guard: noFindingsAfter('continueIr'), target: '#continueIr', actions: rememberCaptainOutput },
691
- { guard: noFindingsAfter('summarizeSpecs'), target: '#summarizeSpecs', actions: rememberCaptainOutput },
692
- { guard: noFindingsAfter('done'), target: '#done', actions: rememberCaptainOutput },
822
+ {
823
+ guard: noFindingsAfter('continueIr'),
824
+ target: '#continueIr',
825
+ actions: rememberCaptainOutput,
826
+ },
827
+ {
828
+ guard: noFindingsAfter('summarizeSpecs'),
829
+ target: '#summarizeSpecs',
830
+ actions: rememberCaptainOutput,
831
+ },
832
+ {
833
+ guard: noFindingsAfter('done'),
834
+ target: '#done',
835
+ actions: rememberCaptainOutput,
836
+ },
693
837
  {
694
838
  guard: guardIs('hasFindings'),
695
839
  target: '#respondToReview',
696
- actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'commit' })],
840
+ actions: [
841
+ rememberCaptainOutput,
842
+ assign({ reviewSubject: () => 'commit' }),
843
+ ],
697
844
  },
698
845
  ]),
699
846
  onError: captainError,
@@ -701,10 +848,13 @@ export const codingMachine = setup({
701
848
  },
702
849
  reviewIrTaskCommitMixed: {
703
850
  id: 'reviewIrTaskCommitMixed',
704
- description: 'CODE-10: Reviewer reviews an IR-task commit whose changes span both @specs/{user,dev,test}/ and other files.',
851
+ description: stateDescriptions.reviewIrTaskCommitMixed,
852
+ meta: playbookMeta('reviewIrTaskCommitMixed'),
853
+ tags: ['playbook.busy'],
705
854
  invoke: {
706
- src: 'captain',
855
+ src: 'player',
707
856
  input: ({ context }) => ({
857
+ stateId: 'reviewIrTaskCommitMixed',
708
858
  player: 'Reviewer',
709
859
  sourceItem: 'CODE-10',
710
860
  ...bossReplyInputFields(context),
@@ -713,6 +863,8 @@ export const codingMachine = setup({
713
863
  prompt: [
714
864
  'Review the latest commit.',
715
865
  'Refer to the commit message.',
866
+ 'Flag any issues or improvements (numbered; no duplication).',
867
+ "Think thoroughly — don't just approve or reject.",
716
868
  'Verify any affected spec items are:',
717
869
  '',
718
870
  '- Complete & coherent: sufficient for you to reimplement code.',
@@ -721,8 +873,6 @@ export const codingMachine = setup({
721
873
  '- Well organized: spec packages are finely scoped, with high cohesion and low coupling.',
722
874
  '',
723
875
  'Flag anything missing, redundant, over-specified, or under-specified.',
724
- 'Flag any issues or improvements (numbered; no duplication).',
725
- "Think thoroughly — don't just approve or reject.",
726
876
  'For context discovery, @specs/map.md indexes all spec files and @specs/meta.md describes the spec format.',
727
877
  'Verify @specs/map.md reflects the changes.',
728
878
  "If the change is ready to commit or push, don't raise nitpicks.",
@@ -735,13 +885,28 @@ export const codingMachine = setup({
735
885
  },
736
886
  }),
737
887
  onDone: withNeedsBossReplyTransition('reviewIrTaskCommitMixed', [
738
- { guard: noFindingsAfter('continueIr'), target: '#continueIr', actions: rememberCaptainOutput },
739
- { guard: noFindingsAfter('summarizeSpecs'), target: '#summarizeSpecs', actions: rememberCaptainOutput },
740
- { guard: noFindingsAfter('done'), target: '#done', actions: rememberCaptainOutput },
888
+ {
889
+ guard: noFindingsAfter('continueIr'),
890
+ target: '#continueIr',
891
+ actions: rememberCaptainOutput,
892
+ },
893
+ {
894
+ guard: noFindingsAfter('summarizeSpecs'),
895
+ target: '#summarizeSpecs',
896
+ actions: rememberCaptainOutput,
897
+ },
898
+ {
899
+ guard: noFindingsAfter('done'),
900
+ target: '#done',
901
+ actions: rememberCaptainOutput,
902
+ },
741
903
  {
742
904
  guard: guardIs('hasFindings'),
743
905
  target: '#respondToReview',
744
- actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'commit' })],
906
+ actions: [
907
+ rememberCaptainOutput,
908
+ assign({ reviewSubject: () => 'commit' }),
909
+ ],
745
910
  },
746
911
  ]),
747
912
  onError: captainError,
@@ -749,10 +914,13 @@ export const codingMachine = setup({
749
914
  },
750
915
  reviewChangesSpecs: {
751
916
  id: 'reviewChangesSpecs',
752
- description: 'CODE-11: Reviewer reviews uncommitted Coder changes that touch only @specs/{user,dev,test}/ with no accompanying rebuttals.',
917
+ description: stateDescriptions.reviewChangesSpecs,
918
+ meta: playbookMeta('reviewChangesSpecs'),
919
+ tags: ['playbook.busy'],
753
920
  invoke: {
754
- src: 'captain',
921
+ src: 'player',
755
922
  input: ({ context }) => ({
923
+ stateId: 'reviewChangesSpecs',
756
924
  player: 'Reviewer',
757
925
  sourceItem: 'CODE-11',
758
926
  ...bossReplyInputFields(context),
@@ -787,7 +955,10 @@ export const codingMachine = setup({
787
955
  {
788
956
  guard: guardIs('hasFindings'),
789
957
  target: '#respondToReview',
790
- actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'changes' })],
958
+ actions: [
959
+ rememberCaptainOutput,
960
+ assign({ reviewSubject: () => 'changes' }),
961
+ ],
791
962
  },
792
963
  ]),
793
964
  onError: captainError,
@@ -795,10 +966,13 @@ export const codingMachine = setup({
795
966
  },
796
967
  reviewChangesCode: {
797
968
  id: 'reviewChangesCode',
798
- description: 'CODE-12: Reviewer reviews uncommitted Coder changes that touch only files outside @specs/{user,dev,test}/ with no accompanying rebuttals.',
969
+ description: stateDescriptions.reviewChangesCode,
970
+ meta: playbookMeta('reviewChangesCode'),
971
+ tags: ['playbook.busy'],
799
972
  invoke: {
800
- src: 'captain',
973
+ src: 'player',
801
974
  input: ({ context }) => ({
975
+ stateId: 'reviewChangesCode',
802
976
  player: 'Reviewer',
803
977
  sourceItem: 'CODE-12',
804
978
  ...bossReplyInputFields(context),
@@ -827,7 +1001,10 @@ export const codingMachine = setup({
827
1001
  {
828
1002
  guard: guardIs('hasFindings'),
829
1003
  target: '#respondToReview',
830
- actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'changes' })],
1004
+ actions: [
1005
+ rememberCaptainOutput,
1006
+ assign({ reviewSubject: () => 'changes' }),
1007
+ ],
831
1008
  },
832
1009
  ]),
833
1010
  onError: captainError,
@@ -835,16 +1012,21 @@ export const codingMachine = setup({
835
1012
  },
836
1013
  reviewChangesMixed: {
837
1014
  id: 'reviewChangesMixed',
838
- description: 'CODE-13: Reviewer reviews uncommitted Coder changes that touch both @specs/{user,dev,test}/ and other files with no accompanying rebuttals.',
1015
+ description: stateDescriptions.reviewChangesMixed,
1016
+ meta: playbookMeta('reviewChangesMixed'),
1017
+ tags: ['playbook.busy'],
839
1018
  invoke: {
840
- src: 'captain',
1019
+ src: 'player',
841
1020
  input: ({ context }) => ({
1021
+ stateId: 'reviewChangesMixed',
842
1022
  player: 'Reviewer',
843
1023
  sourceItem: 'CODE-13',
844
1024
  ...bossReplyInputFields(context),
845
1025
  prompt: [
846
1026
  'Review the unstaged and untracked changes in the context of the staged changes.',
847
1027
  'Understand the intent.',
1028
+ 'Flag any issues or improvements (numbered; no duplication).',
1029
+ "Think thoroughly — don't just approve or reject.",
848
1030
  'Verify any affected spec items are:',
849
1031
  '',
850
1032
  '- Complete & coherent: sufficient for you to reimplement code.',
@@ -853,8 +1035,6 @@ export const codingMachine = setup({
853
1035
  '- Well organized: spec packages are finely scoped, with high cohesion and low coupling.',
854
1036
  '',
855
1037
  'Flag anything missing, redundant, over-specified, or under-specified.',
856
- 'Flag any issues or improvements (numbered; no duplication).',
857
- "Think thoroughly — don't just approve or reject.",
858
1038
  'For context discovery, @specs/map.md indexes all spec files and @specs/meta.md describes the spec format.',
859
1039
  'Verify @specs/map.md reflects the changes.',
860
1040
  "If the change is ready to commit or push, don't raise nitpicks.",
@@ -875,7 +1055,10 @@ export const codingMachine = setup({
875
1055
  {
876
1056
  guard: guardIs('hasFindings'),
877
1057
  target: '#respondToReview',
878
- actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'changes' })],
1058
+ actions: [
1059
+ rememberCaptainOutput,
1060
+ assign({ reviewSubject: () => 'changes' }),
1061
+ ],
879
1062
  },
880
1063
  ]),
881
1064
  onError: captainError,
@@ -883,10 +1066,13 @@ export const codingMachine = setup({
883
1066
  },
884
1067
  reviewChangesAndChallengesSpecs: {
885
1068
  id: 'reviewChangesAndChallengesSpecs',
886
- description: 'CODE-15: Reviewer reviews uncommitted Coder changes that touch only @specs/{user,dev,test}/ and adjudicates accompanying rebuttals in one round.',
1069
+ description: stateDescriptions.reviewChangesAndChallengesSpecs,
1070
+ meta: playbookMeta('reviewChangesAndChallengesSpecs'),
1071
+ tags: ['playbook.busy'],
887
1072
  invoke: {
888
- src: 'captain',
1073
+ src: 'player',
889
1074
  input: ({ context }) => ({
1075
+ stateId: 'reviewChangesAndChallengesSpecs',
890
1076
  player: 'Reviewer',
891
1077
  sourceItem: 'CODE-15',
892
1078
  ...bossReplyInputFields(context),
@@ -924,7 +1110,10 @@ export const codingMachine = setup({
924
1110
  {
925
1111
  guard: guardIs('needsRevision'),
926
1112
  target: '#respondToReview',
927
- actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'changes' })],
1113
+ actions: [
1114
+ rememberCaptainOutput,
1115
+ assign({ reviewSubject: () => 'changes' }),
1116
+ ],
928
1117
  },
929
1118
  ]),
930
1119
  onError: captainError,
@@ -932,10 +1121,13 @@ export const codingMachine = setup({
932
1121
  },
933
1122
  reviewChangesAndChallengesCode: {
934
1123
  id: 'reviewChangesAndChallengesCode',
935
- description: 'CODE-16: Reviewer reviews uncommitted Coder changes that touch only files outside @specs/{user,dev,test}/ and adjudicates accompanying rebuttals in one round.',
1124
+ description: stateDescriptions.reviewChangesAndChallengesCode,
1125
+ meta: playbookMeta('reviewChangesAndChallengesCode'),
1126
+ tags: ['playbook.busy'],
936
1127
  invoke: {
937
- src: 'captain',
1128
+ src: 'player',
938
1129
  input: ({ context }) => ({
1130
+ stateId: 'reviewChangesAndChallengesCode',
939
1131
  player: 'Reviewer',
940
1132
  sourceItem: 'CODE-16',
941
1133
  ...bossReplyInputFields(context),
@@ -967,7 +1159,10 @@ export const codingMachine = setup({
967
1159
  {
968
1160
  guard: guardIs('needsRevision'),
969
1161
  target: '#respondToReview',
970
- actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'changes' })],
1162
+ actions: [
1163
+ rememberCaptainOutput,
1164
+ assign({ reviewSubject: () => 'changes' }),
1165
+ ],
971
1166
  },
972
1167
  ]),
973
1168
  onError: captainError,
@@ -975,10 +1170,13 @@ export const codingMachine = setup({
975
1170
  },
976
1171
  reviewChangesAndChallengesMixed: {
977
1172
  id: 'reviewChangesAndChallengesMixed',
978
- description: 'CODE-17: Reviewer reviews uncommitted Coder changes that touch both @specs/{user,dev,test}/ and other files and adjudicates accompanying rebuttals in one round.',
1173
+ description: stateDescriptions.reviewChangesAndChallengesMixed,
1174
+ meta: playbookMeta('reviewChangesAndChallengesMixed'),
1175
+ tags: ['playbook.busy'],
979
1176
  invoke: {
980
- src: 'captain',
1177
+ src: 'player',
981
1178
  input: ({ context }) => ({
1179
+ stateId: 'reviewChangesAndChallengesMixed',
982
1180
  player: 'Reviewer',
983
1181
  sourceItem: 'CODE-17',
984
1182
  ...bossReplyInputFields(context),
@@ -987,6 +1185,8 @@ export const codingMachine = setup({
987
1185
  prompt: [
988
1186
  'Review the unstaged and untracked changes in the context of the staged changes.',
989
1187
  'Understand the intent.',
1188
+ 'Flag any issues or improvements (numbered; no duplication).',
1189
+ "Think thoroughly — don't just approve or reject.",
990
1190
  'Verify any affected spec items are:',
991
1191
  '',
992
1192
  '- Complete & coherent: sufficient for you to reimplement code.',
@@ -995,8 +1195,6 @@ export const codingMachine = setup({
995
1195
  '- Well organized: spec packages are finely scoped, with high cohesion and low coupling.',
996
1196
  '',
997
1197
  'Flag anything missing, redundant, over-specified, or under-specified.',
998
- 'Flag any issues or improvements (numbered; no duplication).',
999
- "Think thoroughly — don't just approve or reject.",
1000
1198
  'For context discovery, @specs/map.md indexes all spec files and @specs/meta.md describes the spec format.',
1001
1199
  'Verify @specs/map.md reflects the changes.',
1002
1200
  "If the change is ready to commit or push, don't raise nitpicks.",
@@ -1018,7 +1216,10 @@ export const codingMachine = setup({
1018
1216
  {
1019
1217
  guard: guardIs('needsRevision'),
1020
1218
  target: '#respondToReview',
1021
- actions: [rememberCaptainOutput, assign({ reviewSubject: () => 'changes' })],
1219
+ actions: [
1220
+ rememberCaptainOutput,
1221
+ assign({ reviewSubject: () => 'changes' }),
1222
+ ],
1022
1223
  },
1023
1224
  ]),
1024
1225
  onError: captainError,
@@ -1026,10 +1227,13 @@ export const codingMachine = setup({
1026
1227
  },
1027
1228
  adjudicateChallenges: {
1028
1229
  id: 'adjudicateChallenges',
1029
- description: 'CODE-14: Reviewer adjudicates Coder rebuttals against the prior review when Coder produced no code edits this round.',
1230
+ description: stateDescriptions.adjudicateChallenges,
1231
+ meta: playbookMeta('adjudicateChallenges'),
1232
+ tags: ['playbook.busy'],
1030
1233
  invoke: {
1031
- src: 'captain',
1234
+ src: 'player',
1032
1235
  input: ({ context }) => ({
1236
+ stateId: 'adjudicateChallenges',
1033
1237
  player: 'Reviewer',
1034
1238
  sourceItem: 'CODE-14',
1035
1239
  ...bossReplyInputFields(context),
@@ -1089,10 +1293,13 @@ export const codingMachine = setup({
1089
1293
  },
1090
1294
  commitCoderInitial: {
1091
1295
  id: 'commitCoderInitial',
1092
- description: 'CODE-18: Committer commits Coder Initial Changes when Reviewer has not played since the last commit.',
1296
+ description: stateDescriptions.commitCoderInitial,
1297
+ meta: playbookMeta('commitCoderInitial'),
1298
+ tags: ['playbook.busy'],
1093
1299
  invoke: {
1094
- src: 'captain',
1300
+ src: 'player',
1095
1301
  input: ({ context }) => ({
1302
+ stateId: 'commitCoderInitial',
1096
1303
  player: 'Committer',
1097
1304
  sourceItem: 'CODE-18',
1098
1305
  ...bossReplyInputFields(context),
@@ -1100,7 +1307,7 @@ export const codingMachine = setup({
1100
1307
  committerPlayer: context.committerPlayer,
1101
1308
  prompt: [
1102
1309
  'Make a commit of the changes that belong in the repo, following @specs/dev/git.md (reread if necessary).',
1103
- 'Write concisely.',
1310
+ 'Write the commit message concisely.',
1104
1311
  'Coder is <coder-llm>.',
1105
1312
  'Format the `Co-authored-by` `<model>` token as the conventional human form of the substituted id (e.g., `claude-opus-4-7` → `Claude-Opus-4.7`, `gpt-5.5` → `GPT-5.5`).',
1106
1313
  ].join('\n'),
@@ -1144,18 +1351,29 @@ export const codingMachine = setup({
1144
1351
  target: '#reviewIrTaskCommitMixed',
1145
1352
  actions: rememberCaptainOutput,
1146
1353
  },
1147
- { guard: guardIs('noRelevantChanges'), target: '#ready', actions: rememberCaptainOutput },
1148
- { guard: guardIs('needsBossInput'), target: '#ready', actions: rememberCaptainOutput },
1354
+ {
1355
+ guard: guardIs('noRelevantChanges'),
1356
+ target: '#ready',
1357
+ actions: rememberCaptainOutput,
1358
+ },
1359
+ {
1360
+ guard: guardIs('needsBossInput'),
1361
+ target: '#ready',
1362
+ actions: rememberCaptainOutput,
1363
+ },
1149
1364
  ]),
1150
1365
  onError: captainError,
1151
1366
  },
1152
1367
  },
1153
1368
  commitJoint: {
1154
1369
  id: 'commitJoint',
1155
- description: 'CODE-19: Committer commits changes when both Coder and Reviewer have played since the last commit.',
1370
+ description: stateDescriptions.commitJoint,
1371
+ meta: playbookMeta('commitJoint'),
1372
+ tags: ['playbook.busy'],
1156
1373
  invoke: {
1157
- src: 'captain',
1374
+ src: 'player',
1158
1375
  input: ({ context }) => ({
1376
+ stateId: 'commitJoint',
1159
1377
  player: 'Committer',
1160
1378
  sourceItem: 'CODE-19',
1161
1379
  ...bossReplyInputFields(context),
@@ -1164,7 +1382,7 @@ export const codingMachine = setup({
1164
1382
  committerPlayer: context.committerPlayer,
1165
1383
  prompt: [
1166
1384
  'Make a commit of the changes that belong in the repo, following @specs/dev/git.md (reread if necessary).',
1167
- 'Write concisely.',
1385
+ 'Write the commit message concisely.',
1168
1386
  'Coder is <coder-llm>; Reviewer is <reviewer-llm>.',
1169
1387
  'Format the `Co-authored-by` `<model>` token as the conventional human form of the substituted id (e.g., `claude-opus-4-7` → `Claude-Opus-4.7`, `gpt-5.5` → `GPT-5.5`).',
1170
1388
  ].join('\n'),
@@ -1177,34 +1395,48 @@ export const codingMachine = setup({
1177
1395
  }),
1178
1396
  onDone: withNeedsBossReplyTransition('commitJoint', [
1179
1397
  {
1180
- guard: ({ context, event }) => outputOf(event)?.guard === 'committed' && context.afterReview === 'continueIr',
1398
+ guard: ({ context, event }) => outputOf(event)?.guard === 'committed' &&
1399
+ context.afterReview === 'continueIr',
1181
1400
  target: '#continueIr',
1182
1401
  actions: rememberCaptainOutput,
1183
1402
  },
1184
1403
  {
1185
- guard: ({ context, event }) => outputOf(event)?.guard === 'committed' && context.afterReview === 'summarizeSpecs',
1404
+ guard: ({ context, event }) => outputOf(event)?.guard === 'committed' &&
1405
+ context.afterReview === 'summarizeSpecs',
1186
1406
  target: '#summarizeSpecs',
1187
1407
  actions: rememberCaptainOutput,
1188
1408
  },
1189
1409
  {
1190
- guard: ({ context, event }) => outputOf(event)?.guard === 'committed' && context.afterReview === 'done',
1410
+ guard: ({ context, event }) => outputOf(event)?.guard === 'committed' &&
1411
+ context.afterReview === 'done',
1191
1412
  target: '#done',
1192
1413
  actions: rememberCaptainOutput,
1193
1414
  },
1194
- { guard: guardIs('noRelevantChanges'), target: '#done', actions: rememberCaptainOutput },
1195
- { guard: guardIs('needsBossInput'), target: '#ready', actions: rememberCaptainOutput },
1415
+ {
1416
+ guard: guardIs('noRelevantChanges'),
1417
+ target: '#done',
1418
+ actions: rememberCaptainOutput,
1419
+ },
1420
+ {
1421
+ guard: guardIs('needsBossInput'),
1422
+ target: '#ready',
1423
+ actions: rememberCaptainOutput,
1424
+ },
1196
1425
  ]),
1197
1426
  onError: captainError,
1198
1427
  },
1199
1428
  },
1200
1429
  failed: {
1201
1430
  id: 'failed',
1202
- description: 'Captures the last Captain error so the runner can report it. Boss may resume from here.',
1431
+ description: stateDescriptions.failed,
1432
+ meta: playbookMeta('failed'),
1433
+ tags: ['playbook.parked'],
1203
1434
  on: readyEvents,
1204
1435
  },
1205
1436
  done: {
1206
1437
  id: 'done',
1207
- description: 'The selected coding workflow has completed.',
1438
+ description: stateDescriptions.done,
1439
+ meta: playbookMeta('done'),
1208
1440
  type: 'final',
1209
1441
  },
1210
1442
  },