@sublang/playbook 13.3.0 → 14.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 (32) hide show
  1. package/README.md +5 -5
  2. package/docs/configuration.md +10 -2
  3. package/docs/embedding.md +20 -1
  4. package/package.json +6 -1
  5. package/reference/sdlc/code.playbook/bin/launch-config.js +88 -5
  6. package/reference/sdlc/code.playbook/bin/playbook.js +4 -0
  7. package/reference/sdlc/code.playbook/bin/repository-effects.js +11 -3
  8. package/reference/sdlc/code.playbook/bin/run.js +4 -0
  9. package/reference/sdlc/code.playbook/bin/session-store.js +2 -2
  10. package/reference/sdlc/code.playbook/playbook-captain.js +17 -4
  11. package/reference/sdlc/code.playbook/playbook-captain.ts +19 -4
  12. package/reference/sdlc/dev.playbook/dev.playbook.d.ts +3 -10
  13. package/reference/sdlc/dev.playbook/dev.playbook.js +5 -5
  14. package/reference/sdlc/dev.playbook/dev.playbook.ts +7 -7
  15. package/reference/sdlc/pr.md +17 -4
  16. package/reference/sdlc/pr.playbook/pr.fsm.d.ts +17 -3
  17. package/reference/sdlc/pr.playbook/pr.fsm.js +49 -18
  18. package/reference/sdlc/pr.playbook/pr.fsm.ts +63 -20
  19. package/reference/sdlc/pr.playbook/pr.gears.md +20 -7
  20. package/reference/sdlc/pr.playbook/pr.playbook.js +2 -1
  21. package/reference/sdlc/pr.playbook/pr.playbook.ts +2 -1
  22. package/slc/experiments/fsm-scaffold-guidance.md +31 -0
  23. package/slc/gears2fsm.md +145 -58
  24. package/slc/link.md +158 -7
  25. package/slc/materialize-link.mjs +460 -0
  26. package/slc/optimize.md +46 -6
  27. package/slc/scaffold-fsm.mjs +225 -0
  28. package/slc/slc.pin-inputs.json +13 -0
  29. package/slc/text2gears.md +38 -3
  30. package/slc/workflow-contracts.json +371 -0
  31. package/src/xstate-playbook-runtime.js +35 -1
  32. package/src/xstate-playbook-runtime.ts +54 -1
