@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
@@ -8,9 +8,10 @@
8
8
 
9
9
  # The Captain and each stable session player carries its own defaults inline:
10
10
  # an adapter shorthand (claude, codex) or a block with
11
- # adapter/model/effort/permissions. A role may override only model or effort.
12
- # Omit an override to inherit the player default; set it to false to select
13
- # that provider's current default explicitly.
11
+ # adapter/model/effort/fastMode/permissions. A role may override only model,
12
+ # effort, or fastMode.
13
+ # Omit an override to inherit the player default. For model and effort, false
14
+ # selects the provider default; fastMode false is a literal disabled request.
14
15
 
15
16
  # Each adapter needs its vendor SDK installed as its own top-level
16
17
  # install root — they are optional peer dependencies, so you pay only
@@ -29,7 +30,7 @@
29
30
  # list, so those captains degrade to a prompt-level restriction (DR-013 A1).
30
31
  captain:
31
32
  adapter: claude
32
- model: claude-opus-4-8
33
+ model: claude-opus-5
33
34
  effort: high
34
35
  permissions:
35
36
  mode: auto
@@ -45,19 +46,22 @@ notifications:
45
46
  # shares one provider conversation across those playbooks.
46
47
  players:
47
48
  dev.coder:
48
- adapter: claude
49
- model: claude-opus-4-8[1m]
50
- effort: xhigh
49
+ adapter: codex
50
+ model: gpt-5.6-sol
51
+ effort: ultra
52
+ # Adapter-scoped fast mode is validated by the installed Cligent contract;
53
+ # omitting it takes the provider default.
54
+ fastMode: true
51
55
  permissions:
52
56
  mode: auto
57
+ writablePaths: ['.git']
53
58
 
54
59
  dev.reviewer:
55
- adapter: codex
56
- model: gpt-5.5
60
+ adapter: claude
61
+ model: claude-opus-5
57
62
  effort: xhigh
58
63
  permissions:
59
64
  mode: auto
60
- writablePaths: ['.git']
61
65
 
62
66
  # Enabled playbooks. Each is loaded from its explicit `from` module; the
63
67
  # `<id>` key must equal that module's manifest id. `from`, `command`, and
