@sublang/playbook 15.0.0 → 16.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 (81) hide show
  1. package/README.md +1 -1
  2. package/docs/embedding.md +9 -7
  3. package/package.json +3 -1
  4. package/reference/sdlc/branch.playbook/branch.fsm.d.ts +63 -33
  5. package/reference/sdlc/branch.playbook/branch.fsm.js +190 -108
  6. package/reference/sdlc/branch.playbook/branch.fsm.ts +269 -147
  7. package/reference/sdlc/branch.playbook/branch.gears.md +7 -17
  8. package/reference/sdlc/branch.playbook/branch.playbook.d.ts +12 -16
  9. package/reference/sdlc/branch.playbook/branch.playbook.js +112 -101
  10. package/reference/sdlc/branch.playbook/branch.playbook.ts +128 -171
  11. package/reference/sdlc/branch.playbook/branch.registry.d.ts +3 -2
  12. package/reference/sdlc/branch.playbook/branch.registry.ts +6 -2
  13. package/reference/sdlc/code.playbook/bin/repository-effects.js +54 -13
  14. package/reference/sdlc/code.playbook/code.fsm.d.ts +143 -90
  15. package/reference/sdlc/code.playbook/code.fsm.introspect.d.ts +8 -8
  16. package/reference/sdlc/code.playbook/code.fsm.introspect.ts +13 -13
  17. package/reference/sdlc/code.playbook/code.fsm.js +609 -649
  18. package/reference/sdlc/code.playbook/code.fsm.ts +890 -821
  19. package/reference/sdlc/code.playbook/code.gears.md +39 -29
  20. package/reference/sdlc/code.playbook/code.playbook.d.ts +13 -16
  21. package/reference/sdlc/code.playbook/code.playbook.js +166 -147
  22. package/reference/sdlc/code.playbook/code.playbook.ts +180 -229
  23. package/reference/sdlc/code.playbook/code.registry.d.ts +3 -2
  24. package/reference/sdlc/code.playbook/code.registry.ts +6 -2
  25. package/reference/sdlc/code.playbook/playbook-captain.d.ts +42 -0
  26. package/reference/sdlc/code.playbook/playbook-captain.js +829 -194
  27. package/reference/sdlc/code.playbook/playbook-captain.ts +1227 -220
  28. package/reference/sdlc/decide.md +1 -0
  29. package/reference/sdlc/decide.playbook/decide.fsm.d.ts +270 -154
  30. package/reference/sdlc/decide.playbook/decide.fsm.js +765 -732
  31. package/reference/sdlc/decide.playbook/decide.fsm.ts +1167 -945
  32. package/reference/sdlc/decide.playbook/decide.gears.md +28 -21
  33. package/reference/sdlc/decide.playbook/decide.playbook.d.ts +11 -67
  34. package/reference/sdlc/decide.playbook/decide.playbook.js +155 -3570
  35. package/reference/sdlc/decide.playbook/decide.playbook.ts +186 -5061
  36. package/reference/sdlc/decide.playbook/decide.registry.d.ts +8 -4
  37. package/reference/sdlc/decide.playbook/decide.registry.js +2 -2
  38. package/reference/sdlc/decide.playbook/decide.registry.ts +13 -6
  39. package/reference/sdlc/dev.playbook/dev.fsm.d.ts +113 -131
  40. package/reference/sdlc/dev.playbook/dev.fsm.js +517 -575
  41. package/reference/sdlc/dev.playbook/dev.fsm.ts +667 -787
  42. package/reference/sdlc/dev.playbook/dev.gears.md +52 -54
  43. package/reference/sdlc/dev.playbook/dev.playbook.d.ts +13 -10
  44. package/reference/sdlc/dev.playbook/dev.playbook.js +128 -120
  45. package/reference/sdlc/dev.playbook/dev.playbook.ts +143 -193
  46. package/reference/sdlc/dev.playbook/dev.registry.d.ts +3 -2
  47. package/reference/sdlc/dev.playbook/dev.registry.ts +6 -2
  48. package/reference/sdlc/pr.playbook/pr.fsm.d.ts +92 -85
  49. package/reference/sdlc/pr.playbook/pr.fsm.js +461 -518
  50. package/reference/sdlc/pr.playbook/pr.fsm.ts +533 -663
  51. package/reference/sdlc/pr.playbook/pr.gears.md +47 -63
  52. package/reference/sdlc/pr.playbook/pr.playbook.d.ts +13 -23
  53. package/reference/sdlc/pr.playbook/pr.playbook.js +118 -112
  54. package/reference/sdlc/pr.playbook/pr.playbook.ts +136 -190
  55. package/reference/sdlc/pr.playbook/pr.registry.d.ts +3 -2
  56. package/reference/sdlc/pr.playbook/pr.registry.ts +4 -2
  57. package/reference/sdlc/review.md +3 -3
  58. package/reference/sdlc/review.playbook/review.fsm.d.ts +150 -116
  59. package/reference/sdlc/review.playbook/review.fsm.js +479 -550
  60. package/reference/sdlc/review.playbook/review.fsm.ts +717 -662
  61. package/reference/sdlc/review.playbook/review.gears.md +32 -29
  62. package/reference/sdlc/review.playbook/review.playbook.d.ts +12 -12
  63. package/reference/sdlc/review.playbook/review.playbook.js +180 -155
  64. package/reference/sdlc/review.playbook/review.playbook.ts +190 -230
  65. package/reference/sdlc/review.playbook/review.registry.d.ts +6 -5
  66. package/reference/sdlc/review.playbook/review.registry.js +3 -3
  67. package/reference/sdlc/review.playbook/review.registry.ts +9 -5
  68. package/slc/gears2fsm.md +72 -3
  69. package/slc/link.md +50 -27
  70. package/slc/materialize-link.mjs +51 -13
  71. package/slc/optimize.md +4 -1
  72. package/slc/prefix-prompts.mjs +191 -0
  73. package/slc/prefix.md +203 -0
  74. package/slc/slc.pin-inputs.json +11 -1
  75. package/slc/text2gears.md +71 -11
  76. package/src/xstate-playbook-runtime.d.ts +82 -9
  77. package/src/xstate-playbook-runtime.js +1224 -283
  78. package/src/xstate-playbook-runtime.ts +1671 -338
  79. package/src/xstate-runtime.d.ts +3 -1
  80. package/src/xstate-runtime.js +9 -2
  81. package/src/xstate-runtime.ts +12 -2
