@sublang/playbook 9.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 (64) hide show
  1. package/docs/cli.md +51 -8
  2. package/docs/embedding.md +38 -12
  3. package/package.json +7 -3
  4. package/reference/sdlc/captain.md +14 -10
  5. package/reference/sdlc/captain.playbook/captain.fsm.d.ts +33 -13
  6. package/reference/sdlc/captain.playbook/captain.fsm.js +80 -9
  7. package/reference/sdlc/captain.playbook/captain.fsm.ts +137 -18
  8. package/reference/sdlc/captain.playbook/captain.gears.md +10 -6
  9. package/reference/sdlc/captain.playbook/captain.playbook.d.ts +5 -1
  10. package/reference/sdlc/captain.playbook/captain.playbook.js +140 -10
  11. package/reference/sdlc/captain.playbook/captain.playbook.ts +188 -16
  12. package/reference/sdlc/code.md +0 -1
  13. package/reference/sdlc/code.playbook/bin/interactive-session.js +170 -17
  14. package/reference/sdlc/code.playbook/bin/launch-config.js +136 -4
  15. package/reference/sdlc/code.playbook/bin/playbook.js +81 -4
  16. package/reference/sdlc/code.playbook/bin/repository-effects.js +2930 -0
  17. package/reference/sdlc/code.playbook/bin/run.js +365 -63
  18. package/reference/sdlc/code.playbook/bin/session-store.js +2877 -209
  19. package/reference/sdlc/code.playbook/code.fsm.d.ts +7 -0
  20. package/reference/sdlc/code.playbook/code.fsm.js +74 -25
  21. package/reference/sdlc/code.playbook/code.fsm.ts +83 -29
  22. package/reference/sdlc/code.playbook/code.gears.md +0 -2
  23. package/reference/sdlc/code.playbook/code.playbook.d.ts +5 -2
  24. package/reference/sdlc/code.playbook/code.playbook.js +54 -2
  25. package/reference/sdlc/code.playbook/code.playbook.ts +75 -6
  26. package/reference/sdlc/code.playbook/code.registry.d.ts +10 -3
  27. package/reference/sdlc/code.playbook/code.registry.js +10 -3
  28. package/reference/sdlc/code.playbook/code.registry.ts +23 -5
  29. package/reference/sdlc/code.playbook/playbook-captain.d.ts +99 -7
  30. package/reference/sdlc/code.playbook/playbook-captain.js +1850 -72
  31. package/reference/sdlc/code.playbook/playbook-captain.ts +2759 -96
  32. package/reference/sdlc/decide.md +0 -1
  33. package/reference/sdlc/decide.playbook/decide.fsm.d.ts +7 -0
  34. package/reference/sdlc/decide.playbook/decide.fsm.js +80 -29
  35. package/reference/sdlc/decide.playbook/decide.fsm.ts +89 -31
  36. package/reference/sdlc/decide.playbook/decide.gears.md +0 -1
  37. package/reference/sdlc/decide.playbook/decide.playbook.d.ts +13 -5
  38. package/reference/sdlc/decide.playbook/decide.playbook.js +1712 -91
  39. package/reference/sdlc/decide.playbook/decide.playbook.ts +2677 -136
  40. package/reference/sdlc/decide.playbook/decide.registry.d.ts +7 -3
  41. package/reference/sdlc/decide.playbook/decide.registry.js +10 -3
  42. package/reference/sdlc/decide.playbook/decide.registry.ts +20 -5
  43. package/reference/sdlc/review.playbook/review.fsm.d.ts +7 -0
  44. package/reference/sdlc/review.playbook/review.fsm.js +133 -12
  45. package/reference/sdlc/review.playbook/review.fsm.ts +140 -12
  46. package/reference/sdlc/review.playbook/review.playbook.d.ts +5 -2
  47. package/reference/sdlc/review.playbook/review.playbook.js +65 -2
  48. package/reference/sdlc/review.playbook/review.playbook.ts +83 -6
  49. package/reference/sdlc/review.playbook/review.registry.d.ts +10 -3
  50. package/reference/sdlc/review.playbook/review.registry.js +10 -3
  51. package/reference/sdlc/review.playbook/review.registry.ts +23 -5
  52. package/slc/gears2fsm.md +6 -5
  53. package/slc/link.md +544 -41
  54. package/src/accepted-outcome.d.ts +18 -0
  55. package/src/accepted-outcome.js +94 -0
  56. package/src/accepted-outcome.ts +140 -0
  57. package/src/runtime.d.ts +164 -3
  58. package/src/runtime.ts +213 -2
  59. package/src/xstate-playbook-runtime.d.ts +149 -10
  60. package/src/xstate-playbook-runtime.js +2569 -270
  61. package/src/xstate-playbook-runtime.ts +4133 -490
  62. package/src/xstate-runtime.d.ts +59 -1
  63. package/src/xstate-runtime.js +866 -7
  64. package/src/xstate-runtime.ts +1397 -7
package/slc/link.md CHANGED
@@ -39,7 +39,13 @@ The emitted module shall default-export a factory of the following shape:
39
39
 