@@ -0,0 +1,82 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
3
+
4
+ export declare const RECORDS_STREAM_VERSION: 1;
5
+ export declare function defaultSessionsDir(): string;
6
+ export declare function openSessionStore(
7
+ sessionsDir: string,
8
+ ): PlaybookSessionStore;
9
+
10
+ export type ReplayJsonValue =
11
+ | null
12
+ | boolean
13
+ | number
14
+ | string
15
+ | readonly ReplayJsonValue[]
16
+ | ReplayRecord;
17
+ export type ReplayRecord = {
18
+ readonly [key: string]: ReplayJsonValue;
19
+ };
20
+ export interface ReplayStreamEntry {
21
+ readonly v: 1;
22
+ readonly seq: number;
23
+ readonly role?: string;
24
+ readonly record: ReplayRecord;
25
+ }
26
+ export interface ReplayStreamReadOptions {
27
+ readonly afterSeq?: number;
28
+ }
29
+ export interface ReplayStreamReadResult {
30
+ readonly entries: readonly ReplayStreamEntry[];
31
+ readonly lastReadableSeq: number;
32
+ }
33
+ export interface LeaseReplayStreamReadResult extends ReplayStreamReadResult {
34
+ readonly lastDurableSeq: number;
35
+ readonly incomplete: boolean;
36
+ }
37
+ export type ReplayStreamStatus =
38
+ | {
39
+ readonly lastReadableSeq: number;
40
+ readonly lastDurableSeq: number;
41
+ readonly incomplete: boolean;
42
+ }
43
+ | {
44
+ readonly lastReadableSeq: null;
45
+ readonly lastDurableSeq: null;
46
+ readonly incomplete: true;
47
+ };
48
+ export interface PlaybookSessionSummary {
49
+ readonly schemaVersion: number;
50
+ readonly sessionId: string;
51
+ readonly state: 'settled' | 'uncertain';
52
+ readonly cwd: string;
53
+ readonly updatedAt: string;
54
+ }
55
+ export interface SkippedPlaybookSession {
56
+ readonly sessionId: string;
57
+ readonly reason: string;
58
+ }
59
+ export interface PlaybookSessionListResult {
60
+ readonly sessions: readonly PlaybookSessionSummary[];
61
+ readonly skipped: readonly SkippedPlaybookSession[];
62
+ }
63
+ export interface PlaybookSessionStore {
64
+ readonly sessionsDir: string;
65
+ list(): Promise<PlaybookSessionListResult>;
66
+ read(sessionId: string): Promise<PlaybookSessionSummary>;
67
+ readStream(
68
+ sessionId: string,
69
+ options?: ReplayStreamReadOptions,
70
+ ): Promise<ReplayStreamReadResult>;
71
+ acquire(sessionId: string): Promise<PlaybookSessionLease>;
72
+ }
73
+ export interface PlaybookSessionLease {
74
+ readonly sessionId: string;
75
+ readonly ownerToken: string;
76
+ append(record: object, role?: string): Promise<void>;
77
+ readStream(
78
+ options?: ReplayStreamReadOptions,
79
+ ): Promise<LeaseReplayStreamReadResult>;
80
+ streamStatus(): ReplayStreamStatus;
81
+ release(): Promise<ReplayStreamStatus>;
82
+ }
@@ -0,0 +1,113 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
3
+
4
+ import {
5
+ RECORDS_STREAM_VERSION,
6
+ createCaptainSessionStore,
7
+ defaultCaptainSessionsDir,
8
+ } from './bin/session-store.js';
9
+
10
+ export { RECORDS_STREAM_VERSION };
11
+
12
+ export function defaultSessionsDir() {
13
+ return defaultCaptainSessionsDir();
14
+ }
15
+
16
+ export function openSessionStore(sessionsDir) {
17
+ if (typeof sessionsDir !== 'string') {
18
+ throw new TypeError('session store path must be a string');
19
+ }
20
+ return wrapStore(createCaptainSessionStore({ sessionsDir }));
21
+ }
22
+
23
+ function wrapStore(store) {
24
+ return Object.freeze({
25
+ sessionsDir: store.sessionsDir,
26
+ list: async () => projectListResult(await store.listSummaries()),
27
+ read: async (sessionId) =>
28
+ projectSummary(await store.readSummary(sessionId)),
29
+ readStream: async (sessionId, options) =>
30
+ projectReadResult(await store.readStream(sessionId, options)),
31
+ acquire: async (sessionId) => wrapLease(await store.acquire(sessionId)),
32
+ });
33
+ }
34
+
35
+ function wrapLease(lease) {
36
+ let finalStatus;
37
+ let releaseInFlight;
38
+
39
+ const release = () => {
40
+ if (finalStatus !== undefined) return Promise.resolve(finalStatus);
41
+ if (releaseInFlight !== undefined) return releaseInFlight;
42
+ const operation = lease.release();
43
+ releaseInFlight = operation.then(
44
+ (status) => {
45
+ finalStatus = projectStatus(status);
46
+ return finalStatus;
47
+ },
48
+ (cause) => {
49
+ releaseInFlight = undefined;
50
+ throw cause;
51
+ },
52
+ );
53
+ return releaseInFlight;
54
+ };
55
+
56
+ return Object.freeze({
57
+ sessionId: lease.sessionId,
58
+ ownerToken: lease.ownerToken,
59
+ append: (record, role) => lease.append(record, role),
60
+ readStream: async (options) => {
61
+ if (finalStatus !== undefined) {
62
+ throw new Error('released session lease has no live replay reader');
63
+ }
64
+ return projectLeaseReadResult(await lease.readStream(options));
65
+ },
66
+ streamStatus: () => finalStatus ?? projectStatus(lease.streamStatus()),
67
+ release,
68
+ });
69
+ }
70
+
71
+ function projectListResult(result) {
72
+ return Object.freeze({
73
+ sessions: Object.freeze(result.sessions.map(projectSummary)),
74
+ skipped: Object.freeze(
75
+ result.skipped.map(({ sessionId, reason }) =>
76
+ Object.freeze({ sessionId, reason }),
77
+ ),
78
+ ),
79
+ });
80
+ }
81
+
82
+ function projectSummary(summary) {
83
+ return Object.freeze({
84
+ schemaVersion: summary.schemaVersion,
85
+ sessionId: summary.sessionId,
86
+ state: summary.state,
87
+ cwd: summary.cwd,
88
+ updatedAt: summary.updatedAt,
89
+ });
90
+ }
91
+
92
+ function projectReadResult(result) {
93
+ return Object.freeze({
94
+ entries: Object.freeze([...result.entries]),
95
+ lastReadableSeq: result.lastReadableSeq,
96
+ });
97
+ }
98
+
99
+ function projectLeaseReadResult(result) {
100
+ return Object.freeze({
101
+ ...projectReadResult(result),
102
+ lastDurableSeq: result.lastDurableSeq,
103
+ incomplete: result.incomplete,
104
+ });
105
+ }
106
+
107
+ function projectStatus(status) {
108
+ return Object.freeze({
109
+ lastReadableSeq: status.lastReadableSeq,
110
+ lastDurableSeq: status.lastDurableSeq,
111
+ incomplete: status.incomplete,
112
+ });
113
+ }
@@ -23,32 +23,40 @@ Consult @specs/map.md for relevant context and @specs/meta.md for spec requireme
23
23
  Do not change any files.
