@sublang/playbook 3.0.0 → 4.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 +28 -5
- package/docs/cli.md +82 -1
- package/package.json +6 -4
- package/reference/sdlc/captain.playbook/captain.playbook.js +21 -13
- package/reference/sdlc/captain.playbook/captain.playbook.ts +20 -12
- package/reference/sdlc/code.playbook/bin/adapter-sdk.js +247 -0
- package/reference/sdlc/code.playbook/bin/playbook.js +55 -9
- package/reference/sdlc/code.playbook/bin/provision.js +228 -0
- package/reference/sdlc/code.playbook/bin/run.js +146 -1
- package/reference/sdlc/code.playbook/playbook-captain.js +23 -2
- package/reference/sdlc/code.playbook/playbook-captain.ts +29 -3
- package/reference/sdlc/code.playbook/playbook.config.template.yaml +7 -0
- package/slc/link.md +14 -0
- package/src/xstate-playbook-runtime.d.ts +27 -0
- package/src/xstate-playbook-runtime.js +52 -2
- package/src/xstate-playbook-runtime.ts +87 -7
|
@@ -42,6 +42,48 @@ function isFsmResultFailure(error) {
|
|
|
42
42
|
fsmResultFailures.has(error));
|
|
43
43
|
}
|
|
44
44
|
// ---------------------------------------------------------------------------
|
|
45
|
+
// DR-022: the engine's compatibility self-report. A linked thin module
|
|
46
|
+
// records the values current at link time in `spec.compat`; the factory
|
|
47
|
+
// checks that declaration against this very module — the engine instance
|
|
48
|
+
// that will interpret the FSM, so the check can never consult a different
|
|
49
|
+
// engine copy than the one executing — and fails construction on a mismatch
|
|
50
|
+
// instead of misbehaving deep in a session. Raising RUNTIME_ABI or removing
|
|
51
|
+
// a member of SUPPORTED_ARTIFACT_SCHEMAS is a breaking change (RELEASE-15).
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
/** The runtime ABI this engine implements (DR-022). */
|
|
54
|
+
export const RUNTIME_ABI = 1;
|
|
55
|
+
/** The linked-artifact schema versions this engine accepts (DR-022). */
|
|
56
|
+
export const SUPPORTED_ARTIFACT_SCHEMAS = Object.freeze([
|
|
57
|
+
1,
|
|
58
|
+
]);
|
|
59
|
+
// PBRT-50: validate a declaration against the loaded engine, schema first,
|
|
60
|
+
// so one clear diagnostic covers a fully skewed artifact. Absent means a
|
|
61
|
+
// legacy artifact emitted before the DR-022 contract; those must keep
|
|
62
|
+
// loading unchanged (DR-019 §4), so there is nothing to check.
|
|
63
|
+
function assertRuntimeCompat(compat, label) {
|
|
64
|
+
if (compat === undefined)
|
|
65
|
+
return;
|
|
66
|
+
if (compat === null || typeof compat !== 'object') {
|
|
67
|
+
throw new TypeError(`${label} spec.compat must be an object`);
|
|
68
|
+
}
|
|
69
|
+
const { artifactSchema, runtimeAbi } = compat;
|
|
70
|
+
if (!Number.isSafeInteger(artifactSchema)) {
|
|
71
|
+
throw new TypeError(`${label} spec.compat.artifactSchema must be an integer`);
|
|
72
|
+
}
|
|
73
|
+
if (!Number.isSafeInteger(runtimeAbi)) {
|
|
74
|
+
throw new TypeError(`${label} spec.compat.runtimeAbi must be an integer`);
|
|
75
|
+
}
|
|
76
|
+
if (!SUPPORTED_ARTIFACT_SCHEMAS.includes(artifactSchema)) {
|
|
77
|
+
throw new TypeError(`${label} artifact declares schema ${artifactSchema}, but this ` +
|
|
78
|
+
`@sublang/playbook/xstate-runtime engine supports ` +
|
|
79
|
+
`[${SUPPORTED_ARTIFACT_SCHEMAS.join(', ')}]`);
|
|
80
|
+
}
|
|
81
|
+
if (runtimeAbi !== RUNTIME_ABI) {
|
|
82
|
+
throw new TypeError(`${label} artifact declares runtime ABI ${runtimeAbi}, but this ` +
|
|
83
|
+
`@sublang/playbook/xstate-runtime engine implements ${RUNTIME_ABI}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
45
87
|
// Tolerant judge-JSON recovery (slc/link.md §Boss-event mapping).
|
|
46
88
|
// ---------------------------------------------------------------------------
|
|
47
89
|
function isPlainObject(value) {
|
|
@@ -412,7 +454,12 @@ export function createPlayerBridge(spec, ports, getActiveSignal, boundary, onCon
|
|
|
412
454
|
// `response` and rejects a judge reply that supplies either presentation
|
|
413
455
|
// field as an undeclared extra key.
|
|
414
456
|
// ---------------------------------------------------------------------------
|
|
415
|
-
|
|
457
|
+
/**
|
|
458
|
+
* Default direct-Captain adjudicator prompt (DR-025). The single statement of
|
|
459
|
+
* the `{ guard, …structuralPayloadFields }` reply contract, shared with the
|
|
460
|
+
* compiled default Captain artifact so the wording cannot drift.
|
|
461
|
+
*/
|
|
462
|
+
export function defaultBuildCaptainJudgePrompt(input, finalText) {
|
|
416
463
|
const lines = [];
|
|
417
464
|
lines.push('Adjudicate the direct Captain output for this FSM state.');
|
|
418
465
|
lines.push(`State id: ${input.stateId}`);
|
|
@@ -857,6 +904,9 @@ function makeDefaultClassifyBossText(machine, entryEvent, bossEvents) {
|
|
|
857
904
|
*/
|
|
858
905
|
export function createXStatePlaybookRuntime(machine, spec) {
|
|
859
906
|
const label = spec.label ?? 'playbook';
|
|
907
|
+
// DR-022 / PBRT-50: reject an incompatible artifact declaration before any
|
|
908
|
+
// machine interpretation, against this loaded engine's own self-report.
|
|
909
|
+
assertRuntimeCompat(spec.compat, label);
|
|
860
910
|
const declaredActors = collectInvokeSources(machine);
|
|
861
911
|
const resumableStateIds = spec.resumableStateIds ?? resumableStateIdsFromMachine(machine);
|
|
862
912
|
const resolvePlayerIdSpec = spec.resolvePlayerId;
|
|
@@ -1337,7 +1387,7 @@ export function createXStatePlaybookRuntime(machine, spec) {
|
|
|
1337
1387
|
if (result.status !== 'ok' || !result.finalText) {
|
|
1338
1388
|
throw new Error('captainActor: boundary returned an unvalidated Captain result');
|
|
1339
1389
|
}
|
|
1340
|
-
const judgePrompt =
|
|
1390
|
+
const judgePrompt = defaultBuildCaptainJudgePrompt(input, result.finalText);
|
|
1341
1391
|
const raw = await boundary.callJudge('captain-output-adjudication', input.stateId, judgePrompt, active);
|
|
1342
1392
|
const output = adjudicateCaptainOutput(extractFields, input, result.finalText, raw);
|
|
1343
1393
|
validateBossReplyOutput(input, output, resumableStateIds);
|
|
@@ -177,18 +177,86 @@ function isFsmResultFailure(error: unknown): boolean {
|
|
|
177
177
|
);
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// DR-022: the engine's compatibility self-report. A linked thin module
|
|
182
|
+
// records the values current at link time in `spec.compat`; the factory
|
|
183
|
+
// checks that declaration against this very module — the engine instance
|
|
184
|
+
// that will interpret the FSM, so the check can never consult a different
|
|
185
|
+
// engine copy than the one executing — and fails construction on a mismatch
|
|
186
|
+
// instead of misbehaving deep in a session. Raising RUNTIME_ABI or removing
|
|
187
|
+
// a member of SUPPORTED_ARTIFACT_SCHEMAS is a breaking change (RELEASE-15).
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
/** The runtime ABI this engine implements (DR-022). */
|
|
191
|
+
export const RUNTIME_ABI = 1;
|
|
192
|
+
|
|
193
|
+
/** The linked-artifact schema versions this engine accepts (DR-022). */
|
|
194
|
+
export const SUPPORTED_ARTIFACT_SCHEMAS: readonly number[] = Object.freeze([
|
|
195
|
+
1,
|
|
196
|
+
]);
|
|
197
|
+
|
|
198
|
+
/** A linked artifact's declared link-time compatibility values (DR-022). */
|
|
199
|
+
export interface XStatePlaybookRuntimeCompat {
|
|
200
|
+
/** The artifact schema version the linker emitted. */
|
|
201
|
+
artifactSchema: number;
|
|
202
|
+
/** The engine ABI the artifact was linked against. */
|
|
203
|
+
runtimeAbi: number;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// PBRT-50: validate a declaration against the loaded engine, schema first,
|
|
207
|
+
// so one clear diagnostic covers a fully skewed artifact. Absent means a
|
|
208
|
+
// legacy artifact emitted before the DR-022 contract; those must keep
|
|
209
|
+
// loading unchanged (DR-019 §4), so there is nothing to check.
|
|
210
|
+
function assertRuntimeCompat(
|
|
211
|
+
compat: XStatePlaybookRuntimeCompat | undefined,
|
|
212
|
+
label: string,
|
|
213
|
+
): void {
|
|
214
|
+
if (compat === undefined) return;
|
|
215
|
+
if (compat === null || typeof compat !== 'object') {
|
|
216
|
+
throw new TypeError(`${label} spec.compat must be an object`);
|
|
217
|
+
}
|
|
218
|
+
const { artifactSchema, runtimeAbi } = compat;
|
|
219
|
+
if (!Number.isSafeInteger(artifactSchema)) {
|
|
220
|
+
throw new TypeError(
|
|
221
|
+
`${label} spec.compat.artifactSchema must be an integer`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
if (!Number.isSafeInteger(runtimeAbi)) {
|
|
225
|
+
throw new TypeError(`${label} spec.compat.runtimeAbi must be an integer`);
|
|
226
|
+
}
|
|
227
|
+
if (!SUPPORTED_ARTIFACT_SCHEMAS.includes(artifactSchema)) {
|
|
228
|
+
throw new TypeError(
|
|
229
|
+
`${label} artifact declares schema ${artifactSchema}, but this ` +
|
|
230
|
+
`@sublang/playbook/xstate-runtime engine supports ` +
|
|
231
|
+
`[${SUPPORTED_ARTIFACT_SCHEMAS.join(', ')}]`,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
if (runtimeAbi !== RUNTIME_ABI) {
|
|
235
|
+
throw new TypeError(
|
|
236
|
+
`${label} artifact declares runtime ABI ${runtimeAbi}, but this ` +
|
|
237
|
+
`@sublang/playbook/xstate-runtime engine implements ${RUNTIME_ABI}`,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
180
242
|
// ---------------------------------------------------------------------------
|
|
181
243
|
// The per-workflow spec. Every strategy member has a generic default derived
|
|
182
244
|
// from the FSM artifact's own data, so a linker-emitted thin module normally
|
|
183
|
-
// supplies only `snapshotOptions` and, where applicable, `
|
|
184
|
-
// Boss-event field metadata, placeholder exceptions, and
|
|
185
|
-
// fields. Hand-maintained artifacts may override any member
|
|
186
|
-
// existing observable behavior exactly.
|
|
245
|
+
// supplies only `snapshotOptions` and, where applicable, `compat`,
|
|
246
|
+
// `entryEvent`, erased Boss-event field metadata, placeholder exceptions, and
|
|
247
|
+
// transition-event fields. Hand-maintained artifacts may override any member
|
|
248
|
+
// to preserve their existing observable behavior exactly.
|
|
187
249
|
// ---------------------------------------------------------------------------
|
|
188
250
|
|
|
189
251
|
export interface XStatePlaybookRuntimeSpec<TOptions> {
|
|
190
252
|
/** Diagnostic label used in internal invariant errors. Default 'playbook'. */
|
|
191
253
|
label?: string;
|
|
254
|
+
/**
|
|
255
|
+
* Link-time compatibility declaration checked at construction against the
|
|
256
|
+
* loaded engine's self-report (DR-022). Absent: a legacy artifact emitted
|
|
257
|
+
* before the contract — constructed with no compatibility check.
|
|
258
|
+
*/
|
|
259
|
+
compat?: XStatePlaybookRuntimeCompat;
|
|
192
260
|
/** Validate and JSON-snapshot the caller's per-run options. */
|
|
193
261
|
snapshotOptions: (value: unknown) => TOptions;
|
|
194
262
|
/** Derive the FSM machine input from validated options. Default: identity. */
|
|
@@ -731,8 +799,17 @@ export function createPlayerBridge(
|
|
|
731
799
|
// field as an undeclared extra key.
|
|
732
800
|
// ---------------------------------------------------------------------------
|
|
733
801
|
|
|
734
|
-
|
|
735
|
-
|
|
802
|
+
/**
|
|
803
|
+
* Default direct-Captain adjudicator prompt (DR-025). The single statement of
|
|
804
|
+
* the `{ guard, …structuralPayloadFields }` reply contract, shared with the
|
|
805
|
+
* compiled default Captain artifact so the wording cannot drift.
|
|
806
|
+
*/
|
|
807
|
+
export function defaultBuildCaptainJudgePrompt(
|
|
808
|
+
input: {
|
|
809
|
+
readonly stateId: string;
|
|
810
|
+
readonly sourceItem: string;
|
|
811
|
+
readonly result: Readonly<Record<string, string>>;
|
|
812
|
+
},
|
|
736
813
|
finalText: string,
|
|
737
814
|
): string {
|
|
738
815
|
const lines: string[] = [];
|
|
@@ -1337,6 +1414,9 @@ export function createXStatePlaybookRuntime<TOptions>(
|
|
|
1337
1414
|
spec: XStatePlaybookRuntimeSpec<TOptions>,
|
|
1338
1415
|
): PlaybookRuntimeFactory<TOptions> {
|
|
1339
1416
|
const label = spec.label ?? 'playbook';
|
|
1417
|
+
// DR-022 / PBRT-50: reject an incompatible artifact declaration before any
|
|
1418
|
+
// machine interpretation, against this loaded engine's own self-report.
|
|
1419
|
+
assertRuntimeCompat(spec.compat, label);
|
|
1340
1420
|
const declaredActors = collectInvokeSources(machine);
|
|
1341
1421
|
const resumableStateIds =
|
|
1342
1422
|
spec.resumableStateIds ?? resumableStateIdsFromMachine(machine);
|
|
@@ -1971,7 +2051,7 @@ export function createXStatePlaybookRuntime<TOptions>(
|
|
|
1971
2051
|
'captainActor: boundary returned an unvalidated Captain result',
|
|
1972
2052
|
);
|
|
1973
2053
|
}
|
|
1974
|
-
const judgePrompt =
|
|
2054
|
+
const judgePrompt = defaultBuildCaptainJudgePrompt(
|
|
1975
2055
|
input,
|
|
1976
2056
|
result.finalText,
|
|
1977
2057
|
);
|