40
40
  ```typescript
41
41
  interface PlaybookRuntime {
42
+ readonly retainedGenerationMetadata?: PlaybookRetainedGenerationMetadata;
42
43
  init(session: PlaybookSession): Promise<void>;
44
+ adopt?(
45
+ session: PlaybookSession,
46
+ snapshot: PlaybookRuntimeSnapshot,
47
+ context: PlaybookAdoptionContext,
48
+ ): Promise<void>;
43
49
  handleBossInput(turn: {
44
50
  text: string;
45
51
  signal: AbortSignal;
@@ -49,9 +55,23 @@ interface PlaybookRuntime {
49
55
  result: PlaybookCallResult;
50
56
  signal: AbortSignal;
51
57
  }): Promise<PlaybookRunResult>;
58
+ unresolvedEffectEnvelopes?(): readonly (
59
+ | { readonly kind: 'boundary'; readonly boundaryId: string }
60
+ | { readonly kind: 'logical-operation'; readonly operationId: string }
61
+ )[];
52
62
  dispose(): Promise<void>;
53
63
  }
54
64
 
65
+ interface PlaybookRetainedGenerationMetadata {
66
+ readonly unfinishedFinalStateIds: readonly string[];
67
+ }
68
+
69
+ interface PlaybookAdoptionContext {
70
+ readonly sourceSessionId: string;
71
+ readonly sourceGenerationId: string;
72
+ readonly targetChildSessionId?: string;
73
+ }
74
+
55
75
  interface PlaybookSession {
56
76
  sessionId: string;
57
77
  playbookId: string;
@@ -121,10 +141,160 @@ interface PlaybookSuspendedCall extends PlaybookPendingCall {
121
141
  stateId: string;
122
142
  text: string;
123
143
  turnId?: number;
144
+ effectBoundaryPrefixSequence?: number | null;
145
+ }
146
+
147
+ type PlaybookRepositoryReceiptClassification =
148
+ | 'unchanged'
149
+ | 'one-descendant-commit'
150
+ | 'multiple-commits'
151
+ | 'rewritten-or-non-descendant'
152
+ | 'worktree-only-change'
153
+ | 'concurrent-or-foreign-change'
154
+ | 'observation-ambiguous';
155
+
156
+ interface PlaybookRepositoryObservation {
157
+ readonly worktree: string;
158
+ readonly gitDir: string;
159
+ readonly head: string;
160
+ readonly projection: Readonly<Record<string, JsonValue>>;
161
+ readonly projectionDigest: string;
162
+ }
163
+
164
+ interface PlaybookRepositoryReceipt {
165
+ readonly classification: PlaybookRepositoryReceiptClassification;
166
+ readonly baseline: PlaybookRepositoryObservation;
167
+ readonly after?: PlaybookRepositoryObservation;
168
+ readonly commitOid?: string;
169
+ }
170
+
171
+ type PlaybookRepositoryDisposition =
172
+ | 'unchanged'
173
+ | 'one-descendant-commit'
174
+ | 'deferred';
175
+
176
+ interface PlaybookEffectBoundary {
177
+ readonly sequence: number;
178
+ readonly boundaryId: string;
179
+ readonly attemptId: string;
180
+ readonly attemptNumber: number;
181
+ readonly playbookId: string;
182
+ readonly runtimeSessionId: string;
183
+ readonly turnId: number;
184
+ readonly callId: string;
185
+ readonly roleId: string;
186
+ readonly sourceStateId: string;
187
+ readonly sourceOutcomeSchema: JsonValue;
188
+ readonly dispositions: readonly PlaybookRepositoryDisposition[];
189
+ readonly canonicalWorktree: {
190
+ readonly worktree: string;
191
+ readonly gitDir: string;
192
+ };
193
+ readonly baseline: PlaybookRepositoryObservation;
194
+ readonly after?: PlaybookRepositoryObservation;
195
+ readonly physicalReceipt?: PlaybookRepositoryReceipt;
196
+ readonly finalText?: string;
197
+ readonly semanticCandidate?: JsonValue;
198
+ readonly initialSemanticCandidate?: JsonValue;
199
+ readonly correctionBudget: { readonly limit: 1; readonly spent: boolean };
200
+ readonly cohortId?: string;
201
+ readonly logicalOperationId?: string;
202
+ }
203
+
204
+ interface PlaybookEffectLogicalOperation {
205
+ readonly sequence: number;
206
+ readonly operationId: string;
207
+ readonly playbookId: string;
208
+ readonly runtimeSessionId: string;
209
+ readonly boundaryIds: readonly string[];
210
+ readonly originalBaseline: PlaybookRepositoryObservation;
211
+ readonly checkpoint?: PlaybookRepositoryObservation;
212
+ readonly pendingQuestion?: PlaybookPendingBossQuestion;
213
+ readonly playerContinuation?: JsonValue;
214
+ readonly checkpointRestorationEligible: boolean;
215
+ readonly logicalReceipt?: PlaybookRepositoryReceipt;
216
+ }
217
+
218
+ interface PlaybookEffectLedger {
219
+ readonly schemaVersion: 1;
220
+ readonly revision: number;
221
+ readonly boundaries: readonly PlaybookEffectBoundary[];
222
+ readonly logicalOperations: readonly PlaybookEffectLogicalOperation[];
223
+ }
224
+
225
+ type PlaybookEffectBoundaryStart = Omit<
226
+ PlaybookEffectBoundary,
227
+ | 'sequence'
228
+ | 'attemptId'
229
+ | 'attemptNumber'
230
+ | 'after'
231
+ | 'physicalReceipt'
232
+ | 'finalText'
233
+ | 'semanticCandidate'
234
+ | 'initialSemanticCandidate'
235
+ >;
236
+
237
+ type PlaybookEffectLogicalOperationStart = Omit<
238
+ PlaybookEffectLogicalOperation,
239
+ 'sequence'
240
+ >;
241
+
242
+ type PlaybookEffectLedgerCommand =
243
+ | {
244
+ readonly kind: 'start-boundaries';
245
+ readonly boundaries: readonly [
246
+ PlaybookEffectBoundaryStart,
247
+ ...PlaybookEffectBoundaryStart[],
248
+ ];
249
+ }
250
+ | {
251
+ readonly kind: 'replace-boundaries';
252
+ readonly replacements: readonly [
253
+ {
254
+ readonly expected: PlaybookEffectBoundary;
255
+ readonly next: PlaybookEffectBoundary;
256
+ },
257
+ ...{
258
+ readonly expected: PlaybookEffectBoundary;
259
+ readonly next: PlaybookEffectBoundary;
260
+ }[],
261
+ ];
262
+ }
263
+ | {
264
+ readonly kind: 'append-logical-operations';
265
+ readonly operations: readonly [
266
+ PlaybookEffectLogicalOperationStart,
267
+ ...PlaybookEffectLogicalOperationStart[],
268
+ ];
269
+ }
270
+ | {
271
+ readonly kind: 'replace-logical-operations';
272
+ readonly replacements: readonly [
273
+ {
274
+ readonly expected: PlaybookEffectLogicalOperation;
275
+ readonly next: PlaybookEffectLogicalOperation;
276
+ },
277
+ ...{
278
+ readonly expected: PlaybookEffectLogicalOperation;
279
+ readonly next: PlaybookEffectLogicalOperation;
280
+ }[],
281
+ ];
282
+ };
283
+
284
+ type PlaybookEffectLedgerCommandBatch = readonly [
285
+ PlaybookEffectLedgerCommand,
286
+ ...PlaybookEffectLedgerCommand[],
287
+ ];
288
+
289
+ interface PlaybookEffectLedgerCapability {
290
+ snapshot(): PlaybookEffectLedger;
291
+ writeAhead(
292
+ commands: PlaybookEffectLedgerCommandBatch,
293
+ ): Promise<PlaybookEffectLedger>;
124
294
  }
125
295
 
126
296
  interface PlaybookRuntimeSnapshot {
127
- schemaVersion: 3;
297
+ schemaVersion: 4;
128
298
  playbookId: string;
129
299
  machine: JsonValue;
130
300
  roleResumeTokens: { readonly [roleId: string]: string };
@@ -138,11 +308,27 @@ interface PlaybookRuntimeSnapshot {
138
308
  };
139
309
  state: PlaybookState;
140
310
  pendingBossQuestions: readonly PlaybookPendingBossQuestion[];
311
+ effectLedger: PlaybookEffectLedger;
312
+ /** Original runtime identity retained across schema-3 adoption lineage. */
313
+ retainedEffectSourceSessionId?: string;
314
+ /**
315
+ * Unsafe retained-adoption checkpoint. The marker remains durable until
316
+ * authoritative reconciliation proves its complete suffix replay-safe.
317
+ */
318
+ retainedEffectReconciliation?: {
319
+ readonly sourceSessionId: string;
320
+ readonly checkpoint: PlaybookEffectLedger;
321
+ };
322
+ failedEffectAttempt?: {
323
+ readonly boundaryPrefix: number;
324
+ readonly attemptId: string | null;
325
+ };
141
326
  suspendedCall?: PlaybookSuspendedCall;
142
327
  }
143
328
 
144
329
  type PlaybookRunResult =
145
330
  | { outcome: 'quiescent' | 'no-action'; state: PlaybookState }
331
+ | { outcome: 'unresolved-effect'; state: PlaybookState }
146
332
  | {
147
333
  outcome: 'failed' | 'aborted';
148
334
  state: PlaybookState;
@@ -165,11 +351,80 @@ type PlaybookRuntimeFactory<Options = unknown> = (
165
351
  ) => PlaybookRuntime;
166
352
 
167
353
  export default function createPlaybookRuntime(
168
- options: PlaybookRuntimeOptions,
354
+ construction: XStatePlaybookRuntimeConstruction<
355
+ PlaybookRuntimeOptions,
356
+ HostCapabilities
357
+ >,
169
358
  ): PlaybookRuntime;
170
359
  ```
171
360
 