24
24
  ```
25
25
 
26
- Neither role's player shall receive the other role's proposal until both proposals are complete and Coder has committed Coder's own proposal.
26
+ Neither role's player shall receive the other role's proposal until both proposals are complete.
27
+ Each proposal is complete only when its player affirmatively provides a complete design proposal.
28
+ A progress report, status update, or promise of a later proposal supports no proposal outcome.
27
29
  A Boss interrupt during the parallel proposal pair shall restart the whole pair so both players receive the same new topic and remain independent.
28
30
 
29
- When both proposals are complete, Captain shall then give Coder the following instruction:
31
+ When both proposals are complete, Captain shall give Coder the following instruction, with the complete topic and Reviewer's complete proposal inserted under their own labels in quotes (`>`):
30
32
 
31
33
  ```markdown
32
- Turn your proposal into the necessary spec items or DRs.
34
+ Synthesize your independent proposal with Reviewer's proposal below.
35
+ Keep to the original topic below and follow what it asks.
36
+ Keep the best, essential parts of either proposal and reject any point that is unsound, unnecessary, or outside the topic.
37
+ Turn the resulting design into the necessary DRs and/or spec items.
33
38
  Follow @specs/meta.md and update @specs/map.md when needed.
34
- Do not inspect or incorporate Reviewer's proposal before this commit.
35
- Do not change code or implement the proposal.
39
+ Do not change code or implement the design.
36
40
 
37
41
  Commit the result as one new commit, following @specs/packages/git.md.
38
42
  Make the commit message explain concisely what changed and why.