@@ -0,0 +1,371 @@
1
+ {
2
+ "schema": "sublang.playbook.workflow-contracts.v1",
3
+ "package": "@sublang/playbook",
4
+ "artifactSchema": 3,
5
+ "runtimeAbi": 1,
6
+ "description": "Public output interfaces for the packaged builtin workflows. The selected pipeline declares literalTargetBindings as its default nested-target namespace; explicit Source or compiler-dependency bindings override defaults and require their own interfaces. Hosts must honor the compiled bindings. Child output fields retain child-owned authority, while the shared envelope and terminal kind govern transport and authored failure; a local basename alone establishes no binding.",
7
+ "$defs": {
8
+ "compactError": {
9
+ "type": "object",
10
+ "properties": {
11
+ "name": {
12
+ "type": "string"
13
+ },
14
+ "message": {
15
+ "type": "string"
16
+ }
17
+ },
18
+ "required": ["name", "message"],
19
+ "additionalProperties": false
20
+ },
21
+ "json": {
22
+ "anyOf": [
23
+ {
24
+ "type": "null"
25
+ },
26
+ {
27
+ "type": "boolean"
28
+ },
29
+ {
30
+ "type": "number"
31
+ },
32
+ {
33
+ "type": "string"
34
+ },
35
+ {
36
+ "type": "array",
37
+ "items": {
38
+ "$ref": "#/$defs/json"
39
+ }
40
+ },
41
+ {
42
+ "type": "object",
43
+ "additionalProperties": {
44
+ "$ref": "#/$defs/json"
45
+ }
46
+ }
47
+ ]
48
+ },
49
+ "completedCodeResult": {
50
+ "anyOf": [
51
+ {
52
+ "type": "object",
53
+ "properties": {
54
+ "playbookId": {
55
+ "const": "code"
56
+ },
57
+ "status": {
58
+ "const": "ok"
59
+ },
60
+ "output": {
61
+ "$ref": "#/$defs/json"
62
+ }
63
+ },
64
+ "required": ["playbookId", "status"],
65
+ "additionalProperties": false
66
+ },
67
+ {
68
+ "type": "object",
69
+ "properties": {
70
+ "playbookId": {
71
+ "const": "code"
72
+ },
73
+ "status": {
74
+ "enum": ["aborted", "error"]
75
+ },
76
+ "error": {
77
+ "$ref": "#/$defs/compactError"
78
+ }
79
+ },
80
+ "required": ["playbookId", "status", "error"],
81
+ "additionalProperties": false
82
+ }
83
+ ]
84
+ }
85
+ },
86
+ "workflows": {
87
+ "review": {
88
+ "callInput": "text",
89
+ "output": {
90
+ "type": "object",
91
+ "properties": {
92
+ "noUnsettledFindings": {
93
+ "const": true
94
+ },
95
+ "evaluatedRevision": {
96
+ "type": "string",
97
+ "description": "Exact receipt-observed repository revision evaluated by the final clean review round; it can include REVIEW-owned fixes after the caller's original commit."
98
+ }
99
+ },
100
+ "required": ["noUnsettledFindings", "evaluatedRevision"],
101
+ "additionalProperties": false
102
+ }
103
+ },
104
+ "decide": {
105
+ "callInput": "text",
106
+ "output": {
107
+ "anyOf": [
108
+ {
109
+ "type": "object",
110
+ "properties": {
111
+ "decideCommit": {
112
+ "type": "string",
113
+ "description": "Exact DECIDE-owned commit."
114
+ },
115
+ "evaluatedRevision": {
116
+ "type": "string",
117
+ "description": "Exact repository revision evaluated by the final passing review."
118
+ },
119
+ "noUnsettledFindings": {
120
+ "const": true
121
+ }
122
+ },
123
+ "required": [
124
+ "decideCommit",
125
+ "evaluatedRevision",
126
+ "noUnsettledFindings"
127
+ ],
128
+ "additionalProperties": false
129
+ },
130
+ {
131
+ "type": "object",
132
+ "properties": {
133
+ "lastDecideCommit": {
134
+ "type": "string",
135
+ "description": "Exact last DECIDE-owned commit."
136
+ },
137
+ "noUnsettledFindings": {
138
+ "const": false
139
+ },
140
+ "reviewStatus": {
141
+ "enum": ["aborted", "error"]
142
+ },
143
+ "error": {
144
+ "$ref": "#/$defs/compactError"
145
+ }
146
+ },
147
+ "required": [
148
+ "lastDecideCommit",
149
+ "noUnsettledFindings",
150
+ "reviewStatus"
151
+ ],
152
+ "additionalProperties": false
153
+ }
154
+ ]
155
+ }
156
+ },
157
+ "code": {
158
+ "callInput": "text",
159
+ "output": {
160
+ "anyOf": [
161
+ {
162
+ "type": "object",
163
+ "properties": {
164
+ "status": {
165
+ "const": "complete"
166
+ },
167
+ "lastCodeCommit": {
168
+ "type": "string",
169
+ "description": "Exact last CODE-owned commit; excludes REVIEW-owned fix commits."
170
+ },
171
+ "finalEvaluatedRevision": {
172
+ "type": "string",
173
+ "description": "Exact repository revision evaluated by the final passing review; it may differ from lastCodeCommit."
174
+ },
175
+ "allReviewsPassed": {
176
+ "const": true
177
+ }
178
+ },
179
+ "required": [
180
+ "status",
181
+ "lastCodeCommit",
182
+ "finalEvaluatedRevision",
183
+ "allReviewsPassed"
184
+ ],
185
+ "additionalProperties": false
186
+ },
187
+ {
188
+ "type": "object",
189
+ "properties": {
190
+ "status": {
191
+ "const": "review-failed"
192
+ },
193
+ "lastCodeCommit": {
194
+ "type": "string",
195
+ "description": "Exact last CODE-owned commit."
196
+ },
197
+ "error": {
198
+ "$ref": "#/$defs/compactError"
199
+ }
200
+ },
201
+ "required": ["status", "lastCodeCommit", "error"],
202
+ "additionalProperties": false
203
+ }
204
+ ]
205
+ }
206
+ },
207
+ "branch": {
208
+ "callInput": "text",
209
+ "output": {
210
+ "anyOf": [
211
+ {
212
+ "type": "object",
213
+ "properties": {
214
+ "status": {
215
+ "const": "branched"
216
+ },
217
+ "branch": {
218
+ "type": "string",
219
+ "description": "Exact new branch name."
220
+ },
221
+ "baseRevision": {
222
+ "type": "string",
223
+ "description": "Exact receipt-observed repository revision the branch was created from."
224
+ },
225
+ "issueSummary": {
226
+ "type": "string",
227
+ "description": "Concise issue-and-comments or request summary."
228
+ }
229
+ },
230
+ "required": ["status", "branch", "baseRevision", "issueSummary"],
231
+ "additionalProperties": false
232
+ },
233
+ {
234
+ "type": "object",
235
+ "properties": {
236
+ "status": {
237
+ "const": "refused"
238
+ },
239
+ "coderOutput": {
240
+ "type": "string",
241
+ "description": "Complete refusal report."
242
+ }
243
+ },
244
+ "required": ["status", "coderOutput"],
245
+ "additionalProperties": false
246
+ }
247
+ ]
248
+ }
249
+ },
250
+ "pr": {
251
+ "callInput": "text",
252
+ "output": {
253
+ "anyOf": [
254
+ {
255
+ "type": "object",
256
+ "properties": {
257
+ "status": {
258
+ "const": "merged"
259
+ },
260
+ "pullRequest": {
261
+ "type": "string",
262
+ "description": "Exact pull request number as reported."
263
+ },
264
+ "pullRequestUrl": {
265
+ "type": "string",
266
+ "description": "Exact pull request URL as reported."
267
+ },
268
+ "localDefaultUpdated": {
269
+ "type": "boolean"
270
+ }
271
+ },
272
+ "required": [
273
+ "status",
274
+ "pullRequest",
275
+ "pullRequestUrl",
276
+ "localDefaultUpdated"
277
+ ],
278
+ "additionalProperties": false
279
+ },
280
+ {
281
+ "type": "object",
282
+ "properties": {
283
+ "status": {
284
+ "const": "not-merged"
285
+ },
286
+ "reason": {
287
+ "const": "not-published"
288
+ },
289
+ "coderOutput": {
290
+ "type": "string",
291
+ "description": "Complete report explaining why publication did not occur."
292
+ }
293
+ },
294
+ "required": ["status", "reason", "coderOutput"],
295
+ "additionalProperties": false
296
+ },
297
+ {
298
+ "type": "object",
299
+ "properties": {
300
+ "status": {
301
+ "const": "not-merged"
302
+ },
303
+ "reason": {
304
+ "const": "fix-failed"
305
+ },
306
+ "pullRequest": {
307
+ "type": "string"
308
+ },
309
+ "pullRequestUrl": {
310
+ "type": "string"
311
+ },
312
+ "childResult": {
313
+ "$ref": "#/$defs/completedCodeResult"
314
+ }
315
+ },
316
+ "required": [
317
+ "status",
318
+ "reason",
319
+ "pullRequest",
320
+ "pullRequestUrl",
321
+ "childResult"
322
+ ],
323
+ "additionalProperties": false
324
+ },
325
+ {
326
+ "type": "object",
327
+ "properties": {
328
+ "status": {
329
+ "const": "not-merged"
330
+ },
331
+ "reason": {
332
+ "enum": ["fix-not-published", "checks-failed"]
333
+ },
334
+ "pullRequest": {
335
+ "type": "string"
336
+ },
337
+ "pullRequestUrl": {
338
+ "type": "string"
339
+ }
340
+ },
341
+ "required": ["status", "reason", "pullRequest", "pullRequestUrl"],
342
+ "additionalProperties": false
343
+ },
344
+ {
345
+ "type": "object",
346
+ "properties": {
347
+ "status": {
348
+ "const": "merge-unconfirmed"
349
+ },
350
+ "pullRequest": {
351
+ "type": "string"
352
+ },
353
+ "pullRequestUrl": {
354
+ "type": "string"
355
+ }
356
+ },
357
+ "required": ["status", "pullRequest", "pullRequestUrl"],
358
+ "additionalProperties": false
359
+ }
360
+ ]
361
+ }
362
+ }
363
+ },
364
+ "literalTargetBindings": {
365
+ "review": "review",
366
+ "decide": "decide",
367
+ "code": "code",
368
+ "branch": "branch",
369
+ "pr": "pr"
370
+ }
371
+ }
@@ -2455,6 +2455,39 @@ export function createXStatePlaybookRuntime(machine, spec) {
2455
2455
  throw new Error(`createPlaybookRuntime.${method}: deferred settlement recovery is required`, { cause: deferredSettlementClosure });
2456
2456
  }
