@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
package/src/runtime.ts CHANGED
@@ -83,10 +83,13 @@ export interface PlaybookPendingCall {
83
83
  // DR-031 §5: complete durable identity for one nested call whose start
84
84
  // boundary has already been published and whose child remains suspended.
85
85
  // `turnId` is absent when the call was opened outside a Boss-turn boundary.
86
+ // A schema-3 runtime adds the effect-ledger prefix captured before the causal
87
+ // public boundary; null records that the prefix could not be observed.
86
88
  export interface PlaybookSuspendedCall extends PlaybookPendingCall {
87
89
  stateId: string;
88
90
  text: string;
89
91
  turnId?: number;
92
+ effectBoundaryPrefixSequence?: number | null;
90
93
  }
91
94
 
92
95
  export interface PlaybookCallRequest {
@@ -124,6 +127,7 @@ export type PlaybookCallStart =
124
127
 
125
128
  export type PlaybookRunResult =
126
129
  | { outcome: 'quiescent' | 'no-action'; state: PlaybookState }
130
+ | { outcome: 'unresolved-effect'; state: PlaybookState }
127
131
  | {
128
132
  outcome: 'failed' | 'aborted';
129
133
  state: PlaybookState;
@@ -174,6 +178,16 @@ export interface PlaybookSession {
174
178
  ports: PlaybookPorts;
175
179
  }
176
180
 
181
+ // DR-038 §5: the source identities and, for a suspended nested call, the
182
+ // fresh target child identity that let adoption start one explicit target
183
+ // trace lineage without carrying source-session counters or child UUIDs
184
+ // forward.
185
+ export interface PlaybookAdoptionContext {
186
+ readonly sourceSessionId: string;
187
+ readonly sourceGenerationId: string;
188
+ readonly targetChildSessionId?: string;
189
+ }
190
+
177
191
  export type PlaybookTraceType =
178
192
  | 'session.started'
179
193
  | 'boss.input.received'
@@ -188,12 +202,13 @@ export type PlaybookTraceType =
188
202
  | 'apply.started'
189
203
  | 'apply.finished'
190
204
  | 'fsm.transition'
205
+ | 'outcome.accepted'
191
206
  | 'status.emitted'
192
207
  | 'boss.input.settled'
193
208
  | 'session.disposed';
194
209
 
195
210
  export interface PlaybookTraceEvent {
196
- schemaVersion: 3;
211
+ schemaVersion: 4;
197
212
  sessionId: string;
198
213
  playbookId: string;
199
214
  rootSessionId: string;
@@ -215,12 +230,164 @@ export interface PlaybookPendingBossQuestion {
215
230
  sourceItem?: string;
216
231
  }
217
232
 
233
+ /** One repository disposition declared by a governed outcome arm (DR-040). */
234
+ export type PlaybookRepositoryDisposition =
235
+ | 'unchanged'
236
+ | 'one-descendant-commit'
237
+ | 'deferred';
238
+
239
+ /** A detached Git-visible repository observation owned by the effect ledger. */
240
+ export interface PlaybookRepositoryObservation {
241
+ readonly worktree: string;
242
+ readonly gitDir: string;
243
+ readonly head: string;
244
+ readonly projection: Readonly<Record<string, JsonValue>>;
245
+ readonly projectionDigest: string;
246
+ }
247
+
248
+ /** The fail-closed classification of one complete physical or logical receipt. */
249
+ export interface PlaybookRepositoryReceipt {
250
+ readonly classification:
251
+ | 'unchanged'
252
+ | 'one-descendant-commit'
253
+ | 'multiple-commits'
254
+ | 'rewritten-or-non-descendant'
255
+ | 'worktree-only-change'
256
+ | 'concurrent-or-foreign-change'
257
+ | 'observation-ambiguous';
258
+ readonly baseline: PlaybookRepositoryObservation;
259
+ readonly after?: PlaybookRepositoryObservation;
260
+ readonly commitOid?: string;
261
+ }
262
+
263
+ /** One durably ordered physical governed-player boundary (DR-040). */
264
+ export interface PlaybookEffectBoundary {
265
+ readonly sequence: number;
266
+ readonly boundaryId: string;
267
+ readonly attemptId: string;
268
+ readonly attemptNumber: number;
269
+ readonly playbookId: string;
270
+ readonly runtimeSessionId: string;
271
+ readonly turnId: number;
272
+ readonly callId: string;
273
+ readonly roleId: string;
274
+ readonly sourceStateId: string;
275
+ readonly sourceOutcomeSchema: JsonValue;
276
+ readonly dispositions: readonly PlaybookRepositoryDisposition[];
277
+ readonly canonicalWorktree: {
278
+ readonly worktree: string;
279
+ readonly gitDir: string;
280
+ };
281
+ readonly baseline: PlaybookRepositoryObservation;
282
+ readonly after?: PlaybookRepositoryObservation;
283
+ readonly physicalReceipt?: PlaybookRepositoryReceipt;
284
+ readonly finalText?: string;
285
+ readonly semanticCandidate?: JsonValue;
286
+ readonly initialSemanticCandidate?: JsonValue;
287
+ readonly correctionBudget: { readonly limit: 1; readonly spent: boolean };
288
+ readonly cohortId?: string;
289
+ readonly logicalOperationId?: string;
290
+ }
291
+
292
+ /** One physical boundary before the host assigns attempt and sequence data. */
293
+ export type PlaybookEffectBoundaryStart = Omit<
294
+ PlaybookEffectBoundary,
295
+ | 'sequence'
296
+ | 'attemptId'
297
+ | 'attemptNumber'
298
+ | 'after'
299
+ | 'physicalReceipt'
300
+ | 'finalText'
301
+ | 'semanticCandidate'
302
+ | 'initialSemanticCandidate'
303
+ >;
304
+
305
+ /** One deferred logical operation spanning its ordered physical boundaries. */
306
+ export interface PlaybookEffectLogicalOperation {
307
+ readonly sequence: number;
308
+ readonly operationId: string;
309
+ readonly playbookId: string;
310
+ readonly runtimeSessionId: string;
311
+ readonly boundaryIds: readonly string[];
312
+ readonly originalBaseline: PlaybookRepositoryObservation;
313
+ readonly checkpoint?: PlaybookRepositoryObservation;
314
+ readonly pendingQuestion?: PlaybookPendingBossQuestion;
315
+ readonly playerContinuation?: JsonValue;
316
+ readonly checkpointRestorationEligible: boolean;
317
+ readonly logicalReceipt?: PlaybookRepositoryReceipt;
318
+ }
319
+
320
+ /** Complete detached mirror of one host-owned reconciliation ledger. */
321
+ export interface PlaybookEffectLedger {
322
+ readonly schemaVersion: 1;
323
+ readonly revision: number;
324
+ readonly boundaries: readonly PlaybookEffectBoundary[];
325
+ readonly logicalOperations: readonly PlaybookEffectLogicalOperation[];
326
+ }
327
+
328
+ /** One mutation accepted by the host-owned effect-ledger write-ahead boundary. */
329
+ export type PlaybookEffectLedgerCommand =
330
+ | {
331
+ readonly kind: 'start-boundaries';
332
+ readonly boundaries: readonly [
333
+ PlaybookEffectBoundaryStart,
334
+ ...PlaybookEffectBoundaryStart[],
335
+ ];
336
+ }
337
+ | {
338
+ readonly kind: 'replace-boundaries';
339
+ readonly replacements: readonly [
340
+ {
341
+ readonly expected: PlaybookEffectBoundary;
342
+ readonly next: PlaybookEffectBoundary;
343
+ },
344
+ ...{
345
+ readonly expected: PlaybookEffectBoundary;
346
+ readonly next: PlaybookEffectBoundary;
347
+ }[],
348
+ ];
349
+ }
350
+ | {
351
+ readonly kind: 'append-logical-operations';
352
+ readonly operations: readonly [
353
+ Omit<PlaybookEffectLogicalOperation, 'sequence'>,
354
+ ...Omit<PlaybookEffectLogicalOperation, 'sequence'>[],
355
+ ];
356
+ }
357
+ | {
358
+ readonly kind: 'replace-logical-operations';
359
+ readonly replacements: readonly [
360
+ {
361
+ readonly expected: PlaybookEffectLogicalOperation;
362
+ readonly next: PlaybookEffectLogicalOperation;
363
+ },
364
+ ...{
365
+ readonly expected: PlaybookEffectLogicalOperation;
366
+ readonly next: PlaybookEffectLogicalOperation;
367
+ }[],
368
+ ];
369
+ };
370
+
371
+ /** A nonempty command batch persisted as one ledger revision. */
372
+ export type PlaybookEffectLedgerCommandBatch = readonly [
373
+ PlaybookEffectLedgerCommand,
374
+ ...PlaybookEffectLedgerCommand[],
375
+ ];
376
+
377
+ /** Live current-host seam for atomic effect-ledger observation and mutation. */
378
+ export interface PlaybookEffectLedgerCapability {
379
+ snapshot(): PlaybookEffectLedger;
380
+ writeAhead(
381
+ commands: PlaybookEffectLedgerCommandBatch,
382
+ ): Promise<PlaybookEffectLedger>;
383
+ }
384
+
218
385
  // DR-014 §1 / DR-031 §5 / DR-032: JSON-safe capture of a parked or nested-call
219
386
  // suspended session. `machine` is the opaque XState persisted snapshot;
220
387
  // pending Boss questions and a suspended call are first-class so a
221
388
  // host never has to reconstruct durable ownership from presentation records.
222
389
  export interface PlaybookRuntimeSnapshot {
223
- schemaVersion: 3;
390
+ schemaVersion: 4;
224
391
  playbookId: string;
225
392
  machine: JsonValue;
226
393
  roleResumeTokens: { readonly [roleId: string]: string };
@@ -234,6 +401,21 @@ export interface PlaybookRuntimeSnapshot {
234
401
  };
235
402
  state: PlaybookState;
236
403
  pendingBossQuestions: readonly PlaybookPendingBossQuestion[];
404
+ effectLedger: PlaybookEffectLedger;
405
+ /** Original runtime identity retained across schema-3 adoption lineage. */
406
+ retainedEffectSourceSessionId?: string;
407
+ /**
408
+ * Unsafe retained-adoption checkpoint. The marker remains durable until
409
+ * authoritative reconciliation proves its complete suffix replay-safe.
410
+ */
411
+ retainedEffectReconciliation?: {
412
+ readonly sourceSessionId: string;
413
+ readonly checkpoint: PlaybookEffectLedger;
414
+ };
415
+ failedEffectAttempt?: {
416
+ readonly boundaryPrefix: number;
417
+ readonly attemptId: string | null;
418
+ };
237
419
  suspendedCall?: PlaybookSuspendedCall;
238
420
  }
239
421
 
@@ -269,6 +451,15 @@ export type PlaybookControlReceipt =
269
451
  | { disposition: 'executed'; run: PlaybookRunResult }
270
452
  | { disposition: 'failed'; error: NormalizedError };
271
453
 
454
+ // DR-038 §2: link-authored metadata the Captain uses to decide whether a
455
+ // quiescent generation is eligible for retention and whether a root terminal
456
+ // outcome preserves its pre-terminal generation. Presence is classification
457
+ // data, independent from the optional adoption operation; an explicitly empty
458
+ // final-state list is meaningful.
459
+ export interface PlaybookRetainedGenerationMetadata {
460
+ readonly unfinishedFinalStateIds: readonly string[];
461
+ }
462
+
272
463
  export interface PlaybookRuntime {
273
464
  init(session: PlaybookSession): Promise<void>;
274
465
  // DR-014 §1 optional durable-session capability: a runtime implements
@@ -281,6 +472,16 @@ export interface PlaybookRuntime {
281
472
  session: PlaybookSession,
282
473
  snapshot: PlaybookRuntimeSnapshot,
283
474
  ): Promise<void>;
475
+ // DR-038 §1 optional generation-adoption capability: a distinct
476
+ // initialization path that rehydrates a retained snapshot under a fresh
477
+ // engagement identity. Presence is feature-detected independently from
478
+ // retained-generation classification metadata.
479
+ adopt?(
480
+ session: PlaybookSession,
481
+ snapshot: PlaybookRuntimeSnapshot,
482
+ context: PlaybookAdoptionContext,
483
+ ): Promise<void>;
484
+ readonly retainedGenerationMetadata?: PlaybookRetainedGenerationMetadata;
284
485
  // DR-029 optional control-surface capability: a runtime implements
285
486
  // both members or neither. `describe` is side-effect free and valid at
286
487
  // parked quiescence outside an active boundary; `apply` revalidates the
@@ -289,6 +490,16 @@ export interface PlaybookRuntime {
289
490
  // runtime lacking the pair advertises no actions; plain text delivery is
290
491
  // the only verb against it.
291
492
  describe?(): PlaybookControlView;
493
+ /**
494
+ * Host-only identities of the durable envelopes that still require
495
+ * unresolved-effect settlement. The host owns their bounded projection
496
+ * from its authoritative effect ledger; no repository evidence enters a
497
+ * runtime-owned run result.
498
+ */
499
+ unresolvedEffectEnvelopes?(): readonly (
500
+ | { readonly kind: 'boundary'; readonly boundaryId: string }
501
+ | { readonly kind: 'logical-operation'; readonly operationId: string }
502
+ )[];
292
503
  apply?(input: {
293
504
  actionId: string;
294
505
  key: string;
@@ -1,5 +1,5 @@
1
1
  import type { AnyStateMachine, EventObject, PromiseActorLogic } from 'xstate';
2
- import type { CaptainResult, JsonValue, PlaybookPorts, PlaybookRuntimeFactory, PlaybookSession, PlaybookState, PlayerResult } from './runtime.js';
2
+ import type { CaptainResult, JsonValue, PlaybookEffectBoundary, PlaybookEffectBoundaryStart, PlaybookEffectLedger, PlaybookEffectLedgerCapability, PlaybookPendingBossQuestion, PlaybookPorts, PlaybookRepositoryReceipt, PlaybookRuntimeFactory, PlaybookSession, PlaybookState, PlayerResult } from './runtime.js';
3
3
  export interface PlaybookPendingBossQuestionContext {
4
4
  questionId: string;
5
5
  resumeStateId: string;
@@ -52,9 +52,23 @@ export type JudgePurpose = 'boss-input-classification' | 'player-output-adjudica
52
52
  */
53
53
  export interface RuntimeBoundaryCalls {
54
54
  callPlayer(input: PlaybookPlayerInput, roleId: string, prompt: string, signal: AbortSignal): Promise<PlayerResult>;
55
+ /**
56
+ * Return the host-acknowledged adjudication performed while a governed
57
+ * repository claim was still held. The value is consumable once.
58
+ */
59
+ takeGovernedPlayerOutput?(result: PlayerResult): GovernedPlayerSettlement | undefined;
60
+ recordGovernedPlayerOutput?(result: PlayerResult, output: PlaybookActorOutput): void;
55
61
  callJudge(purpose: JudgePurpose, stateId: string | undefined, prompt: string, signal: AbortSignal): Promise<string>;
56
62
  callCaptain?(input: PlaybookCaptainInput, prompt: string, signal: AbortSignal, callOptions?: XStateCaptainCallOptions): Promise<CaptainResult>;
57
63
  }
64
+ /** Host-acknowledged outcome of one governed player reconciliation. */
65
+ type GovernedPlayerSettlement = {
66
+ readonly status: 'resolved';
67
+ readonly output: PlaybookActorOutput;
68
+ } | {
69
+ readonly status: 'unresolved';
70
+ readonly error: unknown;
71
+ };
58
72
  /**
59
73
  * Presentation selection for one traced direct-Captain call
60
74
  * (slc/link.md §Captain adjudication). `'visible'` (the default) is the
@@ -95,6 +109,87 @@ export declare const BOSS_REPLY_ERRORS: {
95
109
  readonly missingQuestion: "needsBossReply outcome missing 'question' field";
96
110
  readonly unregisteredState: (stateId: string) => string;
97
111
  };
112
+ interface XStateRepositoryOperationSettlement<T> {
113
+ readonly status: 'fulfilled';
114
+ readonly value: T;
115
+ }
116
+ interface XStateRepositoryOperationRejection {
117
+ readonly status: 'rejected';
118
+ readonly reason: unknown;
119
+ }
120
+ interface XStateRepositoryExclusiveCompletion<T> {
121
+ readonly boundary: PlaybookEffectBoundary;
122
+ readonly operation: XStateRepositoryOperationSettlement<T> | XStateRepositoryOperationRejection;
123
+ readonly receipt: PlaybookRepositoryReceipt;
124
+ /** Physical receipt for an ordinary call; cumulative receipt for a chain. */
125
+ readonly outcomeReceipt: PlaybookRepositoryReceipt;
126
+ }
127
+ interface XStateDeferredBinding {
128
+ readonly operationId: string;
129
+ readonly pendingQuestion: PlaybookPendingBossQuestion;
130
+ readonly playerContinuation: JsonValue;
131
+ }
132
+ interface XStateRepositoryCompletionEvidence {
133
+ readonly finalText?: string;
134
+ readonly semanticCandidate?: JsonValue;
135
+ readonly deferred?: XStateDeferredBinding;
136
+ readonly unresolved?: true;
137
+ }
138
+ interface XStateRepositoryExclusiveResult<T> {
139
+ readonly operation: XStateRepositoryOperationSettlement<T> | XStateRepositoryOperationRejection;
140
+ readonly receipt: PlaybookRepositoryReceipt;
141
+ readonly effectLedger: PlaybookEffectLedger;
142
+ readonly deferredStatus?: 'bound' | 'unresolved';
143
+ }
144
+ interface XStateRepositoryDeferredContinuationResult<T> {
145
+ readonly status: 'continued';
146
+ readonly operation: XStateRepositoryOperationSettlement<T> | XStateRepositoryOperationRejection;
147
+ readonly receipt: PlaybookRepositoryReceipt;
148
+ readonly logicalReceipt?: PlaybookRepositoryReceipt;
149
+ readonly effectLedger: PlaybookEffectLedger;
150
+ readonly deferredStatus?: 'bound' | 'unresolved';
151
+ }
152
+ interface XStateRepositoryDeferredCheckpointMismatch {
153
+ readonly status: 'checkpoint-mismatch' | 'ineligible';
154
+ readonly effectLedger: PlaybookEffectLedger;
155
+ }
156
+ interface XStateRepositoryDeferredParked {
157
+ readonly status: 'parked';
158
+ readonly effectLedger: PlaybookEffectLedger;
159
+ }
160
+ interface XStateRepositoryDeferredRestoreResult {
161
+ readonly status: 'restored' | 'checkpoint-mismatch' | 'ineligible';
162
+ readonly effectLedger: PlaybookEffectLedger;
163
+ }
164
+ type XStateEffectBoundarySeed = Omit<PlaybookEffectBoundaryStart, 'playbookId' | 'canonicalWorktree' | 'baseline' | 'cohortId'>;
165
+ export interface XStateRepositoryCapability {
166
+ runExclusive<T>(options: {
167
+ readonly signal: AbortSignal;
168
+ readonly effectBoundary: XStateEffectBoundarySeed;
169
+ readonly operation: (context: {
170
+ readonly baseline: PlaybookRepositoryReceipt['baseline'];
171
+ readonly identity: unknown;
172
+ }) => Promise<T>;
173
+ readonly completeEffectBoundary: (completion: XStateRepositoryExclusiveCompletion<T>) => XStateRepositoryCompletionEvidence | Promise<XStateRepositoryCompletionEvidence>;
174
+ }): Promise<XStateRepositoryExclusiveResult<T>>;
175
+ runDeferred<T>(options: {
176
+ readonly mode: 'continue';
177
+ readonly signal: AbortSignal;
178
+ readonly operationId: string;
179
+ readonly effectBoundary: XStateEffectBoundarySeed;
180
+ readonly operation: (context: {
181
+ readonly baseline: PlaybookRepositoryReceipt['baseline'];
182
+ readonly identity: unknown;
183
+ readonly playerContinuation: JsonValue;
184
+ }) => Promise<T>;
185
+ readonly completeEffectBoundary: (completion: XStateRepositoryExclusiveCompletion<T>) => XStateRepositoryCompletionEvidence | Promise<XStateRepositoryCompletionEvidence>;
186
+ }): Promise<XStateRepositoryDeferredContinuationResult<T> | XStateRepositoryDeferredCheckpointMismatch>;
187
+ runDeferred(options: {
188
+ readonly mode: 'park' | 'restore';
189
+ readonly signal: AbortSignal;
190
+ readonly operationId: string;
191
+ }): Promise<XStateRepositoryDeferredParked | XStateRepositoryDeferredRestoreResult>;
192
+ }
98
193
  /** The runtime ABI this engine implements (DR-022). */
99
194
  export declare const RUNTIME_ABI = 1;
100
195
  /** The linked-artifact schema versions this engine accepts (DR-022). */
@@ -106,6 +201,43 @@ export interface XStatePlaybookRuntimeCompat {
106
201
  /** The engine ABI the artifact was linked against. */
107
202
  runtimeAbi: number;
108
203
  }
204
+ /** Authority for one schema-3 delegated-player outcome payload field. */
205
+ export type XStateOutcomeFieldAuthority = 'presentation' | 'semantic' | 'effect' | 'runtime';
206
+ /** Repository disposition required by one schema-3 outcome arm. */
207
+ export type XStateRepositoryDisposition = 'unchanged' | 'one-descendant-commit' | 'deferred';
208
+ /** Closed authority and repository contract for one governed outcome. */
209
+ export interface XStateGovernedOutcomeSpec {
210
+ readonly fields: Readonly<Record<string, XStateOutcomeFieldAuthority>>;
211
+ readonly repositoryDisposition: XStateRepositoryDisposition;
212
+ }
213
+ /**
214
+ * Schema-3 authority metadata, keyed first by player state and then by its
215
+ * declared outcome. A roleless artifact supplies an explicitly empty
216
+ * `governedPlayerStates` object.
217
+ */
218
+ export interface XStateOutcomeAuthoritySpec {
219
+ readonly governedPlayerStates: Readonly<Record<string, Readonly<Record<string, XStateGovernedOutcomeSpec>>>>;
220
+ }
221
+ /**
222
+ * Schema-3 factory input composed by a registry from persisted configured
223
+ * options and live current-host capabilities. The engine snapshots only the
224
+ * first member and never places the second in machine input or persistence.
225
+ */
226
+ export interface XStatePlaybookRuntimeConstruction<ConfiguredOptions, HostCapabilities extends object> {
227
+ readonly configuredOptions: ConfiguredOptions;
228
+ readonly hostCapabilities: HostCapabilities & {
229
+ readonly repository: XStateRepositoryCapability;
230
+ readonly effectLedger: PlaybookEffectLedgerCapability;
231
+ };
232
+ }
233
+ export type XStatePlaybookRuntimeFactoryOptions<ConfiguredOptions, HostCapabilities extends object> = XStatePlaybookRuntimeConstruction<ConfiguredOptions, HostCapabilities>;
234
+ /** Shared XState factory with its captured, validated artifact compatibility. */
235
+ export type XStatePlaybookRuntimeFactory<Options = unknown, ArtifactSchema extends 3 = 3> = PlaybookRuntimeFactory<Options> & {
236
+ readonly compat: Readonly<{
237
+ readonly artifactSchema: ArtifactSchema;
238
+ readonly runtimeAbi: typeof RUNTIME_ABI;
239
+ }>;
240
+ };
109
241
  /**
110
242
  * One direct-Captain actor invocation handed to a spec's `captainStrategy`
111
243
  * (slc/link.md §Captain adjudication, controller form). The engine owns
@@ -146,15 +278,9 @@ export interface XStateCaptainStrategyRun<TOptions> {
146
278
  recoverableFailure<E extends Error>(error: E): E;
147
279
  }
148
280
  export type XStateCaptainStrategy<TOptions> = (run: XStateCaptainStrategyRun<TOptions>) => Promise<PlaybookActorOutput>;
149
- export interface XStatePlaybookRuntimeSpec<TOptions> {
281
+ interface XStatePlaybookRuntimeSpecBase<TOptions> {
150
282
  /** Diagnostic label used in internal invariant errors. Default 'playbook'. */
151
283
  label?: string;
152
- /**
153
- * Link-time compatibility declaration checked at construction against the
154
- * loaded engine's self-report (DR-022). Absent declarations reject because
155
- * their overloaded player metadata has no safe local-role interpretation.
156
- */
157
- compat?: XStatePlaybookRuntimeCompat;
158
284
  /** Validate and JSON-snapshot the caller's per-run options. */
159
285
  snapshotOptions: (value: unknown) => TOptions;
160
286
  /** Derive the FSM machine input from validated options. Default: identity. */
@@ -226,6 +352,8 @@ export interface XStatePlaybookRuntimeSpec<TOptions> {
226
352
  * surfaced first-class by the view and shall not be named here.
227
353
  */
228
354
  controlContextFields?: readonly string[];
355
+ /** Root final states whose terminal outcome leaves unfinished work. Default: none. */
356
+ unfinishedFinalStateIds?: ReadonlySet<string>;
229
357
  /** States that may suspend for a Boss reply. Default: targets of the FSM's `awaitBossReply` BOSS_REPLY transitions. */
230
358
  resumableStateIds?: ReadonlySet<string>;
231
359
  /** Human status lines for a root transition. Default: guard, declared-player, question, and failure lines. */
@@ -237,6 +365,14 @@ export interface XStatePlaybookRuntimeSpec<TOptions> {
237
365
  /** Working directory for `script` actors. Default: the validated options' string `cwd`, else the process working directory. */
238
366
  scriptCwd?: (options: TOptions) => string | undefined;
239
367
  }
368
+ export interface XStatePlaybookRuntimeSpec<TOptions> extends XStatePlaybookRuntimeSpecBase<TOptions> {
369
+ compat: XStatePlaybookRuntimeCompat & {
370
+ artifactSchema: 3;
371
+ };
372
+ outcomeAuthority: XStateOutcomeAuthoritySpec;
373
+ }
374
+ /** Schema-3 shared-engine spec with required exact outcome authority metadata. */
375
+ export type XStatePlaybookRuntimeSpecV3<TOptions> = XStatePlaybookRuntimeSpec<TOptions>;
240
376
  /** Strip a single Markdown code fence that wraps the whole string. */
241
377
  export declare function stripCodeFence(text: string): string;
242
378
  export declare function extractJsonValue(text: string, start: number, repair: boolean): string | undefined;
@@ -292,9 +428,11 @@ export interface PlayerAdjudicationSpec {
292
428
  export declare function adjudicatePlayerOutput(spec: PlayerAdjudicationSpec, input: PlaybookPlayerInput, finalText: string, ports: PlaybookPorts, signal: AbortSignal, boundary?: RuntimeBoundaryCalls): Promise<PlaybookActorOutput>;
293
429
  interface PlayerBridgeSpec {
294
430
  resolveRoleId: (input: PlaybookPlayerInput) => string;
431
+ validateInput?: (input: PlaybookPlayerInput) => void;
295
432
  composePlayerPrompt: (input: PlaybookPlayerInput) => string;
296
433
  adjudication: PlayerAdjudicationSpec;
297
434
  resumableStateIds: ReadonlySet<string>;
435
+ allowsCorrectiveReplay?: (result: PlayerResult) => boolean;
298
436
  }
299
437
  export declare function createPlayerBridge(spec: PlayerBridgeSpec, ports: PlaybookPorts, getActiveSignal?: () => AbortSignal | undefined, boundary?: RuntimeBoundaryCalls, onControlPlaneError?: (error: unknown) => void): PromiseActorLogic<PlaybookActorOutput, PlaybookPlayerInput>;
300
438
  /**
@@ -320,12 +458,13 @@ export declare function stateDescriptionsFromMachine(machine: AnyStateMachine):
320
458
  * under the slc/link.md contract. The factory provides every actor kind the
321
459
  * machine declares — `player`, `script`, `captain`, and nested `playbook`
322
460
  * (literal and dynamic) — and implements the full runtime lifecycle including
323
- * the optional parked-session snapshot capability (DR-014).
461
+ * the optional parked-session snapshot capability (DR-014) and the retained-
462
+ * snapshot adoption capability (DR-038).
324
463
  *
325
464
  * Scope: flat single-region machines — no parallel state, no compound
326
465
  * child states, and every root state's `meta.playbook.stateId` equal to its
327
466
  * state key — so each snapshot exposes exactly one playbook state id.
328
467
  * Parallel-region FSMs keep their own linked runtimes.
329
468
  */
330
- export declare function createXStatePlaybookRuntime<TOptions>(machine: AnyStateMachine, spec: XStatePlaybookRuntimeSpec<TOptions>): PlaybookRuntimeFactory<TOptions>;
469
+ export declare function createXStatePlaybookRuntime<TOptions, THostCapabilities extends object>(machine: AnyStateMachine, spec: XStatePlaybookRuntimeSpecV3<TOptions>): XStatePlaybookRuntimeFactory<XStatePlaybookRuntimeConstruction<TOptions, THostCapabilities>, 3>;
331
470
  export {};