@sublang/playbook 8.0.0 → 10.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 (66) hide show
  1. package/README.md +3 -3
  2. package/docs/cli.md +66 -23
  3. package/docs/configuration.md +13 -8
  4. package/docs/embedding.md +45 -14
  5. package/package.json +7 -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 +151 -10
  13. package/reference/sdlc/captain.playbook/captain.playbook.ts +200 -14
  14. package/reference/sdlc/code.md +0 -1
  15. package/reference/sdlc/code.playbook/bin/interactive-session.js +170 -17
  16. package/reference/sdlc/code.playbook/bin/launch-config.js +136 -4
  17. package/reference/sdlc/code.playbook/bin/playbook.js +81 -4
  18. package/reference/sdlc/code.playbook/bin/repository-effects.js +2930 -0
  19. package/reference/sdlc/code.playbook/bin/run.js +365 -63
  20. package/reference/sdlc/code.playbook/bin/session-store.js +2877 -209
  21. package/reference/sdlc/code.playbook/code.fsm.d.ts +11 -1
  22. package/reference/sdlc/code.playbook/code.fsm.js +85 -29
  23. package/reference/sdlc/code.playbook/code.fsm.ts +95 -33
  24. package/reference/sdlc/code.playbook/code.gears.md +0 -2
  25. package/reference/sdlc/code.playbook/code.playbook.d.ts +5 -2
  26. package/reference/sdlc/code.playbook/code.playbook.js +67 -4
  27. package/reference/sdlc/code.playbook/code.playbook.ts +87 -8
  28. package/reference/sdlc/code.playbook/code.registry.d.ts +10 -3
  29. package/reference/sdlc/code.playbook/code.registry.js +10 -3
  30. package/reference/sdlc/code.playbook/code.registry.ts +23 -5
  31. package/reference/sdlc/code.playbook/playbook-captain.d.ts +99 -7
  32. package/reference/sdlc/code.playbook/playbook-captain.js +1894 -82
  33. package/reference/sdlc/code.playbook/playbook-captain.ts +2809 -109
  34. package/reference/sdlc/decide.md +0 -1
  35. package/reference/sdlc/decide.playbook/decide.fsm.d.ts +8 -1
  36. package/reference/sdlc/decide.playbook/decide.fsm.js +80 -29
  37. package/reference/sdlc/decide.playbook/decide.fsm.ts +89 -31
  38. package/reference/sdlc/decide.playbook/decide.gears.md +0 -1
  39. package/reference/sdlc/decide.playbook/decide.playbook.d.ts +15 -5
  40. package/reference/sdlc/decide.playbook/decide.playbook.js +1994 -191
  41. package/reference/sdlc/decide.playbook/decide.playbook.ts +3209 -404
  42. package/reference/sdlc/decide.playbook/decide.registry.d.ts +7 -3
  43. package/reference/sdlc/decide.playbook/decide.registry.js +10 -3
  44. package/reference/sdlc/decide.playbook/decide.registry.ts +20 -5
  45. package/reference/sdlc/review.playbook/review.fsm.d.ts +7 -0
  46. package/reference/sdlc/review.playbook/review.fsm.js +133 -12
  47. package/reference/sdlc/review.playbook/review.fsm.ts +140 -12
  48. package/reference/sdlc/review.playbook/review.playbook.d.ts +5 -2
  49. package/reference/sdlc/review.playbook/review.playbook.js +78 -4
  50. package/reference/sdlc/review.playbook/review.playbook.ts +95 -8
  51. package/reference/sdlc/review.playbook/review.registry.d.ts +10 -3
  52. package/reference/sdlc/review.playbook/review.registry.js +10 -3
  53. package/reference/sdlc/review.playbook/review.registry.ts +23 -5
  54. package/slc/gears2fsm.md +25 -7
  55. package/slc/link.md +727 -82
  56. package/src/accepted-outcome.d.ts +18 -0
  57. package/src/accepted-outcome.js +94 -0
  58. package/src/accepted-outcome.ts +140 -0
  59. package/src/runtime.d.ts +165 -3
  60. package/src/runtime.ts +214 -2
  61. package/src/xstate-playbook-runtime.d.ts +162 -13
  62. package/src/xstate-playbook-runtime.js +3344 -564
  63. package/src/xstate-playbook-runtime.ts +4873 -637
  64. package/src/xstate-runtime.d.ts +76 -8
  65. package/src/xstate-runtime.js +1001 -64
  66. package/src/xstate-runtime.ts +1640 -91
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;
@@ -132,6 +136,7 @@ export type PlaybookRunResult =
132
136
  | {
133
137
  outcome: 'terminal';
134
138
  state: PlaybookState;
139
+ stateDescription?: string;
135
140
  output?: JsonValue;
136
141
  }
