@sublang/playbook 9.0.0 → 11.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 (71) hide show
  1. package/README.md +1 -1
  2. package/docs/cli.md +109 -21
  3. package/docs/configuration.md +89 -40
  4. package/docs/embedding.md +126 -12
  5. package/package.json +14 -3
  6. package/reference/sdlc/captain.md +14 -10
  7. package/reference/sdlc/captain.playbook/captain.fsm.d.ts +33 -13
  8. package/reference/sdlc/captain.playbook/captain.fsm.js +80 -9
  9. package/reference/sdlc/captain.playbook/captain.fsm.ts +137 -18
  10. package/reference/sdlc/captain.playbook/captain.gears.md +10 -6
  11. package/reference/sdlc/captain.playbook/captain.playbook.d.ts +5 -1
  12. package/reference/sdlc/captain.playbook/captain.playbook.js +140 -10
  13. package/reference/sdlc/captain.playbook/captain.playbook.ts +188 -16
  14. package/reference/sdlc/code.md +35 -16
  15. package/reference/sdlc/code.playbook/bin/interactive-session.js +228 -23
  16. package/reference/sdlc/code.playbook/bin/launch-config.js +611 -221
  17. package/reference/sdlc/code.playbook/bin/playbook.js +304 -178
  18. package/reference/sdlc/code.playbook/bin/replay-observer.js +221 -0
  19. package/reference/sdlc/code.playbook/bin/repository-effects.js +2930 -0
  20. package/reference/sdlc/code.playbook/bin/run.js +669 -215
  21. package/reference/sdlc/code.playbook/bin/session-store.js +4546 -502
  22. package/reference/sdlc/code.playbook/code.fsm.d.ts +7 -0
  23. package/reference/sdlc/code.playbook/code.fsm.js +74 -25
  24. package/reference/sdlc/code.playbook/code.fsm.ts +83 -29
  25. package/reference/sdlc/code.playbook/code.gears.md +0 -2
  26. package/reference/sdlc/code.playbook/code.playbook.d.ts +5 -2
  27. package/reference/sdlc/code.playbook/code.playbook.js +54 -2
  28. package/reference/sdlc/code.playbook/code.playbook.ts +75 -6
  29. package/reference/sdlc/code.playbook/code.registry.d.ts +10 -3
  30. package/reference/sdlc/code.playbook/code.registry.js +10 -3
  31. package/reference/sdlc/code.playbook/code.registry.ts +23 -5
  32. package/reference/sdlc/code.playbook/playbook-captain.d.ts +103 -8
  33. package/reference/sdlc/code.playbook/playbook-captain.js +1871 -75
  34. package/reference/sdlc/code.playbook/playbook-captain.ts +2801 -102
  35. package/reference/sdlc/code.playbook/playbook.config.template.yaml +14 -10
  36. package/reference/sdlc/code.playbook/session-store.d.ts +82 -0
  37. package/reference/sdlc/code.playbook/session-store.js +113 -0
  38. package/reference/sdlc/decide.md +24 -16
  39. package/reference/sdlc/decide.playbook/decide.fsm.d.ts +7 -0
  40. package/reference/sdlc/decide.playbook/decide.fsm.js +80 -29
  41. package/reference/sdlc/decide.playbook/decide.fsm.ts +89 -31
  42. package/reference/sdlc/decide.playbook/decide.gears.md +0 -1
  43. package/reference/sdlc/decide.playbook/decide.playbook.d.ts +13 -5
  44. package/reference/sdlc/decide.playbook/decide.playbook.js +1712 -91
  45. package/reference/sdlc/decide.playbook/decide.playbook.ts +2677 -136
  46. package/reference/sdlc/decide.playbook/decide.registry.d.ts +7 -3
  47. package/reference/sdlc/decide.playbook/decide.registry.js +10 -3
  48. package/reference/sdlc/decide.playbook/decide.registry.ts +20 -5
  49. package/reference/sdlc/review.md +36 -18
  50. package/reference/sdlc/review.playbook/review.fsm.d.ts +7 -0
  51. package/reference/sdlc/review.playbook/review.fsm.js +133 -12
  52. package/reference/sdlc/review.playbook/review.fsm.ts +140 -12
  53. package/reference/sdlc/review.playbook/review.playbook.d.ts +5 -2
  54. package/reference/sdlc/review.playbook/review.playbook.js +65 -2
  55. package/reference/sdlc/review.playbook/review.playbook.ts +83 -6
  56. package/reference/sdlc/review.playbook/review.registry.d.ts +10 -3
  57. package/reference/sdlc/review.playbook/review.registry.js +10 -3
  58. package/reference/sdlc/review.playbook/review.registry.ts +23 -5
  59. package/slc/gears2fsm.md +6 -5
  60. package/slc/link.md +544 -41
  61. package/src/accepted-outcome.d.ts +18 -0
  62. package/src/accepted-outcome.js +94 -0
  63. package/src/accepted-outcome.ts +140 -0
  64. package/src/runtime.d.ts +164 -3
  65. package/src/runtime.ts +213 -2
  66. package/src/xstate-playbook-runtime.d.ts +149 -10
  67. package/src/xstate-playbook-runtime.js +2569 -270
  68. package/src/xstate-playbook-runtime.ts +4133 -490
  69. package/src/xstate-runtime.d.ts +59 -1
  70. package/src/xstate-runtime.js +866 -7
  71. package/src/xstate-runtime.ts +1397 -7