2457
2457
  }
2458
+ function pendingHasExactUnchangedOrigin(pending) {
2459
+ // The outcome menu is not the selected outcome: a source-authored
2460
+ // unchanged question may share its state with needsBossReply: deferred.
2461
+ // An open operation nevertheless always retains its checkpoint and
2462
+ // cumulative receipt authority, even if a later boundary looks alike.
2463
+ if (runtimeLogicalOperations().some((operation) => operation.logicalReceipt === undefined)) {
2464
+ return false;
2465
+ }
2466
+ const latest = effectLedgerMirror.boundaries
2467
+ .filter(runtimeBoundaryIsOwned)
2468
+ .at(-1);
2469
+ if (latest === undefined ||
2470
+ latest.sourceStateId !== pending.resumeStateId ||
2471
+ pending.asker.kind !== 'role' ||
2472
+ latest.roleId !== pending.asker.roleId ||
2473
+ latest.logicalOperationId !== undefined ||
2474
+ latest.physicalReceipt?.classification !== 'unchanged') {
2475
+ return false;
2476
+ }
2477
+ // Reuse the persisted authority/receipt check rather than infer an arm
2478
+ // from question prose or search older evidence for a convenient match.
2479
+ const persisted = persistedBoundaryReconciliation(latest, effectLedgerMirror);
2480
+ if (persisted === undefined ||
2481
+ persisted.historicalDeferred ||
2482
+ persisted.reconciliation.status !== 'resolved') {
2483
+ return false;
2484
+ }
2485
+ const output = persisted.reconciliation.output;
2486
+ const declaration = outcomeAuthority.governedPlayerStates[latest.sourceStateId]?.[output.guard];
2487
+ return (declaration?.repositoryDisposition === 'unchanged' &&
2488
+ typeof output.question === 'string' &&
2489
+ output.question === pending.question);
2490
+ }
2458
2491
  function currentBoundDeferredOperation(pending) {
2459
2492
  const projected = {
2460
2493
  questionId: pending.questionId,
@@ -5779,7 +5812,8 @@ export function createXStatePlaybookRuntime(machine, spec) {
5779
5812
  deferredPending = pendingBossQuestionForState(normalizePlaybookSnapshot(snapshot), snapshotContext);
5780
5813
  pendingRequiresDeferredBinding =
5781
5814
  deferredPending !== undefined &&
5782
- outcomeAuthority?.governedPlayerStates[deferredPending.resumeStateId]?.needsBossReply?.repositoryDisposition === 'deferred';
5815
+ outcomeAuthority?.governedPlayerStates[deferredPending.resumeStateId]?.needsBossReply?.repositoryDisposition === 'deferred' &&
5816
+ !pendingHasExactUnchangedOrigin(deferredPending);
5783
5817
  deferredOperation =
5784
5818
  !pendingRequiresDeferredBinding
5785
5819
  ? undefined
@@ -3987,6 +3987,58 @@ export function createXStatePlaybookRuntime<
3987
3987
  }
3988
3988
  }
3989
3989
 
3990
+ function pendingHasExactUnchangedOrigin(
3991
+ pending: PlaybookPendingBossQuestionContext,
3992
+ ): boolean {
3993
+ // The outcome menu is not the selected outcome: a source-authored
3994
+ // unchanged question may share its state with needsBossReply: deferred.
3995
+ // An open operation nevertheless always retains its checkpoint and
3996
+ // cumulative receipt authority, even if a later boundary looks alike.
3997
+ if (
3998
+ runtimeLogicalOperations().some(
3999
+ (operation) => operation.logicalReceipt === undefined,
4000
+ )
4001
+ ) {
4002
+ return false;
4003
+ }
4004
+ const latest = effectLedgerMirror.boundaries
4005
+ .filter(runtimeBoundaryIsOwned)
4006
+ .at(-1);
4007
+ if (
4008
+ latest === undefined ||
4009
+ latest.sourceStateId !== pending.resumeStateId ||
4010
+ pending.asker.kind !== 'role' ||
4011
+ latest.roleId !== pending.asker.roleId ||
4012
+ latest.logicalOperationId !== undefined ||
4013
+ latest.physicalReceipt?.classification !== 'unchanged'
4014
+ ) {
4015
+ return false;
4016
+ }
4017
+ // Reuse the persisted authority/receipt check rather than infer an arm
4018
+ // from question prose or search older evidence for a convenient match.
4019
+ const persisted = persistedBoundaryReconciliation(
4020
+ latest,
4021
+ effectLedgerMirror,
4022
+ );
4023
+ if (
4024
+ persisted === undefined ||
4025
+ persisted.historicalDeferred ||
4026
+ persisted.reconciliation.status !== 'resolved'
4027
+ ) {
4028
+ return false;
4029
+ }
4030
+ const output = persisted.reconciliation.output;
4031
+ const declaration =
4032
+ outcomeAuthority.governedPlayerStates[latest.sourceStateId]?.[
4033
+ output.guard
4034
+ ];
4035
+ return (
4036
+ declaration?.repositoryDisposition === 'unchanged' &&
4037
+ typeof output.question === 'string' &&
4038
+ output.question === pending.question
4039
+ );
4040
+ }
4041
+
3990
4042
  function currentBoundDeferredOperation(
3991
4043
  pending: PlaybookPendingBossQuestionContext,
3992
4044
  ): PlaybookEffectLogicalOperation | undefined {
@@ -8313,7 +8365,8 @@ export function createXStatePlaybookRuntime<
8313
8365
  deferredPending !== undefined &&
8314
8366
  outcomeAuthority?.governedPlayerStates[
8315
8367
  deferredPending.resumeStateId
8316
- ]?.needsBossReply?.repositoryDisposition === 'deferred';
8368
+ ]?.needsBossReply?.repositoryDisposition === 'deferred' &&
8369
+ !pendingHasExactUnchangedOrigin(deferredPending);
8317
8370
  deferredOperation =
8318
8371
  !pendingRequiresDeferredBinding
8319
8372
  ? undefined