172
- The default export conforms to `PlaybookRuntimeFactory<PlaybookRuntimeOptions>`, the generic factory type the shared contract module exposes (§Output).
361
+ For a Captain-hosted linked workflow, the default export conforms to `PlaybookRuntimeFactory<XStatePlaybookRuntimeConstruction<PlaybookRuntimeOptions, HostCapabilities>>`, where `HostCapabilities` is the artifact's exact live schema-3 capability type and `PlaybookRuntimeFactory` is the generic factory type the shared contract module exposes (§Output).
362
+ The roleless session-Captain is the sole signature exception: its public options-only `PlaybookRuntimeFactory<PlaybookRuntimeOptions>` wrapper supplies its fixed empty-ledger, fail-closed schema-3 capabilities internally because no Captain host exists above it.
363
+
364
+ Artifact schema `3` shall require `outcomeAuthority` as an own plain-JSON data property and shall instantiate the shared factory with exactly `{ configuredOptions, hostCapabilities }`, where `configuredOptions` is the registry-validated plain-JSON workflow slice and `hostCapabilities` is a non-null live current-host object.
365
+ For schema `3`, the `Options` argument of the one-argument shared `PlaybookRuntimeFactory<Options>` shall be `XStatePlaybookRuntimeConstruction<ConfiguredOptions, HostCapabilities>`; the registry's public entry receives the two members separately and composes that one internal argument only at the artifact boundary.
366
+ For a Captain-hosted schema-3 artifact, `hostCapabilities` shall contain exactly `authority`, `repository`, and `effectLedger`: authority binds that artifact's id, schema, detached role and cohort declarations, current configured working directory, logical session and lease-owner identities, and canonical worktree; repository exposes that same canonical identity plus host-bound observation, acquisition, exclusive-call, and cohort operations, whose optional live completion mapper may return only detached `finalText`, `semanticCandidate`, `logicalOperationId`, and additional typed ledger commands for the same atomic completion; and the ledger exposes its synchronous detached `snapshot(): PlaybookEffectLedger` mirror plus `writeAhead(commands: PlaybookEffectLedgerCommandBatch): Promise<PlaybookEffectLedger>` against the current host's atomic writer.
367
+ Only `configuredOptions` may reach option snapshotting and FSM input.
368
+ The capability object, its callbacks, lease token, and live claim or store handles shall enter neither `PlaybookPorts`, machine input or context, runtime snapshots, launch or durable projections, retained generations, nor continuation identity; the detached ledger data and canonical identities returned by its ledger channel shall instead persist only through the versioned effect-ledger members defined below.
369
+
370
+ ```typescript
371
+ type XStateOutcomeFieldAuthority =
372
+ | 'presentation'
373
+ | 'semantic'
374
+ | 'effect'
375
+ | 'runtime';
376
+
377
+ type XStateRepositoryDisposition =
378
+ | 'unchanged'
379
+ | 'one-descendant-commit'
380
+ | 'deferred';
381
+
382
+ interface XStateGovernedOutcomeSpec {
383
+ readonly fields: Readonly<Record<string, XStateOutcomeFieldAuthority>>;
384
+ readonly repositoryDisposition: XStateRepositoryDisposition;
385
+ }
386
+
387
+ interface XStateOutcomeAuthoritySpec {
388
+ readonly governedPlayerStates: Readonly<
389
+ Record<
390
+ string,
391
+ Readonly<Record<string, XStateGovernedOutcomeSpec>>
392
+ >
393
+ >;
394
+ }
395
+
396
+ interface XStatePlaybookRuntimeConstruction<
397
+ ConfiguredOptions,
398
+ HostCapabilities extends object,
399
+ > {
400
+ readonly configuredOptions: ConfiguredOptions;
401
+ readonly hostCapabilities: HostCapabilities & {
402
+ readonly effectLedger: PlaybookEffectLedgerCapability;
403
+ };
404
+ }
405
+ ```
406
+
407
+ The shared type-only contract module shall export `PlaybookRepositoryDisposition`, `PlaybookRepositoryObservation`, `PlaybookRepositoryReceipt`, `PlaybookEffectBoundary`, `PlaybookEffectBoundaryStart`, `PlaybookEffectLogicalOperation`, `PlaybookEffectLedger`, `PlaybookEffectLedgerCommand`, `PlaybookEffectLedgerCommandBatch`, and `PlaybookEffectLedgerCapability`; the executable `@sublang/playbook/xstate-runtime` module shall export `assertPlaybookEffectLedger`, `emptyPlaybookEffectLedger`, and `isPlaybookEffectLedgerMonotonicExtension` over those types.
408
+ That executable module shall also export the centralized schema-3 semantic surface: `PlaybookSemanticFieldAuthority`, `PlaybookSemanticOutcomeSpec`, `PlaybookSemanticEvidenceInput`, `PlaybookReconciledSemanticOutput`, `PlaybookRetainedSemanticEvidence`, `PlaybookSemanticReconciliationReason`, `PlaybookSemanticReconciliation`, `PlaybookSemanticCandidateStructureError`, and `reconcilePlaybookSemanticEvidence`.
409
+ The pure reconciler shall accept the declared state-local outcomes, an unknown semantic candidate, and optional unknown `finalText`, repository receipt, and runtime-field evidence; shall return a detached frozen `resolved` or `deferred` decision with exact output and retained evidence, or an `unresolved` decision with retained evidence and one closed reason from `missing-presentation-evidence`, `missing-repository-receipt`, `invalid-repository-receipt`, `repository-disposition-mismatch`, `missing-effect-evidence`, `missing-runtime-evidence`, and `inconsistent-runtime-evidence`; and shall reserve `PlaybookSemanticCandidateStructureError` for candidate defects eligible for the bounded correction path rather than effect-evidence disagreement.
410
+ The empty ledger shall be exactly `{ schemaVersion: 1, revision: 0, boundaries: [], logicalOperations: [] }`, and revision shall be zero if and only if both ordered ledgers are empty.
411
+ The validator shall capture the complete supplied ledger once as detached frozen JSON and enforce every closed member, identity, ordering, receipt, cross-reference, correction-budget, and logical-operation invariant represented above.
412
+ One optional host-owned UUID `cohortId` shall identify every member of exactly one contiguous, distinct-role, all-`unchanged` physical cohort in declared role order; every member shall share attempt, playbook, runtime-session, turn, canonical-worktree, and baseline identity and shall be uniformly started or uniformly complete, complete members shall carry the identical after observation and receipt, and the id shall never be reused by another group.
413
+ Within a logical operation, `checkpoint`, `pendingQuestion`, and `playerContinuation` shall be all present or all absent; the pending question shall preserve its exact nonempty authored identity and nonblank content, and `checkpointRestorationEligible: true` shall require that complete bound group.
414
+ Each logical operation shall reciprocally name every and only boundary carrying its operation id, share those boundaries' playbook and runtime-session identity, and use its first boundary's exact baseline as `originalBaseline`; every linked boundary shall use that baseline's canonical worktree and, after the first, start from the preceding boundary's complete after checkpoint, while a logical receipt shall require every linked physical receipt.
415
+ `isPlaybookEffectLedgerMonotonicExtension(checkpoint, current)` shall accept exact equality and only a ledger reachable through the typed append-or-replace transitions without boundary or operation deletion, identity or original-baseline reassignment, correction-budget replenishment, completed-receipt or evidence loss, or removal or reordering of an earlier boundary-id prefix. A spent correction may replace `semanticCandidate` exactly once only while adding `initialSemanticCandidate` equal to the prior candidate; that initial candidate then remains immutable. A replacement may append boundary ids and replace or clear the complete current checkpoint, pending-question, and player-continuation group together with its eligibility, while an existing logical receipt remains immutable ([DR-040](../specs/decisions/040-outcome-authority-effect-reconciliation.md)).
416
+ Every accepted non-idempotent command batch shall increment revision once; an exact start or append replay under the same boundary or operation identities and payload shall return the same acknowledged ledger, while conflicting identity reuse shall reject without mutation.
417
+ The host shall assign each started boundary's sequence, current uncertain-attempt UUID, and positive attempt number, and shall assign each appended logical operation's sequence.
418
+ Every command batch and every command's entry list shall be nonempty; the host shall apply its commands in order as one ledger transition, perform final cross-reference validation after the complete batch, and acknowledge only one atomic persistence and revision increment.
419
+ Every replace command's exact `{ expected, next }` pair shall compare-and-swap one present boundary or operation, preserve its identity and immutable fields, reject a stale expected value, and move optional evidence, the one-way correction budget, or the current logical binding and eligibility only as permitted by DR-040.
420
+ After a governed operation settles, the host shall retain any exact proposed completion batch only in live memory until it is acknowledged and the cooperative claim retires; an indeterminate same-process write shall retry or recognize that batch under the still-owned claim, while recovery after process death shall reconstruct only evidence provable from the durable baseline and current repository observation before source restoration.
421
+
422
+ `governedPlayerStates` shall name every delegated-player state declared by `roleStates`, or shall be exactly empty for an artifact with no delegated-player state; it shall name no other state.
423
+ Each state shall name exactly the outcomes in that state's `invoke.input.result`, and each outcome shall contain exactly `fields` and `repositoryDisposition`.
424
+ The outcome key owns the semantic discriminator, so `guard` shall not appear in `fields`; the `fields` keys shall equal every additional payload field named by that outcome's result description.
425
+ Each field shall have exactly one authority from `presentation`, `semantic`, `effect`, or `runtime`; every linker-declared verbatim payload field and `question` shall be `presentation`, `latestCommit` shall be `effect`, and the payload fields `irNumber` and `irTask` shall be `semantic`, while outcome keys such as `moreTasks` and `finalTask` remain semantic discriminators.
426
+ Each repository disposition shall be exactly `unchanged`, `one-descendant-commit`, or `deferred`; an effect-owned field is valid only on `one-descendant-commit`, and `deferred` is valid only on `needsBossReply` with presentation-owned `question` and another outcome in that state declaring `one-descendant-commit`.
427
+ The shared factory shall reject every legacy artifact schema and reject schema-3 missing, extra, unknown, wrongly owned, or inconsistent metadata before the affected player call.
173
428
 