@@ -1,288 +1,248 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
3
- //
4
- // Generated by slc/link.md (FSM-to-Runtime linker).
5
- // Source FSM: ./review.fsm.ts
6
- // Role metadata: Coder→coder, Reviewer→reviewer (canonical local roles)
7
- // Boss event: deterministic START_REVIEW entry; exact Boss text becomes
8
- // callerInput; pending player questions retain BOSS_REPLY
9
- // Adjudication: LLM judge per state; coderOutput and reviewerOutput are
10
- // carried verbatim; latestCommit is receipt-owned effect
11
- // evidence, never taken from either player's prose
12
- // Compat: artifact schema 3 / runtime ABI 1
13
-
3
+ // Generated by slc/materialize-link.mjs; governed by the complete slc/link.md.
4
+ // FSM: "./review.fsm.js"; export: reviewMachine; strategies: shared defaults with labelled string relays and nested actors.
5
+ import { reviewMachine as machine } from "./review.fsm.js";
6
+ import type { PlayerInput as SourcePlayerInput } from "./review.fsm.js";
14
7
  import {
15
- createXStatePlaybookRuntime,
16
- composePlayerContinuation,
17
- snapshotJsonValue,
8
+ createXStatePlaybookRuntime, snapshotJsonValue,
9
+ composePlayerContinuation, type XStatePromptIdentity,
18
10
  type PlaybookPlayerInput,
19
- type XStatePlaybookRuntimeFactory,
20
11
  type XStatePlaybookRuntimeConstruction,
21
- type XStatePromptIdentity,
12
+ type XStatePlaybookRuntimeFactory,
22
13
  type XStatePlaybookRuntimeSpecV3,
23
14
  } from '@sublang/playbook/xstate-runtime';