137
142
  | {
@@ -173,6 +178,16 @@ export interface PlaybookSession {
173
178
  ports: PlaybookPorts;
174
179
  }
175
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
+
176
191
  export type PlaybookTraceType =
177
192
  | 'session.started'
178
193
  | 'boss.input.received'
@@ -187,12 +202,13 @@ export type PlaybookTraceType =
187
202
  | 'apply.started'
188
203
  | 'apply.finished'
189
204
  | 'fsm.transition'
205
+ | 'outcome.accepted'
190
206
  | 'status.emitted'
191
207
  | 'boss.input.settled'
192
208
  | 'session.disposed';
193
209
 
194
210
  export interface PlaybookTraceEvent {
195
- schemaVersion: 3;
211
+ schemaVersion: 4;
196
212
  sessionId: string;
197
213
  playbookId: string;
198
214
  rootSessionId: string;
@@ -214,12 +230,164 @@ export interface PlaybookPendingBossQuestion {
214
230
  sourceItem?: string;
215
231
  }
216
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
+
217
385
  // DR-014 §1 / DR-031 §5 / DR-032: JSON-safe capture of a parked or nested-call
218
386
  // suspended session. `machine` is the opaque XState persisted snapshot;
219
387
  // pending Boss questions and a suspended call are first-class so a
220
388
  // host never has to reconstruct durable ownership from presentation records.
221
389
  export interface PlaybookRuntimeSnapshot {
222
- schemaVersion: 3;
390
+ schemaVersion: 4;
223
391
  playbookId: string;
224
392
  machine: JsonValue;
225
393
  roleResumeTokens: { readonly [roleId: string]: string };
@@ -233,6 +401,21 @@ export interface PlaybookRuntimeSnapshot {
233
401
  };
234
402
  state: PlaybookState;
235
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
+ };
236
419
  suspendedCall?: PlaybookSuspendedCall;
237
420
  }
238
421
 
@@ -268,6 +451,15 @@ export type PlaybookControlReceipt =
268
451
  | { disposition: 'executed'; run: PlaybookRunResult }
269
452
  | { disposition: 'failed'; error: NormalizedError };
270
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
+
271
463
  export interface PlaybookRuntime {
272
464
  init(session: PlaybookSession): Promise<void>;
273
465
  // DR-014 §1 optional durable-session capability: a runtime implements
@@ -280,6 +472,16 @@ export interface PlaybookRuntime {
280
472
  session: PlaybookSession,
281
473
  snapshot: PlaybookRuntimeSnapshot,
282
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;
283
485
  // DR-029 optional control-surface capability: a runtime implements
284
486
  // both members or neither. `describe` is side-effect free and valid at
285
487
  // parked quiescence outside an active boundary; `apply` revalidates the
@@ -288,6 +490,16 @@ export interface PlaybookRuntime {
288
490
  // runtime lacking the pair advertises no actions; plain text delivery is
289
491
  // the only verb against it.
290
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
+ )[];
291
503
  apply?(input: {
292
504
  actionId: string;
293
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. */
@@ -168,6 +294,15 @@ export interface XStatePlaybookRuntimeSpec<TOptions> {
168
294
  entryEvent?: {
169
295
  type: string;
170
296
  textField: string;
297
+ /**
298
+ * DR-034: the FSM context member this machine's entry action copies the
299
+ * exact Boss text into. Where it is named, the failure-state retry
300
+ * builds its payload from that member of the live snapshot instead of
301
+ * from the process-local recorded event, so the action derives the same
302
+ * before and after `restore`. Absent: the recorded event stays the
303
+ * source and the action lives only as long as the process.
304
+ */
305
+ contextField?: string;
171
306
  };
172
307
  /**
173
308
  * Exact flat Boss-event contracts whose non-text fields the judge may
@@ -217,6 +352,8 @@ export interface XStatePlaybookRuntimeSpec<TOptions> {
217
352
  * surfaced first-class by the view and shall not be named here.
218
353
  */
219
354
  controlContextFields?: readonly string[];
355
+ /** Root final states whose terminal outcome leaves unfinished work. Default: none. */
356
+ unfinishedFinalStateIds?: ReadonlySet<string>;
220
357
  /** States that may suspend for a Boss reply. Default: targets of the FSM's `awaitBossReply` BOSS_REPLY transitions. */
221
358
  resumableStateIds?: ReadonlySet<string>;
222
359
  /** Human status lines for a root transition. Default: guard, declared-player, question, and failure lines. */
@@ -228,6 +365,14 @@ export interface XStatePlaybookRuntimeSpec<TOptions> {
228
365
  /** Working directory for `script` actors. Default: the validated options' string `cwd`, else the process working directory. */
229
366
  scriptCwd?: (options: TOptions) => string | undefined;
230
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>;
231
376
  /** Strip a single Markdown code fence that wraps the whole string. */
232
377
  export declare function stripCodeFence(text: string): string;
233
378
  export declare function extractJsonValue(text: string, start: number, repair: boolean): string | undefined;
@@ -283,9 +428,11 @@ export interface PlayerAdjudicationSpec {
283
428
  export declare function adjudicatePlayerOutput(spec: PlayerAdjudicationSpec, input: PlaybookPlayerInput, finalText: string, ports: PlaybookPorts, signal: AbortSignal, boundary?: RuntimeBoundaryCalls): Promise<PlaybookActorOutput>;
284
429
  interface PlayerBridgeSpec {
285
430
  resolveRoleId: (input: PlaybookPlayerInput) => string;
431
+ validateInput?: (input: PlaybookPlayerInput) => void;
286
432
  composePlayerPrompt: (input: PlaybookPlayerInput) => string;
287
433
  adjudication: PlayerAdjudicationSpec;
288
434
  resumableStateIds: ReadonlySet<string>;
435
+ allowsCorrectiveReplay?: (result: PlayerResult) => boolean;
289
436
  }
290
437
  export declare function createPlayerBridge(spec: PlayerBridgeSpec, ports: PlaybookPorts, getActiveSignal?: () => AbortSignal | undefined, boundary?: RuntimeBoundaryCalls, onControlPlaneError?: (error: unknown) => void): PromiseActorLogic<PlaybookActorOutput, PlaybookPlayerInput>;
291
438
  /**
@@ -311,11 +458,13 @@ export declare function stateDescriptionsFromMachine(machine: AnyStateMachine):
311
458
  * under the slc/link.md contract. The factory provides every actor kind the
312
459
  * machine declares — `player`, `script`, `captain`, and nested `playbook`
313
460
  * (literal and dynamic) — and implements the full runtime lifecycle including
314
- * 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).
315
463
  *
316
- * Scope: machines that declare no parallel state (each snapshot exposes
317
- * exactly one playbook state id). Parallel-region FSMs keep their own linked
318
- * runtimes.
464
+ * Scope: flat single-region machines no parallel state, no compound
465
+ * child states, and every root state's `meta.playbook.stateId` equal to its
466
+ * state key — so each snapshot exposes exactly one playbook state id.
467
+ * Parallel-region FSMs keep their own linked runtimes.
319
468
  */
320
- 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>;
321
470
  export {};