@sublang/playbook 9.0.0 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/docs/cli.md +109 -21
- package/docs/configuration.md +89 -40
- package/docs/embedding.md +126 -12
- package/package.json +14 -3
- package/reference/sdlc/captain.md +14 -10
- package/reference/sdlc/captain.playbook/captain.fsm.d.ts +33 -13
- package/reference/sdlc/captain.playbook/captain.fsm.js +80 -9
- package/reference/sdlc/captain.playbook/captain.fsm.ts +137 -18
- package/reference/sdlc/captain.playbook/captain.gears.md +10 -6
- package/reference/sdlc/captain.playbook/captain.playbook.d.ts +5 -1
- package/reference/sdlc/captain.playbook/captain.playbook.js +140 -10
- package/reference/sdlc/captain.playbook/captain.playbook.ts +188 -16
- package/reference/sdlc/code.md +35 -16
- package/reference/sdlc/code.playbook/bin/interactive-session.js +228 -23
- package/reference/sdlc/code.playbook/bin/launch-config.js +611 -221
- package/reference/sdlc/code.playbook/bin/playbook.js +304 -178
- package/reference/sdlc/code.playbook/bin/replay-observer.js +221 -0
- package/reference/sdlc/code.playbook/bin/repository-effects.js +2930 -0
- package/reference/sdlc/code.playbook/bin/run.js +669 -215
- package/reference/sdlc/code.playbook/bin/session-store.js +4546 -502
- package/reference/sdlc/code.playbook/code.fsm.d.ts +7 -0
- package/reference/sdlc/code.playbook/code.fsm.js +74 -25
- package/reference/sdlc/code.playbook/code.fsm.ts +83 -29
- package/reference/sdlc/code.playbook/code.gears.md +0 -2
- package/reference/sdlc/code.playbook/code.playbook.d.ts +5 -2
- package/reference/sdlc/code.playbook/code.playbook.js +54 -2
- package/reference/sdlc/code.playbook/code.playbook.ts +75 -6
- package/reference/sdlc/code.playbook/code.registry.d.ts +10 -3
- package/reference/sdlc/code.playbook/code.registry.js +10 -3
- package/reference/sdlc/code.playbook/code.registry.ts +23 -5
- package/reference/sdlc/code.playbook/playbook-captain.d.ts +103 -8
- package/reference/sdlc/code.playbook/playbook-captain.js +1871 -75
- package/reference/sdlc/code.playbook/playbook-captain.ts +2801 -102
- package/reference/sdlc/code.playbook/playbook.config.template.yaml +14 -10
- package/reference/sdlc/code.playbook/session-store.d.ts +82 -0
- package/reference/sdlc/code.playbook/session-store.js +113 -0
- package/reference/sdlc/decide.md +24 -16
- package/reference/sdlc/decide.playbook/decide.fsm.d.ts +7 -0
- package/reference/sdlc/decide.playbook/decide.fsm.js +80 -29
- package/reference/sdlc/decide.playbook/decide.fsm.ts +89 -31
- package/reference/sdlc/decide.playbook/decide.gears.md +0 -1
- package/reference/sdlc/decide.playbook/decide.playbook.d.ts +13 -5
- package/reference/sdlc/decide.playbook/decide.playbook.js +1712 -91
- package/reference/sdlc/decide.playbook/decide.playbook.ts +2677 -136
- package/reference/sdlc/decide.playbook/decide.registry.d.ts +7 -3
- package/reference/sdlc/decide.playbook/decide.registry.js +10 -3
- package/reference/sdlc/decide.playbook/decide.registry.ts +20 -5
- package/reference/sdlc/review.md +36 -18
- package/reference/sdlc/review.playbook/review.fsm.d.ts +7 -0
- package/reference/sdlc/review.playbook/review.fsm.js +133 -12
- package/reference/sdlc/review.playbook/review.fsm.ts +140 -12
- package/reference/sdlc/review.playbook/review.playbook.d.ts +5 -2
- package/reference/sdlc/review.playbook/review.playbook.js +65 -2
- package/reference/sdlc/review.playbook/review.playbook.ts +83 -6
- package/reference/sdlc/review.playbook/review.registry.d.ts +10 -3
- package/reference/sdlc/review.playbook/review.registry.js +10 -3
- package/reference/sdlc/review.playbook/review.registry.ts +23 -5
- package/slc/gears2fsm.md +6 -5
- package/slc/link.md +544 -41
- package/src/accepted-outcome.d.ts +18 -0
- package/src/accepted-outcome.js +94 -0
- package/src/accepted-outcome.ts +140 -0
- package/src/runtime.d.ts +164 -3
- package/src/runtime.ts +213 -2
- package/src/xstate-playbook-runtime.d.ts +149 -10
- package/src/xstate-playbook-runtime.js +2569 -270
- package/src/xstate-playbook-runtime.ts +4133 -490
- package/src/xstate-runtime.d.ts +59 -1
- package/src/xstate-runtime.js +866 -7
- package/src/xstate-runtime.ts +1397 -7
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PlaybookState } from './runtime.js';
|
|
2
|
+
export declare const ACCEPTED_OUTCOME_ACTION_TYPE = "playbook.acceptedOutcome";
|
|
3
|
+
export interface AcceptedOutcomeReceipt {
|
|
4
|
+
readonly source: string;
|
|
5
|
+
readonly target: string;
|
|
6
|
+
readonly acceptedOutcome: string;
|
|
7
|
+
}
|
|
8
|
+
interface InspectedAction {
|
|
9
|
+
readonly type: string;
|
|
10
|
+
readonly params: unknown;
|
|
11
|
+
}
|
|
12
|
+
export interface AcceptedOutcomeConsumer {
|
|
13
|
+
capture(action: InspectedAction): void;
|
|
14
|
+
confirm(previousState: PlaybookState | undefined, state: PlaybookState): readonly AcceptedOutcomeReceipt[];
|
|
15
|
+
reset(): void;
|
|
16
|
+
}
|
|
17
|
+
export declare function createAcceptedOutcomeConsumer(isDeclared: (source: string, acceptedOutcome: string) => boolean): AcceptedOutcomeConsumer;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
|
|
3
|
+
export const ACCEPTED_OUTCOME_ACTION_TYPE = 'playbook.acceptedOutcome';
|
|
4
|
+
function exactMarkerParams(value) {
|
|
5
|
+
if (value === null ||
|
|
6
|
+
typeof value !== 'object' ||
|
|
7
|
+
Array.isArray(value) ||
|
|
8
|
+
(Object.getPrototypeOf(value) !== Object.prototype &&
|
|
9
|
+
Object.getPrototypeOf(value) !== null)) {
|
|
10
|
+
throw new TypeError(`${ACCEPTED_OUTCOME_ACTION_TYPE} params must be a plain object`);
|
|
11
|
+
}
|
|
12
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
13
|
+
const keys = Reflect.ownKeys(descriptors);
|
|
14
|
+
const expected = ['acceptedOutcome', 'source', 'target'];
|
|
15
|
+
if (keys.length !== expected.length ||
|
|
16
|
+
keys.some((key) => typeof key !== 'string' || !expected.includes(key))) {
|
|
17
|
+
throw new TypeError(`${ACCEPTED_OUTCOME_ACTION_TYPE} params must contain exactly source, target, and acceptedOutcome`);
|
|
18
|
+
}
|
|
19
|
+
const stringValue = (key) => {
|
|
20
|
+
const descriptor = descriptors[key];
|
|
21
|
+
if (descriptor === undefined ||
|
|
22
|
+
!Object.prototype.hasOwnProperty.call(descriptor, 'value') ||
|
|
23
|
+
descriptor.enumerable !== true ||
|
|
24
|
+
typeof descriptor.value !== 'string' ||
|
|
25
|
+
descriptor.value.trim().length === 0) {
|
|
26
|
+
throw new TypeError(`${ACCEPTED_OUTCOME_ACTION_TYPE} params.${key} must be a nonempty enumerable string data property`);
|
|
27
|
+
}
|
|
28
|
+
return descriptor.value;
|
|
29
|
+
};
|
|
30
|
+
return Object.freeze({
|
|
31
|
+
source: stringValue('source'),
|
|
32
|
+
target: stringValue('target'),
|
|
33
|
+
acceptedOutcome: stringValue('acceptedOutcome'),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export function createAcceptedOutcomeConsumer(isDeclared) {
|
|
37
|
+
let pending = [];
|
|
38
|
+
let invalidBatch = false;
|
|
39
|
+
return Object.freeze({
|
|
40
|
+
capture(action) {
|
|
41
|
+
if (action.type !== ACCEPTED_OUTCOME_ACTION_TYPE) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (invalidBatch)
|
|
45
|
+
return;
|
|
46
|
+
try {
|
|
47
|
+
const marker = exactMarkerParams(action.params);
|
|
48
|
+
if (!isDeclared(marker.source, marker.acceptedOutcome)) {
|
|
49
|
+
throw new TypeError(`${ACCEPTED_OUTCOME_ACTION_TYPE} names undeclared outcome ` +
|
|
50
|
+
`${marker.source}.${marker.acceptedOutcome}`);
|
|
51
|
+
}
|
|
52
|
+
pending.push(marker);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
pending = [];
|
|
56
|
+
invalidBatch = true;
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
confirm(previousState, state) {
|
|
61
|
+
if (invalidBatch) {
|
|
62
|
+
pending = [];
|
|
63
|
+
invalidBatch = false;
|
|
64
|
+
return Object.freeze([]);
|
|
65
|
+
}
|
|
66
|
+
if (pending.length === 0)
|
|
67
|
+
return Object.freeze([]);
|
|
68
|
+
const captured = pending;
|
|
69
|
+
pending = [];
|
|
70
|
+
if (previousState === undefined) {
|
|
71
|
+
throw new TypeError(`${ACCEPTED_OUTCOME_ACTION_TYPE} marker has no prior public root snapshot`);
|
|
72
|
+
}
|
|
73
|
+
const seen = new Set();
|
|
74
|
+
for (const marker of captured) {
|
|
75
|
+
const identity = marker.source;
|
|
76
|
+
if (seen.has(identity)) {
|
|
77
|
+
throw new TypeError(`${ACCEPTED_OUTCOME_ACTION_TYPE} source ${marker.source} was instrumented more than once in one action batch`);
|
|
78
|
+
}
|
|
79
|
+
seen.add(identity);
|
|
80
|
+
if (!previousState.activeStateIds.includes(marker.source)) {
|
|
81
|
+
throw new TypeError(`${ACCEPTED_OUTCOME_ACTION_TYPE} source ${marker.source} was not confirmed by the prior public root snapshot`);
|
|
82
|
+
}
|
|
83
|
+
if (!state.activeStateIds.includes(marker.target)) {
|
|
84
|
+
throw new TypeError(`${ACCEPTED_OUTCOME_ACTION_TYPE} target ${marker.target} was not confirmed by the public root snapshot`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return Object.freeze(captured);
|
|
88
|
+
},
|
|
89
|
+
reset() {
|
|
90
|
+
pending = [];
|
|
91
|
+
invalidBatch = false;
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
|
|
3
|
+
|
|
4
|
+
import type { PlaybookState } from './runtime.js';
|
|
5
|
+
|
|
6
|
+
export const ACCEPTED_OUTCOME_ACTION_TYPE = 'playbook.acceptedOutcome';
|
|
7
|
+
|
|
8
|
+
export interface AcceptedOutcomeReceipt {
|
|
9
|
+
readonly source: string;
|
|
10
|
+
readonly target: string;
|
|
11
|
+
readonly acceptedOutcome: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface InspectedAction {
|
|
15
|
+
readonly type: string;
|
|
16
|
+
readonly params: unknown;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface AcceptedOutcomeConsumer {
|
|
20
|
+
capture(action: InspectedAction): void;
|
|
21
|
+
confirm(
|
|
22
|
+
previousState: PlaybookState | undefined,
|
|
23
|
+
state: PlaybookState,
|
|
24
|
+
): readonly AcceptedOutcomeReceipt[];
|
|
25
|
+
reset(): void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function exactMarkerParams(value: unknown): AcceptedOutcomeReceipt {
|
|
29
|
+
if (
|
|
30
|
+
value === null ||
|
|
31
|
+
typeof value !== 'object' ||
|
|
32
|
+
Array.isArray(value) ||
|
|
33
|
+
(Object.getPrototypeOf(value) !== Object.prototype &&
|
|
34
|
+
Object.getPrototypeOf(value) !== null)
|
|
35
|
+
) {
|
|
36
|
+
throw new TypeError(
|
|
37
|
+
`${ACCEPTED_OUTCOME_ACTION_TYPE} params must be a plain object`,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
41
|
+
const keys = Reflect.ownKeys(descriptors);
|
|
42
|
+
const expected = ['acceptedOutcome', 'source', 'target'];
|
|
43
|
+
if (
|
|
44
|
+
keys.length !== expected.length ||
|
|
45
|
+
keys.some((key) => typeof key !== 'string' || !expected.includes(key))
|
|
46
|
+
) {
|
|
47
|
+
throw new TypeError(
|
|
48
|
+
`${ACCEPTED_OUTCOME_ACTION_TYPE} params must contain exactly source, target, and acceptedOutcome`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
const stringValue = (key: string): string => {
|
|
52
|
+
const descriptor = descriptors[key];
|
|
53
|
+
if (
|
|
54
|
+
descriptor === undefined ||
|
|
55
|
+
!Object.prototype.hasOwnProperty.call(descriptor, 'value') ||
|
|
56
|
+
descriptor.enumerable !== true ||
|
|
57
|
+
typeof descriptor.value !== 'string' ||
|
|
58
|
+
descriptor.value.trim().length === 0
|
|
59
|
+
) {
|
|
60
|
+
throw new TypeError(
|
|
61
|
+
`${ACCEPTED_OUTCOME_ACTION_TYPE} params.${key} must be a nonempty enumerable string data property`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
return descriptor.value;
|
|
65
|
+
};
|
|
66
|
+
return Object.freeze({
|
|
67
|
+
source: stringValue('source'),
|
|
68
|
+
target: stringValue('target'),
|
|
69
|
+
acceptedOutcome: stringValue('acceptedOutcome'),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function createAcceptedOutcomeConsumer(
|
|
74
|
+
isDeclared: (source: string, acceptedOutcome: string) => boolean,
|
|
75
|
+
): AcceptedOutcomeConsumer {
|
|
76
|
+
let pending: AcceptedOutcomeReceipt[] = [];
|
|
77
|
+
let invalidBatch = false;
|
|
78
|
+
return Object.freeze({
|
|
79
|
+
capture(action: InspectedAction) {
|
|
80
|
+
if (action.type !== ACCEPTED_OUTCOME_ACTION_TYPE) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (invalidBatch) return;
|
|
84
|
+
try {
|
|
85
|
+
const marker = exactMarkerParams(action.params);
|
|
86
|
+
if (!isDeclared(marker.source, marker.acceptedOutcome)) {
|
|
87
|
+
throw new TypeError(
|
|
88
|
+
`${ACCEPTED_OUTCOME_ACTION_TYPE} names undeclared outcome ` +
|
|
89
|
+
`${marker.source}.${marker.acceptedOutcome}`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
pending.push(marker);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
pending = [];
|
|
95
|
+
invalidBatch = true;
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
confirm(previousState: PlaybookState | undefined, state: PlaybookState) {
|
|
100
|
+
if (invalidBatch) {
|
|
101
|
+
pending = [];
|
|
102
|
+
invalidBatch = false;
|
|
103
|
+
return Object.freeze([]);
|
|
104
|
+
}
|
|
105
|
+
if (pending.length === 0) return Object.freeze([]);
|
|
106
|
+
const captured = pending;
|
|
107
|
+
pending = [];
|
|
108
|
+
if (previousState === undefined) {
|
|
109
|
+
throw new TypeError(
|
|
110
|
+
`${ACCEPTED_OUTCOME_ACTION_TYPE} marker has no prior public root snapshot`,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
const seen = new Set<string>();
|
|
114
|
+
for (const marker of captured) {
|
|
115
|
+
const identity = marker.source;
|
|
116
|
+
if (seen.has(identity)) {
|
|
117
|
+
throw new TypeError(
|
|
118
|
+
`${ACCEPTED_OUTCOME_ACTION_TYPE} source ${marker.source} was instrumented more than once in one action batch`,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
seen.add(identity);
|
|
122
|
+
if (!previousState.activeStateIds.includes(marker.source)) {
|
|
123
|
+
throw new TypeError(
|
|
124
|
+
`${ACCEPTED_OUTCOME_ACTION_TYPE} source ${marker.source} was not confirmed by the prior public root snapshot`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
if (!state.activeStateIds.includes(marker.target)) {
|
|
128
|
+
throw new TypeError(
|
|
129
|
+
`${ACCEPTED_OUTCOME_ACTION_TYPE} target ${marker.target} was not confirmed by the public root snapshot`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return Object.freeze(captured);
|
|
134
|
+
},
|
|
135
|
+
reset() {
|
|
136
|
+
pending = [];
|
|
137
|
+
invalidBatch = false;
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
}
|
package/src/runtime.d.ts
CHANGED
|
@@ -55,6 +55,7 @@ export interface PlaybookSuspendedCall extends PlaybookPendingCall {
|
|
|
55
55
|
stateId: string;
|
|
56
56
|
text: string;
|
|
57
57
|
turnId?: number;
|
|
58
|
+
effectBoundaryPrefixSequence?: number | null;
|
|
58
59
|
}
|
|
59
60
|
export interface PlaybookCallRequest {
|
|
60
61
|
callId: string;
|
|
@@ -90,6 +91,9 @@ export type PlaybookCallStart = {
|
|
|
90
91
|
export type PlaybookRunResult = {
|
|
91
92
|
outcome: 'quiescent' | 'no-action';
|
|
92
93
|
state: PlaybookState;
|
|
94
|
+
} | {
|
|
95
|
+
outcome: 'unresolved-effect';
|
|
96
|
+
state: PlaybookState;
|
|
93
97
|
} | {
|
|
94
98
|
outcome: 'failed' | 'aborted';
|
|
95
99
|
state: PlaybookState;
|
|
@@ -126,9 +130,14 @@ export interface PlaybookSession {
|
|
|
126
130
|
playerSessions?: PlayerSessionStore;
|
|
127
131
|
ports: PlaybookPorts;
|
|
128
132
|
}
|
|
129
|
-
export
|
|
133
|
+
export interface PlaybookAdoptionContext {
|
|
134
|
+
readonly sourceSessionId: string;
|
|
135
|
+
readonly sourceGenerationId: string;
|
|
136
|
+
readonly targetChildSessionId?: string;
|
|
137
|
+
}
|
|
138
|
+
export type PlaybookTraceType = 'session.started' | 'boss.input.received' | 'judge.call.started' | 'judge.call.finished' | 'player.call.started' | 'player.call.finished' | 'captain.call.started' | 'captain.call.finished' | 'playbook.call.started' | 'playbook.call.finished' | 'apply.started' | 'apply.finished' | 'fsm.transition' | 'outcome.accepted' | 'status.emitted' | 'boss.input.settled' | 'session.disposed';
|
|
130
139
|
export interface PlaybookTraceEvent {
|
|
131
|
-
schemaVersion:
|
|
140
|
+
schemaVersion: 4;
|
|
132
141
|
sessionId: string;
|
|
133
142
|
playbookId: string;
|
|
134
143
|
rootSessionId: string;
|
|
@@ -153,8 +162,127 @@ export interface PlaybookPendingBossQuestion {
|
|
|
153
162
|
question: string;
|
|
154
163
|
sourceItem?: string;
|
|
155
164
|
}
|
|
165
|
+
/** One repository disposition declared by a governed outcome arm (DR-040). */
|
|
166
|
+
export type PlaybookRepositoryDisposition = 'unchanged' | 'one-descendant-commit' | 'deferred';
|
|
167
|
+
/** A detached Git-visible repository observation owned by the effect ledger. */
|
|
168
|
+
export interface PlaybookRepositoryObservation {
|
|
169
|
+
readonly worktree: string;
|
|
170
|
+
readonly gitDir: string;
|
|
171
|
+
readonly head: string;
|
|
172
|
+
readonly projection: Readonly<Record<string, JsonValue>>;
|
|
173
|
+
readonly projectionDigest: string;
|
|
174
|
+
}
|
|
175
|
+
/** The fail-closed classification of one complete physical or logical receipt. */
|
|
176
|
+
export interface PlaybookRepositoryReceipt {
|
|
177
|
+
readonly classification: 'unchanged' | 'one-descendant-commit' | 'multiple-commits' | 'rewritten-or-non-descendant' | 'worktree-only-change' | 'concurrent-or-foreign-change' | 'observation-ambiguous';
|
|
178
|
+
readonly baseline: PlaybookRepositoryObservation;
|
|
179
|
+
readonly after?: PlaybookRepositoryObservation;
|
|
180
|
+
readonly commitOid?: string;
|
|
181
|
+
}
|
|
182
|
+
/** One durably ordered physical governed-player boundary (DR-040). */
|
|
183
|
+
export interface PlaybookEffectBoundary {
|
|
184
|
+
readonly sequence: number;
|
|
185
|
+
readonly boundaryId: string;
|
|
186
|
+
readonly attemptId: string;
|
|
187
|
+
readonly attemptNumber: number;
|
|
188
|
+
readonly playbookId: string;
|
|
189
|
+
readonly runtimeSessionId: string;
|
|
190
|
+
readonly turnId: number;
|
|
191
|
+
readonly callId: string;
|
|
192
|
+
readonly roleId: string;
|
|
193
|
+
readonly sourceStateId: string;
|
|
194
|
+
readonly sourceOutcomeSchema: JsonValue;
|
|
195
|
+
readonly dispositions: readonly PlaybookRepositoryDisposition[];
|
|
196
|
+
readonly canonicalWorktree: {
|
|
197
|
+
readonly worktree: string;
|
|
198
|
+
readonly gitDir: string;
|
|
199
|
+
};
|
|
200
|
+
readonly baseline: PlaybookRepositoryObservation;
|
|
201
|
+
readonly after?: PlaybookRepositoryObservation;
|
|
202
|
+
readonly physicalReceipt?: PlaybookRepositoryReceipt;
|
|
203
|
+
readonly finalText?: string;
|
|
204
|
+
readonly semanticCandidate?: JsonValue;
|
|
205
|
+
readonly initialSemanticCandidate?: JsonValue;
|
|
206
|
+
readonly correctionBudget: {
|
|
207
|
+
readonly limit: 1;
|
|
208
|
+
readonly spent: boolean;
|
|
209
|
+
};
|
|
210
|
+
readonly cohortId?: string;
|
|
211
|
+
readonly logicalOperationId?: string;
|
|
212
|
+
}
|
|
213
|
+
/** One physical boundary before the host assigns attempt and sequence data. */
|
|
214
|
+
export type PlaybookEffectBoundaryStart = Omit<PlaybookEffectBoundary, 'sequence' | 'attemptId' | 'attemptNumber' | 'after' | 'physicalReceipt' | 'finalText' | 'semanticCandidate' | 'initialSemanticCandidate'>;
|
|
215
|
+
/** One deferred logical operation spanning its ordered physical boundaries. */
|
|
216
|
+
export interface PlaybookEffectLogicalOperation {
|
|
217
|
+
readonly sequence: number;
|
|
218
|
+
readonly operationId: string;
|
|
219
|
+
readonly playbookId: string;
|
|
220
|
+
readonly runtimeSessionId: string;
|
|
221
|
+
readonly boundaryIds: readonly string[];
|
|
222
|
+
readonly originalBaseline: PlaybookRepositoryObservation;
|
|
223
|
+
readonly checkpoint?: PlaybookRepositoryObservation;
|
|
224
|
+
readonly pendingQuestion?: PlaybookPendingBossQuestion;
|
|
225
|
+
readonly playerContinuation?: JsonValue;
|
|
226
|
+
readonly checkpointRestorationEligible: boolean;
|
|
227
|
+
readonly logicalReceipt?: PlaybookRepositoryReceipt;
|
|
228
|
+
}
|
|
229
|
+
/** Complete detached mirror of one host-owned reconciliation ledger. */
|
|
230
|
+
export interface PlaybookEffectLedger {
|
|
231
|
+
readonly schemaVersion: 1;
|
|
232
|
+
readonly revision: number;
|
|
233
|
+
readonly boundaries: readonly PlaybookEffectBoundary[];
|
|
234
|
+
readonly logicalOperations: readonly PlaybookEffectLogicalOperation[];
|
|
235
|
+
}
|
|
236
|
+
/** One mutation accepted by the host-owned effect-ledger write-ahead boundary. */
|
|
237
|
+
export type PlaybookEffectLedgerCommand = {
|
|
238
|
+
readonly kind: 'start-boundaries';
|
|
239
|
+
readonly boundaries: readonly [
|
|
240
|
+
PlaybookEffectBoundaryStart,
|
|
241
|
+
...PlaybookEffectBoundaryStart[]
|
|
242
|
+
];
|
|
243
|
+
} | {
|
|
244
|
+
readonly kind: 'replace-boundaries';
|
|
245
|
+
readonly replacements: readonly [
|
|
246
|
+
{
|
|
247
|
+
readonly expected: PlaybookEffectBoundary;
|
|
248
|
+
readonly next: PlaybookEffectBoundary;
|
|
249
|
+
},
|
|
250
|
+
...{
|
|
251
|
+
readonly expected: PlaybookEffectBoundary;
|
|
252
|
+
readonly next: PlaybookEffectBoundary;
|
|
253
|
+
}[]
|
|
254
|
+
];
|
|
255
|
+
} | {
|
|
256
|
+
readonly kind: 'append-logical-operations';
|
|
257
|
+
readonly operations: readonly [
|
|
258
|
+
Omit<PlaybookEffectLogicalOperation, 'sequence'>,
|
|
259
|
+
...Omit<PlaybookEffectLogicalOperation, 'sequence'>[]
|
|
260
|
+
];
|
|
261
|
+
} | {
|
|
262
|
+
readonly kind: 'replace-logical-operations';
|
|
263
|
+
readonly replacements: readonly [
|
|
264
|
+
{
|
|
265
|
+
readonly expected: PlaybookEffectLogicalOperation;
|
|
266
|
+
readonly next: PlaybookEffectLogicalOperation;
|
|
267
|
+
},
|
|
268
|
+
...{
|
|
269
|
+
readonly expected: PlaybookEffectLogicalOperation;
|
|
270
|
+
readonly next: PlaybookEffectLogicalOperation;
|
|
271
|
+
}[]
|
|
272
|
+
];
|
|
273
|
+
};
|
|
274
|
+
/** A nonempty command batch persisted as one ledger revision. */
|
|
275
|
+
export type PlaybookEffectLedgerCommandBatch = readonly [
|
|
276
|
+
PlaybookEffectLedgerCommand,
|
|
277
|
+
...PlaybookEffectLedgerCommand[]
|
|
278
|
+
];
|
|
279
|
+
/** Live current-host seam for atomic effect-ledger observation and mutation. */
|
|
280
|
+
export interface PlaybookEffectLedgerCapability {
|
|
281
|
+
snapshot(): PlaybookEffectLedger;
|
|
282
|
+
writeAhead(commands: PlaybookEffectLedgerCommandBatch): Promise<PlaybookEffectLedger>;
|
|
283
|
+
}
|
|
156
284
|
export interface PlaybookRuntimeSnapshot {
|
|
157
|
-
schemaVersion:
|
|
285
|
+
schemaVersion: 4;
|
|
158
286
|
playbookId: string;
|
|
159
287
|
machine: JsonValue;
|
|
160
288
|
roleResumeTokens: {
|
|
@@ -170,6 +298,21 @@ export interface PlaybookRuntimeSnapshot {
|
|
|
170
298
|
};
|
|
171
299
|
state: PlaybookState;
|
|
172
300
|
pendingBossQuestions: readonly PlaybookPendingBossQuestion[];
|
|
301
|
+
effectLedger: PlaybookEffectLedger;
|
|
302
|
+
/** Original runtime identity retained across schema-3 adoption lineage. */
|
|
303
|
+
retainedEffectSourceSessionId?: string;
|
|
304
|
+
/**
|
|
305
|
+
* Unsafe retained-adoption checkpoint. The marker remains durable until
|
|
306
|
+
* authoritative reconciliation proves its complete suffix replay-safe.
|
|
307
|
+
*/
|
|
308
|
+
retainedEffectReconciliation?: {
|
|
309
|
+
readonly sourceSessionId: string;
|
|
310
|
+
readonly checkpoint: PlaybookEffectLedger;
|
|
311
|
+
};
|
|
312
|
+
failedEffectAttempt?: {
|
|
313
|
+
readonly boundaryPrefix: number;
|
|
314
|
+
readonly attemptId: string | null;
|
|
315
|
+
};
|
|
173
316
|
suspendedCall?: PlaybookSuspendedCall;
|
|
174
317
|
}
|
|
175
318
|
export interface PlaybookControlAction {
|
|
@@ -194,11 +337,29 @@ export type PlaybookControlReceipt = {
|
|
|
194
337
|
disposition: 'failed';
|
|
195
338
|
error: NormalizedError;
|
|
196
339
|
};
|
|
340
|
+
export interface PlaybookRetainedGenerationMetadata {
|
|
341
|
+
readonly unfinishedFinalStateIds: readonly string[];
|
|
342
|
+
}
|
|
197
343
|
export interface PlaybookRuntime {
|
|
198
344
|
init(session: PlaybookSession): Promise<void>;
|
|
199
345
|
exportSnapshot?(): PlaybookRuntimeSnapshot | undefined;
|
|
200
346
|
restore?(session: PlaybookSession, snapshot: PlaybookRuntimeSnapshot): Promise<void>;
|
|
347
|
+
adopt?(session: PlaybookSession, snapshot: PlaybookRuntimeSnapshot, context: PlaybookAdoptionContext): Promise<void>;
|
|
348
|
+
readonly retainedGenerationMetadata?: PlaybookRetainedGenerationMetadata;
|
|
201
349
|
describe?(): PlaybookControlView;
|
|
350
|
+
/**
|
|
351
|
+
* Host-only identities of the durable envelopes that still require
|
|
352
|
+
* unresolved-effect settlement. The host owns their bounded projection
|
|
353
|
+
* from its authoritative effect ledger; no repository evidence enters a
|
|
354
|
+
* runtime-owned run result.
|
|
355
|
+
*/
|
|
356
|
+
unresolvedEffectEnvelopes?(): readonly ({
|
|
357
|
+
readonly kind: 'boundary';
|
|
358
|
+
readonly boundaryId: string;
|
|
359
|
+
} | {
|
|
360
|
+
readonly kind: 'logical-operation';
|
|
361
|
+
readonly operationId: string;
|
|
362
|
+
})[];
|
|
202
363
|
apply?(input: {
|
|
203
364
|
actionId: string;
|
|
204
365
|
key: string;
|