24
- import {
25
- reviewMachine,
26
- type PlayerInput,
27
- type ReviewInput,
28
- } from './review.fsm.js';
29
- import type { PlaybookHostConstructionCapabilities } from '../code.playbook/playbook-captain.js';
30
- import type {
31
- CaptainCallOptions,
32
- CaptainResult,
33
- JsonValue,
34
- NormalizedError,
35
- PlayerCallOptions,
36
- PlaybookCallRequest,
37
- PlaybookCallResult,
38
- PlaybookCallStart,
39
- PlaybookControlReceipt,
40
- PlaybookControlView,
41
- PlaybookPendingCall,
42
- PlaybookPorts,
43
- PlaybookRunResult,
44
- PlaybookRuntime,
45
- PlaybookRuntimeFactory,
46
- PlaybookRuntimeSnapshot,
47
- PlaybookSession,
48
- PlaybookState,
49
- PlaybookStateValue,
50
- PlaybookTraceEvent,
51
- PlaybookTraceType,
15
+ export type {
52
16
  PlayerResult,
17
+ PlayerCallOptions,
53
18
  PlayerSessionStore,
54
- } from '@sublang/playbook/runtime';
55
-
56
- export type {
57
- CaptainCallOptions,
58
19
  CaptainResult,
20
+ CaptainCallOptions,
59
21
  JsonValue,
60
22
  NormalizedError,
61
- PlayerCallOptions,
62
23
  PlaybookCallRequest,
63
24
  PlaybookCallResult,
64
25
  PlaybookCallStart,
65
- PlaybookControlReceipt,
66
- PlaybookControlView,
26
+ PlaybookStateValue,
27
+ PlaybookState,
67
28
  PlaybookPendingCall,
68
- PlaybookPorts,
69
29
  PlaybookRunResult,
70
30
  PlaybookRuntime,
71
31
  PlaybookRuntimeFactory,
72
32
  PlaybookRuntimeSnapshot,
73
33
  PlaybookSession,
74
- PlaybookState,
75
- PlaybookStateValue,
34
+ PlaybookPorts,
76
35
  PlaybookTraceEvent,
77
36
  PlaybookTraceType,
78
- PlayerResult,
79
- PlayerSessionStore,
80
- };
37
+ PlaybookControlReceipt,
38
+ PlaybookControlView,
39
+ } from '@sublang/playbook/runtime';
81
40
 