39
- Include exactly one final-response line beginning `Commit: `, followed only by the exact commit identity; other final-response content may appear on other lines.
40
- Coder is <coder-llm>; format the model token in conventional human form.
43
+ Identify every new commit you make.
44
+ Coder is <coder-llm> and Reviewer is <reviewer-llm>.
45
+
46
+ > Original topic: \<caller-topic\>
47
+ > Reviewer's independent proposal: \<reviewer-proposal\>
41
48
  ```
42
49
 
43
- After Coder commits, Captain shall call playbook `review`:
50
+ No transition shall depend on a fixed presentation format of either player's reply.
51
+ Captain shall use the repository-effect receipt as the authoritative identity of Coder's new `decide`-owned commit.
52
+
53
+ After Coder commits, Captain shall call playbook `review` with the following input in quotes (`>`):
44
54
 
45
- > Review the latest commit as a spec-design change against the initial intent.
46
- > Compare it with your independent proposal and take the best of both.
47
- > Make your suggestions.
48
- >
49
- > Initial intent: \<caller-topic\>.
50
- > Coder's independent proposal: \<coder-proposal\>.
55
+ > Original intent: \<caller-topic\>
56
+ > Review scope: the `decide`-owned commit \<decide-commit\> and its resulting repository state.
57
+ > Coder output: \<coder-output\>
51
58
 
52
- `decide` is complete when `review` returns the approved latest commit and the fact that no unsettled findings remain.
53
- When `review` returns an authored abort or failure, or a terminal result that does not prove exact approval, `decide` shall report the failure and the last `decide`-owned commit to its caller.
59
+ `decide` is complete only when `review` returns a result that applies to the supplied review scope, gives the exact evaluated repository revision, and affirmatively establishes that no unsettled findings remain.
60
+ It then returns the `decide`-owned commit and that evaluated revision to its caller.
61
+ When `review` returns an authored abort or failure, or a terminal result that does not establish those facts, `decide` shall report the failure and the last `decide`-owned commit to its caller.
54
62
  When the nested `review` call fails outside that authored result contract, `decide` shall park as failed and retain the control-plane error instead of reporting an authored review outcome.
@@ -127,6 +127,13 @@ export declare const decideMachine: import("xstate").StateMachine<DecideContext,
127
127
  logic: import("xstate").PromiseActorLogic<PlayerOutput, PlayerInput, import("xstate").EventObject>;
128
128
  id: string | undefined;
129
129
  }, {
130
+ type: "playbook.acceptedOutcome";
131
+ params: {
132
+ readonly source: string;
133
+ readonly target: string;
134
+ readonly acceptedOutcome: string;
135
+ };
136
+ } | {
130
137
  type: "rememberActorError";
131
138
  params: import("xstate").NonReducibleUnknown;
132
139
  } | {
@@ -23,7 +23,6 @@ const COMMIT_CODER_PROMPT = [
23
23
  '',
24
24
  'Commit the result as one new commit, following @specs/packages/git.md.',
25
25
  'Make the commit message explain concisely what changed and why.',
26
- 'Include exactly one final-response line beginning `Commit: `, followed only by the exact commit identity; other final-response content may appear on other lines.',
27
26
  'Coder is <coder-llm>; format the model token in conventional human form.',
28
27
  ].join('\n');
29
28
  const REVIEW_INPUT_TEMPLATE = [
@@ -59,13 +58,6 @@ function commitOutput(event) {
59
58
  !isNonEmptyString(output.latestCommit)) {
60
59
  return undefined;
61
60
  }
62
- const commitLines = output.coderOutput
63
- .split('\n')
64
- .filter((line) => line.startsWith('Commit: '));
65
- if (commitLines.length !== 1 ||
66
- commitLines[0] !== `Commit: ${output.latestCommit}`) {
67
- return undefined;
68
- }
69
61
  return {
70
62
  coderOutput: output.coderOutput,
71
63
  latestCommit: output.latestCommit,
@@ -305,6 +297,7 @@ export const decideMachine = setup({
305
297
  }),
306
298
  },
307
299
  actions: {
300
+ 'playbook.acceptedOutcome': (_args, _params) => undefined,
308
301
  copyStartTopic: assign({
309
302
  callerTopic: ({ event }) => event.type === 'START_DECIDE' ? event.callerTopic : undefined,
310
303
  coderProposal: undefined,
@@ -514,14 +507,24 @@ export const decideMachine = setup({
514
507
  {
515
508
  guard: 'needsBossReplyWithQuestion',
516
509
  target: 'waiting',
517
- actions: {
518
- type: 'setPendingBossQuestion',
519
- params: {
520
- ...stateMetadata.askCoderProposal,
521
- resumeStateId: 'askCoderProposal',
522
- question: '',
510
+ actions: [
511
+ {
512
+ type: 'playbook.acceptedOutcome',
513
+ params: {
514
+ source: 'askCoderProposal',
515
+ target: 'waitCoderProposalReply',
516
+ acceptedOutcome: 'needsBossReply',
517
+ },
523
518
  },
524
- },
519
+ {
520
+ type: 'setPendingBossQuestion',
521
+ params: {
522
+ ...stateMetadata.askCoderProposal,
523
+ resumeStateId: 'askCoderProposal',
524
+ question: '',
525
+ },
526
+ },
527
+ ],
525
528
  },
526
529
  {
527
530
  guard: 'needsBossReplyWithoutQuestion',
@@ -535,6 +538,16 @@ export const decideMachine = setup({
535
538
  guard: 'coderProposed',
536
539
  target: 'complete',
537
540
  actions: [
541
+ {
542
+ type: 'playbook.acceptedOutcome',
543
+ params: ({ context }) => ({
544
+ source: 'askCoderProposal',
545
+ target: context.stagedReviewerResult === undefined
546
+ ? 'coderProposalComplete'
547
+ : 'commitCoderProposal',
548
+ acceptedOutcome: 'proposed',
549
+ }),
550
+ },
538
551
  'stageCoderProposal',
539
552
  {
540
553
  type: 'clearBranchBossReplyContext',
@@ -630,14 +643,24 @@ export const decideMachine = setup({
630
643
  {
631
644
  guard: 'needsBossReplyWithQuestion',
632
645
  target: 'waiting',
633
- actions: {
634
- type: 'setPendingBossQuestion',
635
- params: {
636
- ...stateMetadata.askReviewerProposal,
637
- resumeStateId: 'askReviewerProposal',
638
- question: '',
646
+ actions: [
647
+ {
648
+ type: 'playbook.acceptedOutcome',
649
+ params: {
650
+ source: 'askReviewerProposal',
651
+ target: 'waitReviewerProposalReply',
652
+ acceptedOutcome: 'needsBossReply',
653
+ },
639
654
  },
640
- },
655
+ {
656
+ type: 'setPendingBossQuestion',
657
+ params: {
658
+ ...stateMetadata.askReviewerProposal,
659
+ resumeStateId: 'askReviewerProposal',
660
+ question: '',
661
+ },
662
+ },
663
+ ],
641
664
  },
642
665
  {
643
666
  guard: 'needsBossReplyWithoutQuestion',
@@ -651,6 +674,16 @@ export const decideMachine = setup({
651
674
  guard: 'reviewerProposed',
652
675
  target: 'complete',
653
676
  actions: [
677
+ {
678
+ type: 'playbook.acceptedOutcome',
679
+ params: ({ context }) => ({
680
+ source: 'askReviewerProposal',
681
+ target: context.stagedCoderResult === undefined
682
+ ? 'reviewerProposalComplete'
683
+ : 'commitCoderProposal',
684
+ acceptedOutcome: 'proposed',
685
+ }),
686
+ },
654
687
  'stageReviewerProposal',
655
688
  {
656
689
  type: 'clearBranchBossReplyContext',
@@ -748,14 +781,24 @@ export const decideMachine = setup({
748
781
  {
749
782
  guard: 'needsBossReplyWithQuestion',
750
783
  target: 'awaitBossReply',
751
- actions: {
752
- type: 'setPendingBossQuestion',
753
- params: {
754
- ...stateMetadata.commitCoderProposal,
755
- resumeStateId: 'commitCoderProposal',
756
- question: '',
784
+ actions: [
785
+ {
786
+ type: 'playbook.acceptedOutcome',
787
+ params: {
788
+ source: 'commitCoderProposal',
789
+ target: 'awaitBossReply',
790
+ acceptedOutcome: 'needsBossReply',
791
+ },
757
792
  },
758
- },
793
+ {
794
+ type: 'setPendingBossQuestion',
795
+ params: {
796
+ ...stateMetadata.commitCoderProposal,
797
+ resumeStateId: 'commitCoderProposal',
798
+ question: '',
799
+ },
800
+ },
801
+ ],
759
802
  },
760
803
  {
761
804
  guard: 'needsBossReplyWithoutQuestion',
@@ -769,6 +812,14 @@ export const decideMachine = setup({
769
812
  guard: 'committed',
770
813
  target: 'reviewCommit',
771
814
  actions: [
815
+ {
816
+ type: 'playbook.acceptedOutcome',
817
+ params: {
818
+ source: 'commitCoderProposal',
819
+ target: 'reviewCommit',
820
+ acceptedOutcome: 'committed',
821
+ },
822
+ },
772
823
  'rememberCommit',
773
824
  {
774
825
  type: 'clearBranchBossReplyContext',