@@ -1,4 +1,4 @@
1
- import { type PlaybookRuntime } from './decide.playbook.js';
1
+ import { type DecidePlaybookHostCapabilities, type PlaybookRuntime } from './decide.playbook.js';
2
2
  export interface PlaybookSummaryPolicy {
3
3
  stateCountLabels: Readonly<Record<string, string>>;
4
4
  copyPasteGuardNames: readonly string[];
@@ -12,12 +12,16 @@ export interface DecidePlaybookRegistryEntry {
12
12
  id: 'decide';
13
13
  command: 'decide';
14
14
  intent: string;
15
- artifactSchema: 2;
15
+ artifactSchema: 3;
16
+ runtimeProfile: {
17
+ readonly kind: 'bespoke';
18
+ readonly artifactSchema: 3;
19
+ };
16
20
  requiredRoleIds: readonly ['coder', 'reviewer'];
17
21
  concurrentRoleSets: readonly [readonly ['coder', 'reviewer']];
18
22
  summaryPolicy: PlaybookSummaryPolicy;
19
23
  validateOptions(optionSlice: unknown): DecideOptions;
20
- createRuntime(options: DecideOptions): PlaybookRuntime;
24
+ createRuntime(options: DecideOptions, hostCapabilities: DecidePlaybookHostCapabilities): PlaybookRuntime;
21
25
  }
22
26
  export declare const decideStateCountLabels: {
23
27
  readonly independentProposals: "proposal round";
@@ -42,13 +42,20 @@ export const decidePlaybookRegistryEntry = {
42
42
  id: 'decide',
43
43
  command: 'decide',
44
44
  intent: 'turn independent Coder and Reviewer proposals into an approved spec-design commit',
45
- artifactSchema: 2,
45
+ artifactSchema: 3,
46
+ runtimeProfile: Object.freeze({
47
+ kind: 'bespoke',
48
+ artifactSchema: 3,
49
+ }),
46
50
  requiredRoleIds: ['coder', 'reviewer'],
47
51
  concurrentRoleSets: [['coder', 'reviewer']],
48
52
  summaryPolicy: decideSummaryPolicy,
49
53
  validateOptions: validateDecideOptions,
50
- createRuntime(options) {
51
- return createPlaybookRuntime(options);
54
+ createRuntime(options, hostCapabilities) {
55
+ return createPlaybookRuntime({
56
+ configuredOptions: options,
57
+ hostCapabilities,
58
+ });
52
59
  },
53
60
  };
54
61
  export default decidePlaybookRegistryEntry;
@@ -2,6 +2,7 @@
2
2
  // SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
3
3
 
4
4
  import createPlaybookRuntime, {
5
+ type DecidePlaybookHostCapabilities,
5
6
  type PlaybookRuntime,
6
7
  } from './decide.playbook.js';
7
8
 
@@ -20,12 +21,19 @@ export interface DecidePlaybookRegistryEntry {
20
21
  id: 'decide';
21
22
  command: 'decide';
22
23
  intent: string;
23
- artifactSchema: 2;
24
+ artifactSchema: 3;
25
+ runtimeProfile: {
26
+ readonly kind: 'bespoke';
27
+ readonly artifactSchema: 3;
28
+ };
24
29
  requiredRoleIds: readonly ['coder', 'reviewer'];
25
30
  concurrentRoleSets: readonly [readonly ['coder', 'reviewer']];
26
31
  summaryPolicy: PlaybookSummaryPolicy;
27
32
  validateOptions(optionSlice: unknown): DecideOptions;
28
- createRuntime(options: DecideOptions): PlaybookRuntime;
33
+ createRuntime(
34
+ options: DecideOptions,
35
+ hostCapabilities: DecidePlaybookHostCapabilities,
36
+ ): PlaybookRuntime;
29
37
  }
30
38
 
31
39
  export const decideStateCountLabels = {
@@ -88,13 +96,20 @@ export const decidePlaybookRegistryEntry: DecidePlaybookRegistryEntry = {
88
96
  command: 'decide',
89
97
  intent:
90
98
  'turn independent Coder and Reviewer proposals into an approved spec-design commit',
91
- artifactSchema: 2,
99
+ artifactSchema: 3,
100
+ runtimeProfile: Object.freeze({
101
+ kind: 'bespoke',
102
+ artifactSchema: 3,
103
+ }),
92
104
  requiredRoleIds: ['coder', 'reviewer'],
93
105
  concurrentRoleSets: [['coder', 'reviewer']],
94
106
  summaryPolicy: decideSummaryPolicy,
95
107
  validateOptions: validateDecideOptions,
96
- createRuntime(options) {
97
- return createPlaybookRuntime(options);
108
+ createRuntime(options, hostCapabilities) {
109
+ return createPlaybookRuntime({
110
+ configuredOptions: options,
111
+ hostCapabilities,
112
+ });
98
113
  },
99
114
  };
100
115
 
@@ -9,45 +9,55 @@ Roles:
9
9
  - Coder
10
10
  - Reviewer
11
11
 
12
- The caller supplies the initial intent or any specific context and relevant run results.
12
+ The caller supplies:
13
13
 
14
- `review` examines committed work only.
15
- Every review round begins with a new or existing commit.
14
+ - the original intent;
15
+ - the review scope in the caller's own words;
16
+ - optional relevant context and run results.
16
17
 
17
- At the first review round, Captain shall relay to Reviewer the complete initial review request in quotes (`>`).
18
+ The caller's review scope is the baseline for every round, and each review-fix commit joins that scope as it lands, so every later round reviews the cumulative committed state.
19
+ `review` examines committed work only.
20
+ Captain shall take the evaluated repository revision from repository authority, not from either player's prose.
18
21
 
19
22
  At the first review round, Captain shall give Reviewer the following instruction:
20
23
 
21
24
  ```markdown
22
- A new review begins on the latest commit.
23
- Review the latest commit and resulting repository state; read the commit message first for its intent, scope, and rationale.
25
+ A new review begins for the review scope.
26
+ Keep to the original intent and follow what it asks.
27
+ When the scope names commits, read each commit message for its context and rationale; otherwise use repository history and commit messages wherever they help establish that context.
24
28
  ```
25
29
 
26
30
  After every review-fix commit, Captain shall give Reviewer the following instruction:
27
31
 
28
32
  ```markdown
29
- Review the latest commit and resulting repository state; read the commit message first for its intent, scope, and rationale.
33
+ A new review round begins for the review scope in the cumulative committed state, with particular attention to the latest review-fix commit.
34
+ Keep to the original intent and follow what it asks.
35
+ Read the latest review-fix commit's message and see Coder's feedback below.
30
36
  ```
31
37
 
32
38
  When Coder rejects every finding and makes no commit, Captain shall give Reviewer the following instruction:
33
39
 
34
40
  ```markdown
35
41
  No new commit was made because Coder rejected every finding.
42
+ See Coder's feedback below.
36
43
  ```
37
44
 
38
- At the start of *every* review round, Captain shall relay to Reviewer any Coder feedback from the preceding round and any relevant run results, in quotes (`>`) after the instruction.
45
+ At the start of *every* review round, Captain shall relay to Reviewer the original intent, the review scope and context, the exact repository revision being evaluated, any Coder feedback from the preceding round, and any relevant run results, in quotes (`>`) after the instruction.
39
46
 
40
47
  At the start of *every* review round, Captain shall append the following instruction to the end of the prompt:
41
48
 
42
49
  ```markdown
43
50
  Understand the full picture and think systematically about the underlying design.
44
- Continue to identify issues or improvements, if any (numbered; no duplication).
45
- For any rebuttal, accept or challenge it.
46
- Treat as settled, and do not raise again, any finding in this review rejected twice with reasoning.
51
+ Continue to identify issues or improvements, if any, without duplication.
52
+ Number the findings consistently across rounds.
47
53
  Flag only what materially affects correctness, behavior, or spec quality — not style, equally valid alternatives, or theoretical threats.
48
- For specs, flag stale, missing, over-specified, or under-specified ones.
54
+ For specs, flag stale, missing, over-specified, or under-specified ones, if any.
49
55
  Avoid unnecessary complexity in code or tests, but flag any fundamental design flaw when leaving it would cost more in later patches than fixing it now.
50
56
 
57
+ If an issue represents a class of defect, find every instance within the review scope worth fixing rather than surfacing one or two per round, which drags out the review.
58
+ For any rebuttal, accept or challenge it.
59
+ Treat as settled, and do not raise again, any finding in this review rejected twice with reasoning.
60
+
51
61
  Do not re-run tests or builds whose inputs have not changed since any previous reported run.
52
62
  Do not edit files or commit; report findings only.
53
63
 
@@ -55,26 +65,34 @@ Consult @specs/map.md for context if needed; verify it remains accurate.
55
65
  Consult @specs/meta.md for spec requirements if needed; verify affected specs follow it.
56
66
  ```
57
67
 
58
- When Reviewer raises or keeps any finding, Captain shall relay the Reviewer's findings and any relevant run results to Coder, in quotes (`>`), along with the following prompt:
68
+ Finding numbers are references within this review only.
69
+ No review transition shall depend on numbering or any fixed presentation format of either player's reply.
70
+
71
+ When Reviewer raises or keeps any finding, Captain shall relay the original intent, the review scope and context, the exact repository revision being evaluated, the Reviewer's findings, and any relevant run results to Coder, in quotes (`>`), along with the following prompt:
59
72
 
60
73
  ```markdown
61
74
  For each review item, accept or reject it.
62
75
  Before deciding, understand the full picture and think systematically about the underlying design.
76
+ Keep to the original intent and follow what it asks.
63
77
  Reject anything that is not essential or is not worth fixing now.
64
- If you accept an item, fix its root cause, including any fundamental design flaw - do not patch around it.
78
+ If you accept an item, fix its root cause, including any fundamental design flaw do not patch around it; if it represents a class of defect, find every instance within the review scope worth fixing rather than addressing one or two per round, which drags out the review.
65
79
  If you reject an item, give the reasoning and cite code or test output that supports it.
66
80
  Do not re-run tests or builds whose inputs have not changed since any previous reported run.
67
81
 
68
- If you accept any item, make minimal changes and commit them as one new commit; never amend the reviewed commit.
82
+ If you accept any item, make minimal changes and add one new review-fix commit; never rewrite any existing commit.
69
83
  Follow @specs/packages/git.md.
70
84
  Make the commit message explain concisely what changed and why, including relevant verification.
71
- Coder is <coder-llm>; Reviewer is <reviewer-llm>; format model tokens in conventional human form.
85
+ Identify every new commit you make.
86
+ Coder is <coder-llm>; Reviewer is <reviewer-llm>.
72
87
 
73
88
  If you reject every item, change nothing and make no commit.
74
89
  Report every disposition, all relevant run results, and every rebuttal.
75
90
  ```
76
91
 
92
+ Captain shall use the repository-effect receipt as the authoritative identity of any review-fix commit.
93
+
77
94
  When Coder makes a new commit or decides to reject all findings, Captain shall relay the above required context to Reviewer and begin the next review round.
78
95
  Reviewer shall read the context information and follow the corresponding instructions.
79
- Rounds continue until Reviewer raises no unsettled findings.
80
- `review` then returns the approved latest commit and the fact that no findings remain to its caller.
96
+ Rounds continue until Reviewer affirmatively reports that the requested review is complete and no unsettled findings remain.
97
+ A progress report, status update, or promise of a later result supports no review outcome.
98
+ `review` then returns the exact repository revision at which the review scope was evaluated and the fact that no unsettled findings remain within that scope.
@@ -81,6 +81,13 @@ export declare const reviewMachine: import("xstate").StateMachine<ReviewContext,
81
81
  logic: import("xstate").PromiseActorLogic<PlayerOutput, PlayerInput, import("xstate").EventObject>;
82
82
  id: string | undefined;
83
83
  }, {
84
+ type: "playbook.acceptedOutcome";
85
+ params: {
86
+ readonly source: string;
87
+ readonly target: string;
88
+ readonly acceptedOutcome: string;
89
+ };
90
+ } | {
84
91
  type: "rememberActorError";
85
92
  params: import("xstate").NonReducibleUnknown;
86
93
  } | {
@@ -170,6 +170,7 @@ export const reviewMachine = setup({
170
170
  event.bossIntent.trim().length > 0,
171
171
  },
172
172
  actions: {
173
+ 'playbook.acceptedOutcome': (_args, _params) => undefined,
173
174
  copyStartInput: assign({
174
175
  callerInput: ({ event }) => event.type === 'START_REVIEW' ? event.callerInput : undefined,
175
176
  reviewerOutput: undefined,
@@ -320,17 +321,47 @@ export const reviewMachine = setup({
320
321
  {
321
322
  guard: 'hasFindings',
322
323
  target: '#addressFindings',
323
- actions: 'rememberReviewerOutput',
324
+ actions: [
325
+ {
326
+ type: 'playbook.acceptedOutcome',
327
+ params: {
328
+ source: 'reviewInitial',
329
+ target: 'addressFindings',
330
+ acceptedOutcome: 'hasFindings',
331
+ },
332
+ },
333
+ 'rememberReviewerOutput',
334
+ ],
324
335
  },
325
336
  {
326
337
  guard: 'noFindings',
327
338
  target: '#done',
328
- actions: 'clearBossReplyContext',
339
+ actions: [
340
+ {
341
+ type: 'playbook.acceptedOutcome',
342
+ params: {
343
+ source: 'reviewInitial',
344
+ target: 'done',
345
+ acceptedOutcome: 'noFindings',
346
+ },
347
+ },
348
+ 'clearBossReplyContext',
349
+ ],
329
350
  },
330
351
  {
331
352
  guard: 'needsBossReply',
332
353
  target: '#awaitBossReply',
333
- actions: 'setPendingReviewInitial',
354
+ actions: [
355
+ {
356
+ type: 'playbook.acceptedOutcome',
357
+ params: {
358
+ source: 'reviewInitial',
359
+ target: 'awaitBossReply',
360
+ acceptedOutcome: 'needsBossReply',
361
+ },
362
+ },
363
+ 'setPendingReviewInitial',
364
+ ],
334
365
  },
335
366
  ],
336
367
  onError: {
@@ -360,17 +391,47 @@ export const reviewMachine = setup({
360
391
  {
361
392
  guard: 'committed',
362
393
  target: '#reviewAfterCommit',
363
- actions: 'rememberCoderOutput',
394
+ actions: [
395
+ {
396
+ type: 'playbook.acceptedOutcome',
397
+ params: {
398
+ source: 'addressFindings',
399
+ target: 'reviewAfterCommit',
400
+ acceptedOutcome: 'committed',
401
+ },
402
+ },
403
+ 'rememberCoderOutput',
404
+ ],
364
405
  },
365
406
  {
366
407
  guard: 'rejectedAll',
367
408
  target: '#reviewAfterRebuttal',
368
- actions: 'rememberCoderOutput',
409
+ actions: [
410
+ {
411
+ type: 'playbook.acceptedOutcome',
412
+ params: {
413
+ source: 'addressFindings',
414
+ target: 'reviewAfterRebuttal',
415
+ acceptedOutcome: 'rejectedAll',
416
+ },
417
+ },
418
+ 'rememberCoderOutput',
419
+ ],
369
420
  },
370
421
  {
371
422
  guard: 'needsBossReply',
372
423
  target: '#awaitBossReply',
373
- actions: 'setPendingAddressFindings',
424
+ actions: [
425
+ {
426
+ type: 'playbook.acceptedOutcome',
427
+ params: {
428
+ source: 'addressFindings',
429
+ target: 'awaitBossReply',
430
+ acceptedOutcome: 'needsBossReply',
431
+ },
432
+ },
433
+ 'setPendingAddressFindings',
434
+ ],
374
435
  },
375
436
  ],
376
437
  onError: {
@@ -400,17 +461,47 @@ export const reviewMachine = setup({
400
461
  {
401
462
  guard: 'hasFindings',
402
463
  target: '#addressFindings',
403
- actions: 'rememberReviewerOutput',
464
+ actions: [
465
+ {
466
+ type: 'playbook.acceptedOutcome',
467
+ params: {
468
+ source: 'reviewAfterCommit',
469
+ target: 'addressFindings',
470
+ acceptedOutcome: 'hasFindings',
471
+ },
472
+ },
473
+ 'rememberReviewerOutput',
474
+ ],
404
475
  },
405
476
  {
406
477
  guard: 'noFindings',
407
478
  target: '#done',
408
- actions: 'clearBossReplyContext',
479
+ actions: [
480
+ {
481
+ type: 'playbook.acceptedOutcome',
482
+ params: {
483
+ source: 'reviewAfterCommit',
484
+ target: 'done',
485
+ acceptedOutcome: 'noFindings',
486
+ },
487
+ },
488
+ 'clearBossReplyContext',
489
+ ],
409
490
  },
410
491
  {
411
492
  guard: 'needsBossReply',
412
493
  target: '#awaitBossReply',
413
- actions: 'setPendingReviewAfterCommit',
494
+ actions: [
495
+ {
496
+ type: 'playbook.acceptedOutcome',
497
+ params: {
498
+ source: 'reviewAfterCommit',
499
+ target: 'awaitBossReply',
500
+ acceptedOutcome: 'needsBossReply',
501
+ },
502
+ },
503
+ 'setPendingReviewAfterCommit',
504
+ ],
414
505
  },
415
506
  ],
416
507
  onError: {
@@ -440,17 +531,47 @@ export const reviewMachine = setup({
440
531
  {
441
532
  guard: 'hasFindings',
442
533
  target: '#addressFindings',
443
- actions: 'rememberReviewerOutput',
534
+ actions: [
535
+ {
536
+ type: 'playbook.acceptedOutcome',
537
+ params: {
538
+ source: 'reviewAfterRebuttal',
539
+ target: 'addressFindings',
540
+ acceptedOutcome: 'hasFindings',
541
+ },
542
+ },
543
+ 'rememberReviewerOutput',
544
+ ],
444
545
  },
445
546
  {
446
547
  guard: 'noFindings',
447
548
  target: '#done',
448
- actions: 'clearBossReplyContext',
549
+ actions: [
550
+ {
551
+ type: 'playbook.acceptedOutcome',
552
+ params: {
553
+ source: 'reviewAfterRebuttal',
554
+ target: 'done',
555
+ acceptedOutcome: 'noFindings',
556
+ },
557
+ },
558
+ 'clearBossReplyContext',
559
+ ],
449
560
  },
450
561
  {
451
562
  guard: 'needsBossReply',
452
563
  target: '#awaitBossReply',
453
- actions: 'setPendingReviewAfterRebuttal',
564
+ actions: [
565
+ {
566
+ type: 'playbook.acceptedOutcome',
567
+ params: {
568
+ source: 'reviewAfterRebuttal',
569
+ target: 'awaitBossReply',
570
+ acceptedOutcome: 'needsBossReply',
571
+ },
572
+ },
573
+ 'setPendingReviewAfterRebuttal',
574
+ ],
454
575
  },
455
576
  ],
456
577
  onError: {
@@ -292,6 +292,14 @@ export const reviewMachine = setup({
292
292
  event.bossIntent.trim().length > 0,
293
293
  },
294
294
  actions: {
295
+ 'playbook.acceptedOutcome': (
296
+ _args,
297
+ _params: {
298
+ readonly source: string;
299
+ readonly target: string;
300
+ readonly acceptedOutcome: string;
301
+ },
302
+ ) => undefined,
295
303
  copyStartInput: assign({
296
304
  callerInput: ({ event }) =>
297
305
  event.type === 'START_REVIEW' ? event.callerInput : undefined,
@@ -446,17 +454,47 @@ export const reviewMachine = setup({
446
454
  {
447
455
  guard: 'hasFindings',
448
456
  target: '#addressFindings',
449
- actions: 'rememberReviewerOutput',
457
+ actions: [
458
+ {
459
+ type: 'playbook.acceptedOutcome',
460
+ params: {
461
+ source: 'reviewInitial',
462
+ target: 'addressFindings',
463
+ acceptedOutcome: 'hasFindings',
464
+ },
465
+ },
466
+ 'rememberReviewerOutput',
467
+ ],
450
468
  },
451
469
  {
452
470
  guard: 'noFindings',
453
471
  target: '#done',
454
- actions: 'clearBossReplyContext',
472
+ actions: [
473
+ {
474
+ type: 'playbook.acceptedOutcome',
475
+ params: {
476
+ source: 'reviewInitial',
477
+ target: 'done',
478
+ acceptedOutcome: 'noFindings',
479
+ },
480
+ },
481
+ 'clearBossReplyContext',
482
+ ],
455
483
  },
456
484
  {
457
485
  guard: 'needsBossReply',
458
486
  target: '#awaitBossReply',
459
- actions: 'setPendingReviewInitial',
487
+ actions: [
488
+ {
489
+ type: 'playbook.acceptedOutcome',
490
+ params: {
491
+ source: 'reviewInitial',
492
+ target: 'awaitBossReply',
493
+ acceptedOutcome: 'needsBossReply',
494
+ },
495
+ },
496
+ 'setPendingReviewInitial',
497
+ ],
460
498
  },
461
499
  ],
462
500
  onError: {
@@ -486,17 +524,47 @@ export const reviewMachine = setup({
486
524
  {
487
525
  guard: 'committed',
488
526
  target: '#reviewAfterCommit',
489
- actions: 'rememberCoderOutput',
527
+ actions: [
528
+ {
529
+ type: 'playbook.acceptedOutcome',
530
+ params: {
531
+ source: 'addressFindings',
532
+ target: 'reviewAfterCommit',
533
+ acceptedOutcome: 'committed',
534
+ },
535
+ },
536
+ 'rememberCoderOutput',
537
+ ],
490
538
  },
491
539
  {
492
540
  guard: 'rejectedAll',
493
541
  target: '#reviewAfterRebuttal',
494
- actions: 'rememberCoderOutput',
542
+ actions: [
543
+ {
544
+ type: 'playbook.acceptedOutcome',
545
+ params: {
546
+ source: 'addressFindings',
547
+ target: 'reviewAfterRebuttal',
548
+ acceptedOutcome: 'rejectedAll',
549
+ },
550
+ },
551
+ 'rememberCoderOutput',
552
+ ],
495
553
  },
496
554
  {
497
555
  guard: 'needsBossReply',
498
556
  target: '#awaitBossReply',
499
- actions: 'setPendingAddressFindings',
557
+ actions: [
558
+ {
559
+ type: 'playbook.acceptedOutcome',
560
+ params: {
561
+ source: 'addressFindings',
562
+ target: 'awaitBossReply',
563
+ acceptedOutcome: 'needsBossReply',
564
+ },
565
+ },
566
+ 'setPendingAddressFindings',
567
+ ],
500
568
  },
501
569
  ],
502
570
  onError: {
@@ -526,17 +594,47 @@ export const reviewMachine = setup({
526
594
  {
527
595
  guard: 'hasFindings',
528
596
  target: '#addressFindings',
529
- actions: 'rememberReviewerOutput',
597
+ actions: [
598
+ {
599
+ type: 'playbook.acceptedOutcome',
600
+ params: {
601
+ source: 'reviewAfterCommit',
602
+ target: 'addressFindings',
603
+ acceptedOutcome: 'hasFindings',
604
+ },
605
+ },
606
+ 'rememberReviewerOutput',
607
+ ],
530
608
  },
531
609
  {
532
610
  guard: 'noFindings',
533
611
  target: '#done',
534
- actions: 'clearBossReplyContext',
612
+ actions: [
613
+ {
614
+ type: 'playbook.acceptedOutcome',
615
+ params: {
616
+ source: 'reviewAfterCommit',
617
+ target: 'done',
618
+ acceptedOutcome: 'noFindings',
619
+ },
620
+ },
621
+ 'clearBossReplyContext',
622
+ ],
535
623
  },
536
624
  {
537
625
  guard: 'needsBossReply',
538
626
  target: '#awaitBossReply',
539
- actions: 'setPendingReviewAfterCommit',
627
+ actions: [
628
+ {
629
+ type: 'playbook.acceptedOutcome',
630
+ params: {
631
+ source: 'reviewAfterCommit',
632
+ target: 'awaitBossReply',
633
+ acceptedOutcome: 'needsBossReply',
634
+ },
635
+ },
636
+ 'setPendingReviewAfterCommit',
637
+ ],
540
638
  },
541
639
  ],
542
640
  onError: {
@@ -566,17 +664,47 @@ export const reviewMachine = setup({
566
664
  {
567
665
  guard: 'hasFindings',
568
666
  target: '#addressFindings',
569
- actions: 'rememberReviewerOutput',
667
+ actions: [
668
+ {
669
+ type: 'playbook.acceptedOutcome',
670
+ params: {
671
+ source: 'reviewAfterRebuttal',
672
+ target: 'addressFindings',
673
+ acceptedOutcome: 'hasFindings',
674
+ },
675
+ },
676
+ 'rememberReviewerOutput',
677
+ ],
570
678
  },
571
679
  {
572
680
  guard: 'noFindings',
573
681
  target: '#done',
574
- actions: 'clearBossReplyContext',
682
+ actions: [
683
+ {
684
+ type: 'playbook.acceptedOutcome',
685
+ params: {
686
+ source: 'reviewAfterRebuttal',
687
+ target: 'done',
688
+ acceptedOutcome: 'noFindings',
689
+ },
690
+ },
691
+ 'clearBossReplyContext',
692
+ ],
575
693
  },
576
694
  {
577
695
  guard: 'needsBossReply',
578
696
  target: '#awaitBossReply',
579
- actions: 'setPendingReviewAfterRebuttal',
697
+ actions: [
698
+ {
699
+ type: 'playbook.acceptedOutcome',
700
+ params: {
701
+ source: 'reviewAfterRebuttal',
702
+ target: 'awaitBossReply',
703
+ acceptedOutcome: 'needsBossReply',
704
+ },
705
+ },
706
+ 'setPendingReviewAfterRebuttal',
707
+ ],
580
708
  },
581
709
  ],
582
710
  onError: {