174
429
  `init` receives the host-owned playbook session identity and ports, constructs the XState actor with FSM `input` derived from `options`, and starts the actor.
175
430
  The runtime owns the actor for its lifetime; `handleBossInput` runs one turn, and `dispose` stops the actor and drains pending port emissions.
@@ -192,7 +447,7 @@ Only the terminal variant may carry `stateDescription`; the runtime shall omit i
192
447
  Control-plane exceptions reject the runtime method rather than masquerade as a
193
448
  recoverable workflow `failed` result.
194
449
 
195
- `PlaybookRuntimeOptions` is host-agnostic and carries only _per-run_ workflow knobs, strategy overrides the linker exposes, and where the compiled playbook's policy needs a host seam host-supplied port-shaped callbacks the linker exposes as option members whose types the artifact itself declares, so the six-member `PlaybookPorts` contract and the shared contract module stay free of host types.
450
+ Configured options shall be plain JSON and live host seams shall enter only through `hostCapabilities` in the disjoint schema-3 construction input above.
196
451
  The link compiler emits a typed options interface per playbook based on the FSM's `CodingInput` (or equivalent).
197
452
  The CLI's absence of `--link-option` values does not mean that
198
453
  `PlaybookRuntimeOptions` is empty. CLI link options are compile-time inputs;
@@ -288,6 +543,8 @@ type PlaybookCallStart =
288
543
  | { state: 'suspended'; childSessionId: string };
289
544
  ```
290
545
 
546
+ A runtime's `{ outcome: 'unresolved-effect', state }` abandonment result is not a `PlaybookCallResult`: a host shall not translate it into child output or error, resume a parent FSM with it, or treat it as authored completion.
547
+
291
548
  `PlayerResult` mirrors the status, resume token, final text, and error fields of cligent's `PlayerRunResult` ([TMUX-033](https://github.com/sublang-ai/cligent/blob/main/specs/user/tmux-play.md#tmux-033)).
292
549
  The runtime treats `status !== 'ok'` as a player failure and routes it through the FSM's error path (§Abort).
293
550
  An `ok` player result whose `finalText` is missing, empty, or whitespace-only
@@ -389,7 +646,7 @@ The runtime never speaks to LLMs directly and never touches host types beyond `P
389
646
  ## Playbook trace
390
647
 
391
648
  Every linked runtime shall emit a boundary-complete, ordered trace through `emitTelemetry` topic `playbook.trace`.
392
- Each payload shall carry `schemaVersion: 3`, the immutable session identity and
649
+ Each payload shall carry `schemaVersion: 4`, the immutable session identity and
393
650
  causality, a contiguous one-based `sequence`, a Unix-millisecond `timestamp`, a
394
651
  trace `type`, event `payload`, and the runtime-local `turnId` / paired `callId`
395
652
  where applicable.
@@ -409,12 +666,13 @@ type PlaybookTraceType =
409
666
  | 'apply.started'
410
667
  | 'apply.finished'
411
668
  | 'fsm.transition'
669
+ | 'outcome.accepted'
412
670
  | 'status.emitted'
413
671
  | 'boss.input.settled'
414
672
  | 'session.disposed';
415
673
 