82
- export type ReviewPlaybookOptions = ReviewInput;
83
- export type ReviewPlaybookHostCapabilities =
84
- PlaybookHostConstructionCapabilities &
85
- XStatePlaybookRuntimeConstruction<ReviewPlaybookOptions, object>['hostCapabilities'];
41
+ export interface PlaybookRuntimeOptions {
86
42
 
87
- const PLACEHOLDER = /<(#|[A-Za-z_$][A-Za-z0-9_$-]*)>/g;
43
+ }
44
+ export type PlaybookHostCapabilities = XStatePlaybookRuntimeConstruction<
45
+ PlaybookRuntimeOptions, { readonly authority: object }
46
+ >['hostCapabilities'];
88
47
 
48
+ const OPTION_SCHEMA = {} as const;
49
+ const INPUT_MAPPING = {} as const;
50
+ const RESUMABLE_STATE_IDS: ReadonlySet<string> = new Set([
51
+ "firstReview",
52
+ "fixFindings",
53
+ "reviewAfterFix",
54
+ "reviewAfterRejection"
55
+ ]);
56
+ const UNFINISHED_FINAL_STATE_IDS: ReadonlySet<string> = new Set([]);
89
57
  const VERBATIM_PAYLOAD_FIELDS: ReadonlySet<string> = new Set([
90
- 'reviewerOutput',
91
- 'coderOutput',
58
+ "reviewerOutput",
59
+ "coderOutput"
92
60
  ]);
93
- const UNFINISHED_FINAL_STATE_IDS: ReadonlySet<string> = new Set();
94
-
95
- function snapshotReviewOptions(value: unknown): ReviewPlaybookOptions {
96
- const captured = snapshotJsonValue(value, 'REVIEW runtime options');
97
- if (
98
- captured === null ||
99
- typeof captured !== 'object' ||
100
- Array.isArray(captured)
101
- ) {
102
- throw new TypeError('REVIEW runtime options must be an object');
61
+ export function validateOptions(value: unknown): PlaybookRuntimeOptions {
62
+ const captured = snapshotJsonValue(value === undefined ? {} : value, "REVIEW runtime options");
63
+ if (captured === null || typeof captured !== 'object' || Array.isArray(captured)) {
64
+ throw new TypeError("REVIEW runtime options must be an object");
103
65
  }
104
- const record = captured as Readonly<Record<string, JsonValue>>;
105
- for (const key of Object.keys(record)) {
106
- throw new TypeError(`REVIEW runtime options.${key} is not declared`);
66
+ const fields = captured as Readonly<Record<string, unknown>>;
67
+ for (const key of Object.keys(captured)) {
68
+ if (!Object.hasOwn(OPTION_SCHEMA, key)) throw new TypeError("REVIEW runtime options." + key + ' is not declared');
107
69
  }
108
- return captured as unknown as ReviewPlaybookOptions;
109
- }
110
-
111
- function placeholderField(token: string): string {
112
- if (token === '#') return 'irNumber';
113
- return token.replace(/-([A-Za-z0-9_$])/g, (_match, next: string) =>
114
- next.toUpperCase(),
115
- );
116
- }
117
-
118
- function quotedContinuation(value: string): string {
119
- return value.replaceAll('\n', '\n> ');
70
+ for (const [key, schema] of Object.entries(OPTION_SCHEMA) as [string, { type: string; required: boolean }][]) {
71
+ if (!Object.hasOwn(captured, key)) {
72
+ if (schema.required) throw new TypeError("REVIEW runtime options." + key + ' is required');
73
+ } else if (typeof fields[key] !== schema.type || (schema.type === 'number' && !Number.isFinite(fields[key]))) {
74
+ throw new TypeError("REVIEW runtime options." + key + ' must be a ' + schema.type);
75
+ }
76
+ }
77
+ return captured as unknown as PlaybookRuntimeOptions;
120
78
  }
121
-
122
- /** Keep every line of a relayed runtime value inside its authored quote. */
123
- function composePlayerPrompt(
124
- input: PlayerInput,
125
- promptIdentity: XStatePromptIdentity,
126
- resuming = false,
127
- ): string {
128
- const fields = input as unknown as Record<string, unknown>;
129
- const body = input.prompt.replace(
130
- PLACEHOLDER,
131
- (match: string, token: string, offset: number, source: string) => {
132
- const value =
133
- token === 'coder-llm'
134
- ? promptIdentity('coder')
135
- : token === 'reviewer-llm'
136
- ? promptIdentity('reviewer')
137
- : fields[placeholderField(token)];
79
+ function renderPlayerPrompt(input: SourcePlayerInput, promptIdentity: XStatePromptIdentity, resuming = false): string {
80
+ const fields = input as unknown as Readonly<Record<string, unknown>>;
81
+ const mapping: Readonly<Record<string, string>> = {};
82
+ const identities: Readonly<Record<string, string>> = {"coder-llm":"coder","reviewer-llm":"reviewer"};
83
+ const omitted = new Set<string>([]);
84
+ const fieldFor = (token: string): string => Object.hasOwn(mapping, token) ? mapping[token]! : (token === '#' ? 'irNumber' : token.replace(/-([A-Za-z0-9_$])/g, (_match: string, next: string) => next.toUpperCase()));
85
+ const parts = input.prompt.split(/(\r?\n)/);
86
+ let body = '';
87
+ for (let index = 0; index < parts.length; index += 2) {
88
+ const line = parts[index]!;
89
+ if (omitted.has(line)) {
90
+ const token = /<(#|[A-Za-z_$][A-Za-z0-9_$-]*)>$/.exec(line)![1]!;
91
+ if (fields[fieldFor(token)] === '') continue;
92
+ }
93
+ body += line.replace(/<(#|[A-Za-z_$][A-Za-z0-9_$-]*)>/g, (match: string, token: string): string => {
94
+ const value = Object.hasOwn(identities, token) ? promptIdentity(identities[token]!) : fields[fieldFor(token)];
138
95
  if (typeof value !== 'string') return match;
139
- const lineStart = source.lastIndexOf('\n', offset - 1) + 1;
140
- return source.slice(lineStart, offset).startsWith('> ')
141
- ? quotedContinuation(value)
142
- : value;
143
- },
144
- );
96
+ return line.startsWith('> ') ? value.replace(/\r?\n/g, (ending: string) => ending + '> ') : value;
97
+ }) + (parts[index + 1] ?? '');
98
+ }
145
99
  return composePlayerContinuation(input, body, resuming);
146
100
  }
147
-
148
- export const _internal = {
149
- composePlayerPrompt,
150
- VERBATIM_PAYLOAD_FIELDS,
151
- UNFINISHED_FINAL_STATE_IDS,
152
- };
153
-
101
+ const composePlayerPrompt = (input: PlaybookPlayerInput, promptIdentity: XStatePromptIdentity, resuming?: boolean): string =>
102
+ renderPlayerPrompt(input as SourcePlayerInput, promptIdentity, resuming);
154
103
  const runtimeSpec = {
155
- label: 'REVIEW',
156
- // DR-022 / slc/link.md: the declaration carries the value current at link
157
- // time — a literal, never the loading engine's RUNTIME_ABI self-report,
158
- // which would follow whatever engine loads the module and make the
159
- // factory's skew check compare that engine with itself.
160
- compat: { artifactSchema: 3, runtimeAbi: 1 },
161
- snapshotOptions: snapshotReviewOptions,
162
- entryEvent: {
163
- type: 'START_REVIEW',
164
- textField: 'callerInput',
165
- // `copyStartInput` copies the entry text here, so the failure-state
166
- // retry reads it back from the persisted machine snapshot and survives
167
- // a continued session (DR-034).
168
- contextField: 'callerInput',
104
+ composePlayerPrompt,
105
+ ...{
106
+ "label": "REVIEW",
107
+ "compat": {
108
+ "artifactSchema": 3,
109
+ "runtimeAbi": 1
169
110
  },
170
- roleStates: {
171
- reviewInitial: {
172
- role: 'reviewer',
173
- label:
174
- "REVIEW-1: Reviewer reviews the caller's review scope against the original intent.",
175
- },
176
- addressFindings: {
177
- role: 'coder',
178
- label: 'REVIEW-2: Coder accepts or rejects every current review finding.',
111
+ "entryEvent": {
112
+ "type": "START_REVIEW",
113
+ "textField": "callerInput",
114
+ "contextField": "callerInput"
115
+ },
116
+ "bossEvents": [],
117
+ "roleStates": {
118
+ "firstReview": {
119
+ "role": "reviewer",
120
+ "label": "Reviewer runs the first review round over the review scope."
179
121
  },
180
- reviewAfterCommit: {
181
- role: 'reviewer',
182
- label:
183
- 'REVIEW-3: Reviewer reviews the cumulative committed state after a review-fix commit.',
122
+ "fixFindings": {
123
+ "role": "coder",
124
+ "label": "Coder accepts or rejects each of Reviewer's findings and commits any accepted fixes."
184
125
  },
185
- reviewAfterRebuttal: {
186
- role: 'reviewer',
187
- label:
188
- 'REVIEW-4: Reviewer adjudicates an all-rejected Coder disposition.',
126
+ "reviewAfterFix": {
127
+ "role": "reviewer",
128
+ "label": "Reviewer runs the next review round over the cumulative committed state after a review-fix commit."
189
129
  },
130
+ "reviewAfterRejection": {
131
+ "role": "reviewer",
132
+ "label": "Reviewer runs the next review round after Coder rejected every finding without a commit."
133
+ }
190
134
  },
191
- outcomeAuthority: {
192
- governedPlayerStates: {
193
- reviewInitial: {
194
- hasFindings: {
195
- fields: { reviewerOutput: 'presentation' },
196
- repositoryDisposition: 'unchanged',
197
- },
198
- noFindings: {
199
- // DR-045: the clean round's unchanged receipt observes the exact
200
- // evaluated revision as HEAD; the reconciler injects it here.
201
- fields: { evaluatedRevision: 'effect' },
202
- repositoryDisposition: 'unchanged',
135
+ "outcomeAuthority": {
136
+ "governedPlayerStates": {
137
+ "firstReview": {
138
+ "hasFindings": {
139
+ "fields": {
140
+ "reviewerOutput": "presentation"
141
+ },
142
+ "repositoryDisposition": "unchanged"
203
143
  },
204
- needsBossReply: {
205
- fields: { question: 'presentation' },
206
- repositoryDisposition: 'unchanged',
144
+ "noFindings": {
145
+ "fields": {
146
+ "evaluatedRevision": "effect"
147
+ },
148
+ "repositoryDisposition": "unchanged"
207
149
  },
150
+ "needsBossReply": {
151
+ "fields": {
152
+ "question": "presentation"
153
+ },
154
+ "repositoryDisposition": "unchanged"
155
+ }
208
156
  },
209
- addressFindings: {
210
- committed: {
211
- fields: {
212
- coderOutput: 'presentation',
213
- latestCommit: 'effect',
157
+ "fixFindings": {
158
+ "committed": {
159
+ "fields": {
160
+ "coderOutput": "presentation",
161
+ "latestCommit": "effect"
214
162
  },
215
- repositoryDisposition: 'one-descendant-commit',
216
- },
217
- rejectedAll: {
218
- fields: { coderOutput: 'presentation' },
219
- repositoryDisposition: 'unchanged',
163
+ "repositoryDisposition": "one-descendant-commit"
220
164
  },
221
- needsBossReply: {
222
- fields: { question: 'presentation' },
223
- repositoryDisposition: 'deferred',
165
+ "rejectedAll": {
166
+ "fields": {
167
+ "coderOutput": "presentation"
168
+ },
169
+ "repositoryDisposition": "unchanged"
224
170
  },
171
+ "needsBossReply": {
172
+ "fields": {
173
+ "question": "presentation"
174
+ },
175
+ "repositoryDisposition": "deferred"
176
+ }
225
177
  },
226
- reviewAfterCommit: {
227
- hasFindings: {
228
- fields: { reviewerOutput: 'presentation' },
229
- repositoryDisposition: 'unchanged',
230
- },
231
- noFindings: {
232
- // DR-045: the clean round's unchanged receipt observes the exact
233
- // evaluated revision as HEAD; the reconciler injects it here.
234
- fields: { evaluatedRevision: 'effect' },
235
- repositoryDisposition: 'unchanged',
178
+ "reviewAfterFix": {
179
+ "hasFindings": {
180
+ "fields": {
181
+ "reviewerOutput": "presentation"
182
+ },
183
+ "repositoryDisposition": "unchanged"
236
184
  },
237
- needsBossReply: {
238
- fields: { question: 'presentation' },
239
- repositoryDisposition: 'unchanged',
185
+ "noFindings": {
186
+ "fields": {
187
+ "evaluatedRevision": "effect"
188
+ },
189
+ "repositoryDisposition": "unchanged"
240
190
  },
191
+ "needsBossReply": {
192
+ "fields": {
193
+ "question": "presentation"
194
+ },
195
+ "repositoryDisposition": "unchanged"
196
+ }
241
197
  },
242
- reviewAfterRebuttal: {
243
- hasFindings: {
244
- fields: { reviewerOutput: 'presentation' },
245
- repositoryDisposition: 'unchanged',
246
- },
247
- noFindings: {
248
- // DR-045: the clean round's unchanged receipt observes the exact
249
- // evaluated revision as HEAD; the reconciler injects it here.
250
- fields: { evaluatedRevision: 'effect' },
251
- repositoryDisposition: 'unchanged',
198
+ "reviewAfterRejection": {
199
+ "hasFindings": {
200
+ "fields": {
201
+ "reviewerOutput": "presentation"
202
+ },
203
+ "repositoryDisposition": "unchanged"
252
204
  },
253
- needsBossReply: {
254
- fields: { question: 'presentation' },
255
- repositoryDisposition: 'unchanged',
205
+ "noFindings": {
206
+ "fields": {
207
+ "evaluatedRevision": "effect"
208
+ },
209
+ "repositoryDisposition": "unchanged"
256
210
  },
257
- },
258
- },
211
+ "needsBossReply": {
212
+ "fields": {
213
+ "question": "presentation"
214
+ },
215
+ "repositoryDisposition": "unchanged"
216
+ }
217
+ }
218
+ }
259
219
  },
260
- composePlayerPrompt: (
261
- input: PlaybookPlayerInput,
262
- promptIdentity: XStatePromptIdentity,
263
- resuming?: boolean,
264
- ) => composePlayerPrompt(input as PlayerInput, promptIdentity, resuming),
220
+ "placeholderFields": {},
221
+ "transitionEventFields": [
222
+ "callerInput",
223
+ "targetId",
224
+ "answer",
225
+ "questionId"
226
+ ],
227
+ "controlContextFields": []
228
+ },
229
+ snapshotOptions: validateOptions,
230
+ machineInput: (options: PlaybookRuntimeOptions) => Object.fromEntries(
231
+ Object.entries(INPUT_MAPPING).filter(([, key]) => options[key as keyof PlaybookRuntimeOptions] !== undefined)
232
+ .map(([field, key]) => [field, options[key as keyof PlaybookRuntimeOptions]]),
233
+ ),
265
234
  verbatimPayloadFields: VERBATIM_PAYLOAD_FIELDS,
266
- controlContextFields: [],
235
+ resumableStateIds: RESUMABLE_STATE_IDS,
267
236
  unfinishedFinalStateIds: UNFINISHED_FINAL_STATE_IDS,
268
- transitionEventFields: [
269
- 'callerInput',
270
- 'bossIntent',
271
- 'targetId',
272
- 'answer',
273
- 'questionId',
274
- ],
275
- } satisfies XStatePlaybookRuntimeSpecV3<ReviewPlaybookOptions>;
237
+ } satisfies XStatePlaybookRuntimeSpecV3<PlaybookRuntimeOptions>;
276
238
 
239
+ export const _internal = {
240
+ composePlayerPrompt,
241
+ RESUMABLE_STATE_IDS,
242
+ UNFINISHED_FINAL_STATE_IDS,
243
+ VERBATIM_PAYLOAD_FIELDS,
244
+ };
277
245
  const createPlaybookRuntime: XStatePlaybookRuntimeFactory<
278
- XStatePlaybookRuntimeConstruction<
279
- ReviewPlaybookOptions,
280
- ReviewPlaybookHostCapabilities
281
- >,
282
- 3
283
- > = createXStatePlaybookRuntime<
284
- ReviewPlaybookOptions,
285
- ReviewPlaybookHostCapabilities
286
- >(reviewMachine, runtimeSpec);
287
-
246
+ XStatePlaybookRuntimeConstruction<PlaybookRuntimeOptions, PlaybookHostCapabilities>, 3
247
+ > = createXStatePlaybookRuntime<PlaybookRuntimeOptions, PlaybookHostCapabilities>(machine, runtimeSpec);
288
248
  export default createPlaybookRuntime;
@@ -1,4 +1,5 @@
1
- import { type ReviewPlaybookHostCapabilities, type PlaybookRuntime } from './review.playbook.js';
1
+ import { type PlaybookHostCapabilities, type PlaybookRuntime } from './review.playbook.js';
2
+ import type { PlaybookHostConstructionCapabilities } from '../code.playbook/playbook-captain.js';
2
3
  export interface PlaybookSummaryPolicy {
3
4
  stateCountLabels: Readonly<Record<string, string>>;
4
5
  copyPasteGuardNames: readonly string[];
@@ -24,12 +25,12 @@ export interface ReviewPlaybookRegistryEntry {
24
25
  concurrentRoleSets: readonly [];
25
26
  summaryPolicy: PlaybookSummaryPolicy;
26
27
  validateOptions(optionSlice: unknown): ReviewOptions;
27
- createRuntime(options: ReviewOptions, hostCapabilities: ReviewPlaybookHostCapabilities): PlaybookRuntime;
28
+ createRuntime(options: ReviewOptions, hostCapabilities: PlaybookHostConstructionCapabilities & PlaybookHostCapabilities): PlaybookRuntime;
28
29
  }
29
30
  export declare const reviewStateCountLabels: {
30
- readonly reviewInitial: "review round";
31
- readonly reviewAfterCommit: "review round";
32
- readonly reviewAfterRebuttal: "rebuttal";
31
+ readonly firstReview: "review round";
32
+ readonly reviewAfterFix: "review round";
33
+ readonly reviewAfterRejection: "rebuttal";
33
34
  };
34
35
  export declare const reviewCopyPasteGuardNames: readonly ["hasFindings", "committed", "rejectedAll"];
35
36
  export declare function reviewSavedCountsLine(counts: {
@@ -2,9 +2,9 @@
2
2
  // SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
3
3
  import createPlaybookRuntime from './review.playbook.js';
4
4
  export const reviewStateCountLabels = {
5
- reviewInitial: 'review round',
6
- reviewAfterCommit: 'review round',
7
- reviewAfterRebuttal: 'rebuttal',
5
+ firstReview: 'review round',
6
+ reviewAfterFix: 'review round',
7
+ reviewAfterRejection: 'rebuttal',
8
8
  };
9
9
  export const reviewCopyPasteGuardNames = [
10
10
  'hasFindings',
@@ -2,9 +2,10 @@
2
2
  // SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
3
3
 
4
4
  import createPlaybookRuntime, {
5
- type ReviewPlaybookHostCapabilities,
5
+ type PlaybookHostCapabilities,
6
6
  type PlaybookRuntime,
7
7
  } from './review.playbook.js';
8
+ import type { PlaybookHostConstructionCapabilities } from '../code.playbook/playbook-captain.js';
8
9
 
9
10
  export interface PlaybookSummaryPolicy {
10
11
  stateCountLabels: Readonly<Record<string, string>>;
@@ -33,16 +34,19 @@ export interface ReviewPlaybookRegistryEntry {
33
34
  concurrentRoleSets: readonly [];
34
35
  summaryPolicy: PlaybookSummaryPolicy;
35
36
  validateOptions(optionSlice: unknown): ReviewOptions;
37
+ // The linked module types live authority as opaque (link-materialization);
38
+ // the Captain entry binds its own construction capabilities here.
36
39
  createRuntime(
37
40
  options: ReviewOptions,
38
- hostCapabilities: ReviewPlaybookHostCapabilities,
41
+ hostCapabilities: PlaybookHostConstructionCapabilities &
42
+ PlaybookHostCapabilities,
39
43
  ): PlaybookRuntime;
40
44
  }
41
45
 
42
46
  export const reviewStateCountLabels = {
43
- reviewInitial: 'review round',
44
- reviewAfterCommit: 'review round',
45
- reviewAfterRebuttal: 'rebuttal',
47
+ firstReview: 'review round',
48
+ reviewAfterFix: 'review round',
49
+ reviewAfterRejection: 'rebuttal',
46
50
  } as const;
47
51
 
48
52
  export const reviewCopyPasteGuardNames = [