416
674
  interface PlaybookTraceEvent {
417
- schemaVersion: 3;
675
+ schemaVersion: 4;
418
676
  sessionId: string;
419
677
  playbookId: string;
420
678
  rootSessionId: string;
@@ -440,8 +698,9 @@ The trace types are `session.started`, `boss.input.received`,
440
698
  `player.call.finished`, `captain.call.started`, `captain.call.finished`,
441
699
  `playbook.call.started`,
442
700
  `playbook.call.finished`, `apply.started`, `apply.finished`,
443
- `fsm.transition`, `status.emitted`,
701
+ `fsm.transition`, `outcome.accepted`, `status.emitted`,
444
702
  `boss.input.settled`, and `session.disposed`.
703
+ No trace event whose `schemaVersion` is below `4` is authority-bearing accepted-outcome evidence.
445
704
  Call pairs carry exact prompts and replies, normalized failures, actor and state
446
705
  identity, and their boundary-specific options.
447
706
  `apply.started` and `apply.finished` are the paired apply boundary of a
@@ -456,8 +715,13 @@ Direct-Captain start and finish payloads shall carry `allowedTools` exactly when
456
715
  the originating `CaptainCallOptions` selects it and shall omit the member when
457
716
  the call preserves the host Captain's configured tools.
458
717
  `session.started` and `session.disposed` carry their descriptor as top-level
459
- `state` and its singular `stateId` when present. Every judge start and finish
460
- carries the working snapshot's singular `stateId` when one exists;
718
+ `state` and its singular `stateId` when present. An adopted runtime begins its
719
+ fresh target trace with `session.started` at sequence `1`; that event also
720
+ carries an exact nested `adoption` object with `sourceSessionId` and
721
+ `sourceGenerationId`, plus the source/target call and child-session identities
722
+ when a suspended edge was rebased. The suspended form carries the fresh target
723
+ call id as top-level `callId` and carries no source `turnId`. Every judge start
724
+ and finish carries the working snapshot's singular `stateId` when one exists;
461
725
  classification uses the current descriptor and adjudication uses the invoking
462
726
  actor input. The default Captain always has such a singular id, while a
463
727
  parallel snapshot may omit it. Every judge finish also carries
@@ -518,6 +782,7 @@ result: its outcome must be one of the `PlaybookRunResult` discriminants (never
518
782
  an invented `error` outcome), and it shall include `state`, singular
519
783
  `stateId`, `pendingCall`, `output`, and normalized `error` whenever the matching
520
784
  result arm carries them.
785
+ The `unresolved-effect` arm shall carry only `state`; bounded repository-effect evidence remains host-owned and shall enter neither that result nor its trace projection.
521
786
  One runtime-owned concurrency-one emission queue shall serialize every trace,
522
787
  human status, and state telemetry call. Sequence allocation and enqueueing
523
788
  shall occur atomically, and every public method shall drain that queue before
@@ -787,7 +1052,8 @@ clause (or equivalent typed output metadata). Backticked prose before that
787
1052
  clause can name statuses, guards, or concepts such as `ok`, `aborted`, and
788
1053
  `error`; those names are not output properties and shall never become required
789
1054
  judge fields.
790
- For a delegated-player field annotated exactly `` `<field>: <verbatim final text>` ``, the judge shall select the guard but the runtime shall replace any judge-supplied value with the player's canonical non-empty final text before returning the actor output.
1055
+ For a nongoverned delegated-player field annotated exactly `` `<field>: <verbatim final text>` ``, the judge shall select the guard but the runtime shall replace any judge-supplied value with the player's canonical non-empty final text before returning the actor output.
1056
+ For an artifact-schema-3 governed field, that annotation instead declares presentation authority and any judge-supplied value is a structural error under the authority rule below.
791
1057
  The linker shall derive the complete `verbatimPayloadFields` set from those annotations across the FSM result maps.
792
1058
  A field name that is annotated in one result map and unannotated in another is a link error because the shared adjudication strategy cannot give one property both ownership policies.
793
1059
  For a direct Captain result, `question` and `response` are human-presentation
@@ -800,13 +1066,87 @@ After validating that selection, the runtime shall inject the exact non-empty
800
1066
  It shall reject a judge reply that supplies either presentation field as an
801
1067
  undeclared extra key, so hidden adjudication cannot replace, paraphrase, or
802
1068
  decorate prose Boss already saw.
803
- Delegated-player adjudication retains extraction of every required field from
804
- the judge reply, including a player-authored Boss question.
1069
+ For an artifact-schema-3 governed delegated-player call, the shared engine
1070
+ shall instead use one semantic reconciler for both the default linked runtime
1071
+ and any bespoke linked runtime that adopts schema `3`.
1072
+ That reconciler shall retain the validated player's exact non-empty
1073
+ `finalText` as opaque presentation evidence, let the hidden adjudicator read
1074
+ it only as semantic evidence, and require the adjudicator's detached
1075
+ plain-JSON candidate to contain exactly `guard` plus every and only
1076
+ semantic-owned payload field declared for that guard.
1077
+ The candidate shall therefore contain no presentation-, effect-, or
1078
+ runtime-owned payload field; `guard` shall name exactly one outcome declared
1079
+ by both the live result map and `outcomeAuthority`; and every semantic-owned
1080
+ field shall satisfy the result map's required-field type before any actor
1081
+ output is delivered.
1082
+ The reconciler shall construct the complete actor output rather than accept a
1083
+ cross-authority object from the judge: every presentation-owned payload field
1084
+ shall receive the canonical `finalText.trim()` value, effect-owned
1085
+ `latestCommit` shall receive only the qualifying receipt's exact commit OID,
1086
+ and no authority may supply, overwrite, or contradict another authority's
1087
+ field.
1088
+ It shall reject an absent required field, an undeclared or extra field, a
1089
+ field supplied by the wrong authority, an invalid value, or any mutually
1090
+ inconsistent candidate before FSM delivery.
1091
+
1092
+ For a non-deferred candidate, reconciliation shall require a complete durable
1093
+ physical receipt, or the complete cumulative logical receipt of a deferred
1094
+ operation, whose classification is exactly the outcome's declared
1095
+ `unchanged` or `one-descendant-commit` disposition; the latter shall carry
1096
+ exactly the after-HEAD OID used for `latestCommit`.
1097
+ A `deferred` candidate shall be admissible only for its already-validated
1098
+ effect-authorized `needsBossReply` outcome and only from a complete after
1099
+ observation whose HEAD equals the logical operation's original baseline HEAD
1100
+ and whose classification is exactly `unchanged` or `worktree-only-change`.
1101
+ It shall become deliverable only after the current host durably acknowledges
1102
+ the exact checkpoint, question, continuation, and logical-operation binding
1103
+ defined above; a missing checkpoint, changed HEAD, multiple or rewritten
1104
+ history, detected concurrent or foreign change, or ambiguous observation
1105
+ shall leave it unresolved.
1106
+
1107
+ The first structurally invalid schema-3 semantic reply shall make at most one
1108
+ corrective hidden adjudication eligible over the identical retained
1109
+ presentation evidence and declared outcome schema, with the validation error
1110
+ restated.
1111
+ Before starting that corrective judge, the runtime shall compare-and-swap the
1112
+ boundary's `correctionBudget` from `{ limit: 1, spent: false }` to
1113
+ `{ limit: 1, spent: true }` while atomically retaining its receipt, opaque
1114
+ presentation, and first recoverable invalid `semanticCandidate` through
1115
+ `effectLedger.writeAhead`, await the durable acknowledgement, replace its
1116
+ mirror with that acknowledged ledger, and check the applicable abort signal
1117
+ again.
1118
+ A failed or indeterminate spend, an acknowledgement that does not contain the
1119
+ exact one-way update, a previously spent budget, or an abort before the call
1120
+ begins shall start no corrective judge; the spent value shall remain spent
1121
+ across export, restore, adoption, and process restart.
1122
+ A second structurally invalid reply shall receive no further correction.
1123
+ A player abort, error, non-`ok` result, or missing non-empty `finalText` shall
1124
+ start no adjudication, while an initial or corrective judge transport failure
1125
+ or invalid host result shall start no corrective or third judge respectively.
1126
+
1127
+ Only a complete, authority-consistent semantic-and-effect envelope shall be
1128
+ delivered once to the FSM, and only after its evidence and applicable
1129
+ correction-budget or deferred-operation updates are durably acknowledged.
1130
+ The completion path shall retain the opaque `finalText`, the latest recoverable
1131
+ detached plain-JSON semantic candidate even when it is structurally invalid,
1132
+ and the receipt and correction budget without parsing the presentation for a
1133
+ repository fact; where a correction replaces that candidate, immutable
1134
+ `initialSemanticCandidate` shall preserve the candidate that consumed the
1135
+ budget, while a malformed reply from which no JSON value can be recovered may
1136
+ omit both candidates.
1137
+ An effect-possible envelope whose presentation, semantic, effect, or deferred
1138
+ checkpoint evidence is absent, invalid, incomplete, or inconsistent shall
1139
+ deliver no actor output and shall remain parked for later reconciliation;
1140
+ once its matching source state is restored, reconstruction from a durable
1141
+ complete envelope may perform that same reconciliation once without another
1142
+ player or judge call.
805
1143
  The adjudicator shall use the same document-order tolerant JSON recovery as
806
1144
  the Boss classifier. Unlike invalid classification, a reply from which no
807
1145
  object can be recovered, an undeclared guard, or a missing required field is a
808
- control-plane error and shall throw after the invocation reaches its FSM error
809
- path and ordered emissions drain.
1146
+ control-plane error for nongoverned delegated-player and direct-Captain adjudication and
1147
+ shall throw after the invocation reaches its FSM error path and ordered
1148
+ emissions drain; schema-3 governed adjudication follows the bounded
1149
+ reconciliation contract above instead.
810
1150
 
811
1151
  Two default adjudication strategies, in selection order:
812
1152
 
@@ -814,9 +1154,11 @@ Two default adjudication strategies, in selection order:
814
1154
  names the source item's actor (and delegated player where applicable),
815
1155
  includes the actor's verbatim output,
816
1156
  lists the `result` keys with their descriptions, and demands a JSON
817
- `{ guard, …structuralPayloadFields }` answer keyed to exactly one of the
818
- declared guards, excluding the runtime-owned direct-Captain `question` and
819
- `response` fields above. The prompt shall identify hidden control work,
1157
+ answer keyed to exactly one of the declared guards: a nongoverned player uses
1158
+ `{ guard, …structuralPayloadFields }`, while a governed schema-3 player uses
1159
+ `{ guard, …semanticOwnedPayloadFields }` and explicitly forbids every other
1160
+ payload field. Both forms exclude the runtime-injected direct-Captain
1161
+ `question` and `response` fields above. The prompt shall identify hidden control work,
820
1162
  prohibit tool use, file inspection, and external evidence, direct the judge
821
1163
  to decide only from the supplied actor output and declared outcomes, and
822
1164
  require exactly one JSON object with no prose. The judge prompt shall not
@@ -889,7 +1231,7 @@ the `{ visibility: 'visible', resume: false }` workflow-call selection
889
1231
  (§PlaybookPorts contract, §Captain prompt composition) stay the
890
1232
  visible-presentation shape for non-controller playbooks.
891
1233
 
892
- The adjudicator shall fail loudly on:
1234
+ The nongoverned player adjudicator and every direct-Captain adjudicator shall fail loudly on:
893
1235
 
894
1236
  - A guard the state does not declare,
895
1237
  - A missing payload field the state's `result` description requires,
@@ -901,7 +1243,7 @@ identify an undeclared guard, and an incomplete selection shall identify the
901
1243
  missing required field. A generic “no declared guard selected” error for all
902
1244
  three cases is nonconformant.
903
1245
 
904
- Adjudicator failures are control-plane errors.
1246
+ Those adjudicator failures are control-plane errors.
905
1247
  The runtime shall propagate them by throwing out of `handleBossInput` after attempting cleanup.
906
1248
  The host adapter surfaces the throw on its control-plane channel (cligent surfaces such throws as `runtime_error` per [TMUX-025](https://github.com/sublang-ai/cligent/blob/main/specs/user/tmux-play.md#tmux-025)).
907
1249
  The host's player-result channels (`player_finished` and equivalents) are reserved for failures the player itself produced; the host emits them when `callPlayer` resolves with `status !== 'ok'`.
@@ -911,11 +1253,12 @@ failure path specified above. Captain transport, result-shape, trace-sink, and
911
1253
  adjudication failures remain control-plane errors unless the transport failure
912
1254
  is causally identical to the active abort signal.
913
1255
  Because XState still needs the invoked promise to settle, the linked runtime
914
- shall latch an adjudicator, actor-output JSON-validation, or nested-boundary
1256
+ shall latch a nongoverned delegated-player or direct-Captain adjudicator failure, actor-output JSON-validation, or nested-boundary
915
1257
  control error outside machine context, allow the invocation's `onError` path to
916
1258
  reach quiescence, drain all emissions, and then reject the public runtime
917
1259
  method with that original error. It shall not return such a failure as a
918
1260
  recoverable `{ outcome: 'failed' }` workflow result.
1261
+ An artifact-schema-3 governed-player adjudicator shall instead use the bounded structural correction, authority reconciliation, and unresolved parking contract above.
919
1262
  The first latched non-abort control error takes precedence over a coincident
920
1263
  boundary-signal abort. Read and clear the latch only in the public boundary's
921
1264
  `finally` cleanup after XState and emissions have settled, so it cannot leak
@@ -1279,18 +1622,22 @@ The `PlaybookRuntime` shall:
1279
1622
  The actor's `lastError` field shall be surfaced via `emitStatus` when the machine enters its `failed` state.
1280
1623
  Presence of linker-emitted `roleStates` selects the canonical factory-backed status profile.
1281
1624
  That profile shall emit the selected Boss event type
1282
- before sending that event, exactly `→ <guard>` (with no payload-count or tally
1283
- rider) when a settling actor output carries a guard, and
1625
+ before sending that event; exactly `→ <acceptedOutcome>` (with no payload-count or tally
1626
+ rider) only from a confirmed accepted-outcome marker; and
1284
1627
  `⤷ <Role>: <label>` only when the entered state appears in the linked module's `roleStates` metadata.
1285
1628
  It shall emit no raw state-id fallback for any other state.
1286
1629
  `roleStates` shall be a complete map of the FSM states
1287
- that invoke the typed `player` actor; each schema-2 value carries the exact
1630
+ that invoke the typed `player` actor; each value carries the exact
1288
1631
  local role from that state's source-derived `meta.playbook.role` and the state's exact FSM description as `{ role, label }`.
1289
1632
  The factory shall reject an
1290
1633
  incomplete entry, a non-player state, or a role or label that differs from the FSM metadata.
1291
1634
  Artifact schema `1` and a missing compatibility declaration
1292
1635
  shall reject before interpretation because their legacy `player` values may
1293
1636
  encode bindings or aliases rather than canonical local roles.
1637
+ For artifact schema `3`, an accepted-outcome marker is a root-machine XState action with exact type `playbook.acceptedOutcome` and exact plain-data params `{ source, target, acceptedOutcome }` naming a declared governed outcome.
1638
+ The runtime shall observe that action only through the public root `@xstate.action` inspection event, retain it privately until the corresponding next public root `@xstate.snapshot` confirms `source` active in the prior snapshot and `target` active in the new snapshot, then emit one trace-schema-4 `outcome.accepted` event with those exact params before its canonical status and before public settlement; markers confirmed together shall retain their XState execution order.
1639
+ A valid unmarked transition, including an unexecuted guarded arm or rejected-guard fallback, shall settle normally with neither accepted-outcome evidence nor claimed-outcome status.
1640
+ An executed marker that is malformed, undeclared, or unconfirmed by those adjacent snapshots, or a batch that instruments one governed source more than once regardless of target or outcome, shall clear the entire pending marker batch and fail the current public boundary after retaining the ordinary transitioned state but before settlement, accepted-outcome evidence, or claimed-outcome status.
1294
1641
  For the default Captain runtime, an initial `ready` state and a terminal `done`
1295
1642
  state shall not emit human status. The terminal response is already visible
1296
1643
  Captain prose; a synthetic “entered done” message would present it twice.
@@ -1333,18 +1680,22 @@ quiescent state with actor status `active`.
1333
1680
  At a safe capture point it shall return a JSON-safe
1334
1681
  `PlaybookRuntimeSnapshot` carrying:
1335
1682
 
1336
- - `schemaVersion`: literal `3`.
1683
+ - `schemaVersion`: literal `4`.
1337
1684
  - `playbookId`: the bound session's playbook id.
1338
1685
  - `machine`: the root actor's `getPersistedSnapshot()` result, passed
1339
1686
  through the shared JSON detachment with any raw `Error` context value
1340
1687
  (for example FSM `lastError`) normalized to `{ name, message, stack? }`
1341
1688
  first. The value is opaque to hosts.
1689
+ - `effectLedger`: the detached immutable schema-version-1 mirror most recently
1690
+ acknowledged by the current host's atomic ledger channel; a linked workflow
1691
+ runtime carries the complete current-host mirror, while the internal compiled
1692
+ Captain runtime carries the exact empty ledger.
1342
1693
  - `roleResumeTokens`: the local-role resume-token projection as a plain object
1343
1694
  (§PlaybookPorts contract).
1344
1695
  - `sequences`: the live `trace`, `turn`, `judgeCall`, `playerCall`, and
1345
1696
  `playbookCall` counters, plus `captainCall` when the runtime supports direct
1346
1697
  Captain calls.
1347
- A direct-Captain-capable runtime shall persist it in every schema-version-3 export.
1698
+ A direct-Captain-capable runtime shall persist it in every schema-version-4 export.
1348
1699
  - `state`: the current normalized state descriptor.
1349
1700
  - `pendingBossQuestions`: the pending Boss question(s) from FSM context as
1350
1701
  a list of `{ questionId, asker, question, sourceItem? }`, where `asker` is
@@ -1366,14 +1717,18 @@ unsafe and returns `undefined`.
1366
1717
  `restore(session, snapshot)` is an alternative to `init` under the same
1367
1718
  lifecycle guards (§Session lifecycle): it shall reject when already
1368
1719
  initialized, disposing, or disposed, and shall validate
1369
- schema version `3` and that `snapshot.playbookId` equals `session.playbookId` before touching state.
1370
- Runtime snapshot schemas `1` and `2` shall reject before state binding because their token and pending-question fields conflate local roles, concrete players, and Captain identity.
1720
+ schema version `4`, the complete effect-ledger mirror, and that `snapshot.playbookId` equals `session.playbookId` before touching state.
1721
+ Runtime snapshot schemas `1` and `2` shall reject before state binding because their token and pending-question fields conflate local roles, concrete players, and Captain identity; schema `3` shall reject because it cannot prove an effect ledger.
1371
1722
  The host supplies the same immutable `PlaybookSession` identity the
1372
1723
  snapshot was exported under and recreates the runtime through the same
1373
1724
  factory with equivalent options; the runtime does not diff options, and
1374
1725
  module identity — that the factory constructing this runtime still
1375
1726
  belongs to the snapshot's playbook — is likewise the host's check to
1376
1727
  make before calling `restore`.
1728
+ Before actor or source-state restoration, a linked workflow runtime shall require
1729
+ the snapshot ledger to equal the detached synchronous mirror exposed by its
1730
+ current-host capability; the internal Captain runtime shall require its mirror
1731
+ to be empty.
1377
1732
  `restore` shall bind the session and its current detached role bindings, restore the local-role token projection, the
1378
1733
  sequence counters, and the
1379
1734
  prior-state descriptor from the snapshot,
@@ -1396,6 +1751,110 @@ ownership without a child-host call or duplicate start/finish boundary.
1396
1751
  A restore failure shall leave the runtime unbound so `dispose` remains
1397
1752
  callable and terminal.
1398
1753
 
1754
+ ## Retained-snapshot adoption (optional)
1755
+
1756
+ A linked runtime may implement the optional adoption capability of
1757
+ `@sublang/playbook/runtime` — `adopt(session, snapshot, context)` — as a third
1758
+ initialization path distinct from `init` and same-engagement `restore`.
1759
+ Adoption may bind a retained generation to a fresh valid `PlaybookSession`
1760
+ identity. Every runtime the shared `createXStatePlaybookRuntime` factory
1761
+ constructs implements `adopt`, regardless of whether the artifact supplies
1762
+ retained-generation classification metadata; a bespoke runtime may omit it,
1763
+ and hosts feature-detect the capability by member presence.
1764
+
1765
+ Before actor construction or any player-session-store, port, trace, status,
1766
+ or telemetry effect, `adopt` shall validate and detach the target session, the
1767
+ snapshot, and an exact closed-schema `PlaybookAdoptionContext` whose nonempty
1768
+ `sourceSessionId` names the retained frame's source runtime session, whose
1769
+ nonempty `sourceGenerationId` names the retained stack root's source
1770
+ `rootSessionId`, and whose optional nonempty `targetChildSessionId` is present
1771
+ exactly when the snapshot carries a suspended call. The source session and
1772
+ generation ids shall coincide exactly for a root frame. The target session and
1773
+ root ids shall each differ from their source counterparts, and a supplied
1774
+ target child id shall differ from every source and target identity visible to
1775
+ that frame. Accessors, unknown or missing members, empty identities, and an
1776
+ inconsistent child mapping shall reject during preflight.
1777
+
1778
+ That preflight shall also validate the part of the exact structural envelope
1779
+ visible to the runtime: snapshot schema version `4`, target playbook id, the
1780
+ factory's already-validated artifact contract, and any supplied local-role
1781
+ binding set against the artifact's declared roles. The adopting host
1782
+ owns the working-directory and complete catalog-entry comparison — registry
1783
+ module identity, manifest command, options, and role set — plus every retained
1784
+ frame's artifact-schema comparison, and shall perform them before calling the
1785
+ runtime capability (DR-038 §3).
1786
+ The preflight shall apply the same exact full-mirror rule as restore: a linked
1787
+ workflow target receives a current-host mirror equal to the retained ledger,
1788
+ while the internal Captain target requires the retained ledger to be empty.
1789
+
1790
+ Adoption shall not restore any source counter. The fresh target trace, turn,
1791
+ judge-call, player-call, supported direct-Captain-call, playbook-call, and
1792
+ apply-call counter spaces shall start at zero. Before its session-start trace,
1793
+ a descriptor-free adoption leaves the playbook-call counter at zero. A
1794
+ suspended adoption instead consumes `playbook-1` as the fresh target call id,
1795
+ replaces the descriptor's source child id with `targetChildSessionId`, omits the
1796
+ source `turnId`, and sets the target playbook-call counter to one; it changes no
1797
+ opaque persisted machine value and makes no child-host call.
1798
+
1799
+ After preflight, adoption shall construct the persisted actor and prepare the
1800
+ nested bridge through the same transaction as restore, using the rebased
1801
+ descriptor or an explicit absence. Before actor startup it shall emit exactly
1802
+ one `session.started` as target trace sequence `1`, carrying the adopted
1803
+ top-level `state` and optional `stateId` plus an exact `adoption` object:
1804
+
1805
+ - without a suspended call, `{ sourceSessionId, sourceGenerationId }`;
1806
+ - with a suspended call, `{ sourceSessionId, sourceGenerationId,
1807
+ sourceCallId, sourceChildSessionId, targetCallId: 'playbook-1',
1808
+ targetChildSessionId }`, while the event also carries top-level
1809
+ `callId: 'playbook-1'` and no `turnId`.
1810
+
1811
+ The runtime shall then start the actor with inspection effects suppressed,
1812
+ claim the rebased descriptor, require the reconstructed active normalized
1813
+ state to equal the retained state under that rebase, drain suppressed work,
1814
+ and confirm the bridge as the final fallible step. A preflight mismatch emits
1815
+ nothing. A later state or bridge mismatch makes no child-host call or
1816
+ playbook-call start/finish boundary, rolls provisional ownership back, and,
1817
+ because the target start was attempted, performs failed-start cleanup with one
1818
+ best-effort target `session.disposed`; successful cleanup leaves the runtime
1819
+ reusable. A successful adoption shall close `init`, `restore`, and `adopt`
1820
+ under the ordinary one-start runtime lifecycle. Its immediate export shall
1821
+ carry trace sequence `1`, zero fresh turn, judge, and player counters, zero
1822
+ direct-Captain counter when supported, and playbook-call sequence zero or one
1823
+ according to the suspended shape. Later target turns and calls allocate from
1824
+ those fresh counters rather than continue any source id or sequence. Ordinary
1825
+ same-engagement restore remains trace-silent and preserves its source
1826
+ identities and counters exactly (DR-038 §5).
1827
+
1828
+ Adoption shall not apply the retained snapshot's `roleResumeTokens` through a
1829
+ supplied player-session store's `restore` operation or seed runtime-private
1830
+ continuation from them. For every later local-role invocation, any target
1831
+ session `roleBindings` are the sole source of supplied player and prompt
1832
+ identities, and any supplied player-session store is the sole conversation
1833
+ authority. The runtime shall resolve the current binding and, when a store is
1834
+ supplied, select it at the invocation boundary and pass the exact selected
1835
+ token or `false`. Where
1836
+ the ordinary continuation rules authorize a store mutation, that mutation
1837
+ shall target the same store. It shall never fall back to the retained token
1838
+ projection. A replacement binding whose current selection is `false` therefore
1839
+ starts fresh under its new identities; without a supplied store, the target
1840
+ runtime's private continuation starts empty (DR-038 §4).
1841
+
1842
+ ## Retained-generation classification (optional)
1843
+
1844
+ A linked runtime may expose the optional read-only
1845
+ `retainedGenerationMetadata` marker of `@sublang/playbook/runtime` together
1846
+ with the parked-session snapshot pair and the independently feature-detected
1847
+ adoption capability so a Captain can retain its safe pre-terminal generations.
1848
+ Its `unfinishedFinalStateIds` array shall preserve the artifact's link-time
1849
+ declaration exactly, including an explicitly empty set, and shall be immutable
1850
+ and detached from that declaration. Absence means the runtime contributes no
1851
+ retained generation; presence supplies only terminal classification metadata
1852
+ and does not itself supply the adoption operation.
1853
+ Every runtime the shared `createXStatePlaybookRuntime` factory constructs from
1854
+ a supplied `unfinishedFinalStateIds` spec member shall expose the marker; a
1855
+ bespoke runtime opts into classification only by implementing the public member
1856
+ itself.
1857
+
1399
1858
  ## Control surface (optional)
1400
1859
 
1401
1860
  A linked runtime may implement the optional control-surface capability of
@@ -1432,6 +1891,12 @@ type PlaybookControlReceipt =
1432
1891
  // Optional PlaybookRuntime members — both or neither:
1433
1892
  describe?(): PlaybookControlView;
1434
1893
  apply?(input: { actionId: string; key: string; signal: AbortSignal }): Promise<PlaybookControlReceipt>;
1894
+
1895
+ // Independent optional host-only unresolved-envelope identity seam:
1896
+ unresolvedEffectEnvelopes?(): readonly (
1897
+ | { readonly kind: 'boundary'; readonly boundaryId: string }
1898
+ | { readonly kind: 'logical-operation'; readonly operationId: string }
1899
+ )[];
1435
1900
  ```
1436
1901
 
1437
1902
  `describe()` shall be side-effect free — it emits no trace, status, or
@@ -1452,6 +1917,16 @@ identifier for it. A state whose source declares no description carries no
1452
1917
  `stateDescription`: an id is never promoted into a description, so a host is
1453
1918
  never handed an identifier dressed as meaning.
1454
1919
 
1920
+ At that same safe control-capture point, a schema-3 runtime that retains
1921
+ effect-possible outcome-unresolved work may expose
1922
+ `unresolvedEffectEnvelopes()` so its host can project the authoritative effect
1923
+ ledger. The method shall return only exact nonblank durable boundary or
1924
+ logical-operation identities in envelope order, shall return an empty list
1925
+ when no unresolved envelope remains, and shall expose no receipt, repository
1926
+ observation, semantic evidence, prose, or live authority. It is side-effect
1927
+ free on the same terms as `describe()`, and no returned identity or bounded
1928
+ repository evidence shall enter `PlaybookRunResult`.
1929
+
1455
1930
  The view's `context` is an explicit projection the linked runtime **authors**,
1456
1931
  never an allow-by-default serialization of the FSM context (PBRT-52).
1457
1932
  Only the runtime knows which of its context members are safe and relevant
@@ -1482,8 +1957,9 @@ default. The rules:
1482
1957
  Actions derive from the live snapshot, only at the same safe point the
1483
1958
  parked-session snapshot uses (actor status `active`, quiescent, no pending
1484
1959
  nested call); anywhere else `actions` is empty while the rest of the view
1485
- still describes the state. Two families exist, labeled from source state
1486
- descriptions:
1960
+ still describes the state.
1961
+ While effect-possible outcome evidence remains unresolved, the view shall omit its pending Boss questions and state description and shall replace every ordinary action with exactly `reconcile:unresolved-effect` labeled `Retry unresolved effect reconciliation` and `abandon:unresolved-effect` labeled `Abandon unresolved workflow attempt`.
1962
+ Otherwise two ordinary families exist, labeled from source state descriptions:
1487
1963
 
1488
1964
  - **Failure-state retry** — while the singular state id is the recoverable
1489
1965
  failure state and the live snapshot accepts the retry event sourced below,
@@ -1528,8 +2004,8 @@ its key — a later call with that key revalidates afresh, traces its own
1528
2004
  pair, and may execute once the action is advertised — and a key whose call
1529
2005
  threw before reaching acceptance (lifecycle misuse, invalid input, a
1530
2006
  pre-acceptance abort, a rejected start-boundary sink) likewise records
1531
- nothing, so a later call with that key may execute. Executing sends the
1532
- validated event through the same actor drive as `handleBossInput` — state
2007
+ nothing, so a later call with that key may execute.
2008
+ Executing an ordinary retry or jump sends the validated event through the same actor drive as `handleBossInput` — state
1533
2009
  transitions, player/judge boundaries, statuses, and traces flow unchanged —
1534
2010
  and settles `executed` with the projected run result, or `failed` with the
1535
2011
  normalized error when the run settles in the failure state, aborts, or a
@@ -1540,6 +2016,11 @@ the paired `apply.started` / `apply.finished` events of §Playbook trace, and
1540
2016
  `apply` shares the single active-boundary sentinel with `handleBossInput`
1541
2017
  and `resumePlaybookCall`.
1542
2018
 
2019
+ Executing `reconcile:unresolved-effect` shall use only the current host's authoritative effect ledger for any reconciliation refresh and shall start no player.
2020
+ When an open deferred logical operation is checkpoint-restoration eligible, that action shall reacquire its exclusive repository claim and compare the current observation with the saved checkpoint; exact equality shall durably consume eligibility and return to the identical bound wait with its stable question through an ordinary nonterminal run result without a player, judge, or semantic-candidate delivery, while inequality or any other still-unresolved evidence shall return `no-action` and remain unresolved.
2021
+ Executing `abandon:unresolved-effect` shall move no FSM state or start any player, judge, Captain, script, or child call and shall settle `executed` with exactly `{ outcome: 'unresolved-effect', state }`, where `state` is the current normalized nonfinal state.
2022
+ That state-only run-result arm shall carry no `stateDescription`, output, pending call, error, repository receipt, effect ledger, semantic evidence, or other bounded effect fact, and shall claim neither an authored outcome nor workflow completion.
2023
+
1543
2024
  Acceptance is also the line past which `apply` does not throw, and
1544
2025
  publication — the `apply.finished` emission — is the line past which its
1545
2026
  receipt no longer changes. A settlement failure after acceptance but before
@@ -1694,6 +2175,11 @@ The `playbook.trace` copies are the host-agnostic runtime-boundary record requir
1694
2175
  ## Output
1695
2176
 
1696
2177
  The link compiler emits one TypeScript module per playbook.
2178
+ Every linked artifact shall emit an `unfinishedFinalStateIds` set beside its resumable-state registry as mechanical link-time metadata.
2179
+ The set shall contain exactly the stable ids of root `type: 'final'` states whose terminal outcomes leave the procedure unfinished, and shall be explicitly empty when no terminal outcome does.
2180
+ The linker shall not infer the set from a state description, opaque output, or procedure prose.
2181
+ The linker shall reject a declared id that does not name a root final state, and the shared factory shall independently reject it at construction before runtime effects.
2182
+ For a factory-backed artifact the set is a `spec` member; a bespoke artifact shall retain equivalent linked metadata, and the artifact declaration is not itself the public runtime retention marker or an adoption capability.
1697
2183
  For an FSM that declares no `type: 'parallel'` state — necessarily flat
1698
2184
  under [gears2fsm.md](gears2fsm.md)'s one-state-per-item mapping — it shall
1699
2185
  emit the thin shared-factory module defined below.
@@ -1703,8 +2189,9 @@ machinery satisfying this document's runtime contract and shall not invoke
1703
2189
  FSMs under [DR-019](../specs/decisions/019-shared-linked-runtime-factory.md).
1704
2190
  The FSM-interpreter machinery — actor wiring, boundary tracing, Boss-event
1705
2191
  mapping, adjudication, script execution, nested-playbook bridging, session
1706
- lifecycle, abort handling, and the optional parked-session snapshot
1707
- capability — is not regenerated for a factory-backed artifact: it ships once
2192
+ lifecycle, abort handling, and the optional parked-session snapshot and
2193
+ retained-snapshot adoption capabilities — is not regenerated for a
2194
+ factory-backed artifact: it ships once
1708
2195
  as the shared `createXStatePlaybookRuntime(machine, spec)` factory exported by
1709
2196
  `@sublang/playbook/xstate-runtime`, and the emitted module hands its FSM and
1710
2197
  a small per-playbook `spec` to that factory. Every behavioral section of
@@ -1758,9 +2245,13 @@ The thin emitted module:
1758
2245
  complete `roleStates` status map derived from every FSM state that invokes
1759
2246
  the typed `player` actor, with each `role` copied from that state's
1760
2247
  source-derived `meta.playbook.role` (an empty map when there is no such
1761
- state); the
2248
+ state); the exact schema-3 `outcomeAuthority` map derived
2249
+ from every such state's `invoke.input.result` contract and its linked field
2250
+ authorities and repository dispositions (an explicit empty governed map
2251
+ when there is no such state); the
1762
2252
  `verbatimPayloadFields` set derived from annotated result fields above; the
1763
- `controlContextFields` projection of §Control surface; and any
2253
+ explicitly empty or populated `unfinishedFinalStateIds` set declared above;
2254
+ the `controlContextFields` projection of §Control surface; and any
1764
2255
  per-playbook strategy override (classifier, prompt composers,
1765
2256
  required-field extraction, status formatting) an earlier section of this
1766
2257
  definition requires for that playbook.
@@ -1817,9 +2308,8 @@ The thin emitted module:
1817
2308
  runtime-owned arm to have lost payload detail under erasure shall report
1818
2309
  that gap rather than emit the entry.
1819
2310
  - Supplies `spec.compat` with the compatibility values current at link time:
1820
- `{ artifactSchema, runtimeAbi }`, where `artifactSchema` is `2` the
1821
- schema number of the local-role thin-module format this §Output defines — and
1822
- `runtimeAbi` is the installed shared engine's `RUNTIME_ABI` self-report.
2311
+ `{ artifactSchema: 3, runtimeAbi }`, where `runtimeAbi` is the installed shared engine's
2312
+ `RUNTIME_ABI` self-report.
1823
2313
  The linker shall verify that the installed engine lists the emitted
1824
2314
  schema in `SUPPORTED_ARTIFACT_SCHEMAS` and treat its absence as a
1825
2315
  link-time error; it shall not stamp a different member (such as the
@@ -1830,9 +2320,22 @@ The thin emitted module:
1830
2320
  module and fails construction on a mismatch, so an artifact linked under
1831
2321
  one engine cannot run silently skewed under another. Modules emitted
1832
2322
  before this contract carry no `compat` member and shall reject before interpretation.
1833
- - Requires the containing public registry manifest to advertise the same `artifactSchema: 2`; the Captain host shall reject a missing or disagreeing registry value before constructing this runtime, and a bespoke runtime profile shall advertise the same schema without claiming this shared factory's `runtimeAbi`.
1834
- - Default-exports the factory call as `createPlaybookRuntime`, typed
1835
- `PlaybookRuntimeFactory<PlaybookRuntimeOptions>`. A registry module loads
2323
+ - Requires the containing public registry manifest to advertise the identical
2324
+ `artifactSchema` and an exact implementation `runtimeProfile`. A shared
2325
+ factory profile is `{ kind: 'shared-factory', compat }`, where `compat` is
2326
+ the immutable compatibility record captured by that actual factory from
2327
+ its validated `spec.compat`; a bespoke profile is
2328
+ `{ kind: 'bespoke', artifactSchema }`, with schema `3` declared directly by
2329
+ that implementation and no `runtimeAbi` claim. A registry factory accepts configured options and current
2330
+ host capabilities separately and composes the linked runtime's exact
2331
+ `{ configuredOptions, hostCapabilities }` input. The Captain host shall
2332
+ capture the imported manifest fields once, require capabilities for every
2333
+ and only enabled artifact id, validate each capability's artifact, role,
2334
+ cohort, and canonical-worktree authority, and reject a missing, extra,
2335
+ malformed, or mismatched capability before runtime construction.
2336
+ - Default-exports the factory call as `createPlaybookRuntime`, typed as
2337
+ `XStatePlaybookRuntimeFactory<XStatePlaybookRuntimeConstruction<PlaybookRuntimeOptions, HostCapabilities>, 3>`
2338
+ with the artifact's declared live capability type. A registry module loads
1836
2339
  dynamically inside the host's caught boundary, so its eager module-scope
1837
2340
  factory call fails fast there. The compiled session Captain module is the
1838
2341
  exception: the shell and both CLI front ends import it statically, so it