@sublang/playbook 13.1.0 → 13.3.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 +7 -5
- package/docs/cli.md +28 -9
- package/docs/configuration.md +27 -14
- package/docs/embedding.md +1 -1
- package/package.json +40 -2
- package/reference/sdlc/branch.md +37 -0
- package/reference/sdlc/branch.playbook/branch.fsm.d.ts +169 -0
- package/reference/sdlc/branch.playbook/branch.fsm.js +325 -0
- package/reference/sdlc/branch.playbook/branch.fsm.ts +458 -0
- package/reference/sdlc/branch.playbook/branch.gears.md +44 -0
- package/reference/sdlc/branch.playbook/branch.playbook.d.ts +20 -0
- package/reference/sdlc/branch.playbook/branch.playbook.js +121 -0
- package/reference/sdlc/branch.playbook/branch.playbook.ts +217 -0
- package/reference/sdlc/branch.playbook/branch.registry.d.ts +40 -0
- package/reference/sdlc/branch.playbook/branch.registry.js +63 -0
- package/reference/sdlc/branch.playbook/branch.registry.ts +121 -0
- package/reference/sdlc/code.playbook/bin/session-host.js +13 -3
- package/reference/sdlc/code.playbook/playbook-captain.d.ts +26 -1
- package/reference/sdlc/code.playbook/playbook-captain.js +218 -6
- package/reference/sdlc/code.playbook/playbook-captain.ts +281 -6
- package/reference/sdlc/code.playbook/playbook.config.template.yaml +21 -8
- package/reference/sdlc/code.playbook/session-host.d.ts +26 -0
- package/reference/sdlc/dev.md +24 -3
- package/reference/sdlc/dev.playbook/dev.fsm.d.ts +100 -9
- package/reference/sdlc/dev.playbook/dev.fsm.js +235 -18
- package/reference/sdlc/dev.playbook/dev.fsm.ts +368 -24
- package/reference/sdlc/dev.playbook/dev.gears.md +45 -7
- package/reference/sdlc/dev.playbook/dev.playbook.js +13 -1
- package/reference/sdlc/dev.playbook/dev.playbook.ts +13 -1
- package/reference/sdlc/dev.playbook/dev.registry.d.ts +1 -1
- package/reference/sdlc/dev.playbook/dev.registry.js +7 -2
- package/reference/sdlc/dev.playbook/dev.registry.ts +7 -2
- package/reference/sdlc/pr.md +108 -0
- package/reference/sdlc/pr.playbook/pr.fsm.d.ts +352 -0
- package/reference/sdlc/pr.playbook/pr.fsm.js +902 -0
- package/reference/sdlc/pr.playbook/pr.fsm.ts +1251 -0
- package/reference/sdlc/pr.playbook/pr.gears.md +155 -0
- package/reference/sdlc/pr.playbook/pr.playbook.d.ts +27 -0
- package/reference/sdlc/pr.playbook/pr.playbook.js +133 -0
- package/reference/sdlc/pr.playbook/pr.playbook.ts +235 -0
- package/reference/sdlc/pr.playbook/pr.registry.d.ts +40 -0
- package/reference/sdlc/pr.playbook/pr.registry.js +68 -0
- package/reference/sdlc/pr.playbook/pr.registry.ts +124 -0
|
@@ -15,13 +15,28 @@ export type JsonValue =
|
|
|
15
15
|
|
|
16
16
|
export type DevStateId =
|
|
17
17
|
| 'planAnalysis'
|
|
18
|
+
| 'createBranch'
|
|
18
19
|
| 'callCode'
|
|
19
20
|
| 'callDecide'
|
|
20
|
-
| 'callCodeAfterDecide'
|
|
21
|
+
| 'callCodeAfterDecide'
|
|
22
|
+
| 'openPullRequest';
|
|
21
23
|
|
|
22
|
-
export type DevSourceItem =
|
|
24
|
+
export type DevSourceItem =
|
|
25
|
+
| 'DEV-1'
|
|
26
|
+
| 'DEV-2'
|
|
27
|
+
| 'DEV-3'
|
|
28
|
+
| 'DEV-4'
|
|
29
|
+
| 'DEV-5'
|
|
30
|
+
| 'DEV-6';
|
|
23
31
|
|
|
24
|
-
export type DevChildPlaybookId = 'code' | 'decide';
|
|
32
|
+
export type DevChildPlaybookId = 'code' | 'decide' | 'branch' | 'pr';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* DR-050: the development path a pull-request planning outcome selected. It
|
|
36
|
+
* routes the `branch` success into `callCode` or `callDecide`, so the plain
|
|
37
|
+
* `code` and `decide then code` paths keep their items, prompts, and edges.
|
|
38
|
+
*/
|
|
39
|
+
export type DevPullRequestPath = 'code' | 'decide-then-code';
|
|
25
40
|
|
|
26
41
|
export type PendingBossQuestion = {
|
|
27
42
|
readonly questionId: 'planAnalysis';
|
|
@@ -53,11 +68,21 @@ export type PlayerOutput =
|
|
|
53
68
|
| { readonly guard: 'discussionComplete' }
|
|
54
69
|
| { readonly guard: 'code'; readonly planningResult: string }
|
|
55
70
|
| { readonly guard: 'decideThenCode'; readonly planningResult: string }
|
|
71
|
+
| { readonly guard: 'codeViaPullRequest'; readonly planningResult: string }
|
|
72
|
+
| {
|
|
73
|
+
readonly guard: 'decideThenCodeViaPullRequest';
|
|
74
|
+
readonly planningResult: string;
|
|
75
|
+
}
|
|
56
76
|
| { readonly guard: 'needsBossReply'; readonly question: string };
|
|
57
77
|
|
|
58
78
|
export type PlaybookInput = {
|
|
59
|
-
readonly stateId:
|
|
60
|
-
|
|
79
|
+
readonly stateId:
|
|
80
|
+
| 'createBranch'
|
|
81
|
+
| 'callCode'
|
|
82
|
+
| 'callDecide'
|
|
83
|
+
| 'callCodeAfterDecide'
|
|
84
|
+
| 'openPullRequest';
|
|
85
|
+
readonly sourceItem: 'DEV-2' | 'DEV-3' | 'DEV-4' | 'DEV-5' | 'DEV-6';
|
|
61
86
|
readonly playbookId: DevChildPlaybookId;
|
|
62
87
|
readonly text: string;
|
|
63
88
|
};
|
|
@@ -75,6 +100,29 @@ export type DecideSuccessOutput = {
|
|
|
75
100
|
readonly noUnsettledFindings: true;
|
|
76
101
|
};
|
|
77
102
|
|
|
103
|
+
/**
|
|
104
|
+
* The fields DEV consumes from `branch`'s canonical structured terminal
|
|
105
|
+
* output before continuing a pull-request path: the exact branch name, the
|
|
106
|
+
* exact base revision, and the issue summary. Additional members belong to
|
|
107
|
+
* BRANCH's own contract and do not disprove success; a missing member is an
|
|
108
|
+
* insufficient result, never an empty default.
|
|
109
|
+
*/
|
|
110
|
+
export type BranchSuccessOutput = {
|
|
111
|
+
readonly branch: string;
|
|
112
|
+
readonly baseRevision: string;
|
|
113
|
+
readonly issueSummary: string;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The fields DEV consumes from `code`'s canonical structured terminal output
|
|
118
|
+
* before starting the dependent `pr` call: the exact last `code`-owned commit
|
|
119
|
+
* and the exact final evaluated repository revision.
|
|
120
|
+
*/
|
|
121
|
+
export type CodeSuccessOutput = {
|
|
122
|
+
readonly lastCodeCommit: string;
|
|
123
|
+
readonly finalEvaluatedRevision: string;
|
|
124
|
+
};
|
|
125
|
+
|
|
78
126
|
export type CompactError = {
|
|
79
127
|
readonly name: string;
|
|
80
128
|
readonly message: string;
|
|
@@ -99,7 +147,8 @@ export type DevPlaybookOutput =
|
|
|
99
147
|
}
|
|
100
148
|
| {
|
|
101
149
|
readonly status: 'complete';
|
|
102
|
-
|
|
150
|
+
/** The final child of the selected path: `pr` on a pull-request path. */
|
|
151
|
+
readonly childPlaybookId: 'code' | 'pr';
|
|
103
152
|
/** The successful result of DEV's final child call, when it has one. */
|
|
104
153
|
readonly childOutput?: JsonValue;
|
|
105
154
|
}
|
|
@@ -120,6 +169,14 @@ export type DevContext = {
|
|
|
120
169
|
readonly planningResult?: string;
|
|
121
170
|
readonly decideCommit?: string;
|
|
122
171
|
readonly evaluatedRevision?: string;
|
|
172
|
+
/** DR-050: whether the accepted planning outcome selected a pull-request path. */
|
|
173
|
+
readonly deliveryViaPullRequest: boolean;
|
|
174
|
+
readonly pullRequestPath?: DevPullRequestPath;
|
|
175
|
+
readonly branch?: string;
|
|
176
|
+
readonly baseRevision?: string;
|
|
177
|
+
readonly issueSummary?: string;
|
|
178
|
+
readonly lastCodeCommit?: string;
|
|
179
|
+
readonly finalEvaluatedRevision?: string;
|
|
123
180
|
readonly completion?: 'discussion-complete' | 'complete' | 'child-failed';
|
|
124
181
|
readonly childOutput?: JsonValue;
|
|
125
182
|
readonly childFailure?: CompletedChildResult;
|
|
@@ -148,6 +205,7 @@ const PLAN_ANALYSIS_PROMPT = [
|
|
|
148
205
|
'- If the discussion has concluded after a Boss reply and no repository work should follow, choose `discussion complete`.',
|
|
149
206
|
'- If implementation can proceed under the existing decisions, choose `code`.',
|
|
150
207
|
'- If implementation first requires a new or amended durable decision that the existing specs do not settle, choose `decide then code`.',
|
|
208
|
+
'- If the request names a GitHub issue (number or URL) or explicitly asks for pull-request delivery, read the issue and its comments as part of the analysis (`gh issue view --comments` with the issue number) and choose `code via pull request` or `decide then code via pull request` in place of `code` or `decide then code`.',
|
|
151
209
|
'',
|
|
152
210
|
'A question or exploratory discussion is not by itself authorization to create a durable decision or implement changes.',
|
|
153
211
|
'Do not choose `decide then code` merely because the work is large.',
|
|
@@ -161,6 +219,10 @@ const PLAN_ANALYSIS_RESULTS = {
|
|
|
161
219
|
'Analyst determined implementation can proceed under the existing decisions. Output shall include `planningResult: <verbatim final text>`.',
|
|
162
220
|
decideThenCode:
|
|
163
221
|
'Analyst determined implementation first requires a new or amended durable decision that the existing specs do not settle. Output shall include `planningResult: <verbatim final text>`.',
|
|
222
|
+
codeViaPullRequest:
|
|
223
|
+
'Analyst determined implementation can proceed under the existing decisions and the request names a GitHub issue or explicitly asks for pull-request delivery. Output shall include `planningResult: <verbatim final text>`.',
|
|
224
|
+
decideThenCodeViaPullRequest:
|
|
225
|
+
'Analyst determined implementation first requires a new or amended durable decision that the existing specs do not settle and the request names a GitHub issue or explicitly asks for pull-request delivery. Output shall include `planningResult: <verbatim final text>`.',
|
|
164
226
|
needsBossReply:
|
|
165
227
|
"The acting agent's prose surfaces a clarifying question for Boss that the agent cannot answer alone. Output shall include `question: <verbatim question text from the acting agent's prose>`.",
|
|
166
228
|
} as const;
|
|
@@ -169,11 +231,15 @@ const STATE_DESCRIPTIONS = {
|
|
|
169
231
|
ready: 'Waiting for a development request.',
|
|
170
232
|
planAnalysis:
|
|
171
233
|
'Analyst is analyzing the development request to choose the smallest sound next step.',
|
|
234
|
+
createBranch:
|
|
235
|
+
'The BRANCH playbook is preparing the pull-request branch for the planned development path.',
|
|
172
236
|
callCode: 'The CODE playbook is implementing the planned development path.',
|
|
173
237
|
callDecide:
|
|
174
238
|
'The DECIDE playbook is settling the durable decision the planned path requires.',
|
|
175
239
|
callCodeAfterDecide:
|
|
176
240
|
'The CODE playbook is implementing the decided development path.',
|
|
241
|
+
openPullRequest:
|
|
242
|
+
'The PR playbook is delivering the implemented branch through a pull request.',
|
|
177
243
|
awaitBossReply: 'Waiting for Boss to answer Analyst.',
|
|
178
244
|
failed:
|
|
179
245
|
'The development planning workflow failed and is waiting for a new development request.',
|
|
@@ -253,6 +319,26 @@ function isDecideThenCode({ event }: { event: unknown }): boolean {
|
|
|
253
319
|
);
|
|
254
320
|
}
|
|
255
321
|
|
|
322
|
+
// DR-050: the two pull-request outcomes select the same development paths
|
|
323
|
+
// as `code` and `decide then code`, entered through `branch` first.
|
|
324
|
+
function isCodeViaPullRequest({ event }: { event: unknown }): boolean {
|
|
325
|
+
return (
|
|
326
|
+
outputGuard(event, 'codeViaPullRequest') &&
|
|
327
|
+
outputString(event, 'planningResult') !== undefined
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function isDecideThenCodeViaPullRequest({
|
|
332
|
+
event,
|
|
333
|
+
}: {
|
|
334
|
+
event: unknown;
|
|
335
|
+
}): boolean {
|
|
336
|
+
return (
|
|
337
|
+
outputGuard(event, 'decideThenCodeViaPullRequest') &&
|
|
338
|
+
outputString(event, 'planningResult') !== undefined
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
|
|
256
342
|
// Discussion complete is available only after a Boss reply: the round that
|
|
257
343
|
// produced it must itself have been resumed with Boss's answer.
|
|
258
344
|
function isDiscussionComplete({
|
|
@@ -292,6 +378,45 @@ function isDecideSuccess({ event }: { event: unknown }): boolean {
|
|
|
292
378
|
return isDecideSuccessValue(childOutputOf(event));
|
|
293
379
|
}
|
|
294
380
|
|
|
381
|
+
// BRANCH's canonical successful terminal output carries the exact name of
|
|
382
|
+
// the new checked-out branch, the exact receipt-owned base revision, and the
|
|
383
|
+
// issue summary; DEV consumes exactly those three by name and never defaults
|
|
384
|
+
// a missing one.
|
|
385
|
+
function isBranchSuccessValue(value: unknown): value is BranchSuccessOutput {
|
|
386
|
+
return (
|
|
387
|
+
isRecord(value) &&
|
|
388
|
+
isNonEmptyString(value.branch) &&
|
|
389
|
+
isNonEmptyString(value.baseRevision) &&
|
|
390
|
+
isNonEmptyString(value.issueSummary)
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function isBranchSuccessForCode({
|
|
395
|
+
context,
|
|
396
|
+
event,
|
|
397
|
+
}: {
|
|
398
|
+
context: DevContext;
|
|
399
|
+
event: unknown;
|
|
400
|
+
}): boolean {
|
|
401
|
+
return (
|
|
402
|
+
context.pullRequestPath === 'code' &&
|
|
403
|
+
isBranchSuccessValue(childOutputOf(event))
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function isBranchSuccessForDecide({
|
|
408
|
+
context,
|
|
409
|
+
event,
|
|
410
|
+
}: {
|
|
411
|
+
context: DevContext;
|
|
412
|
+
event: unknown;
|
|
413
|
+
}): boolean {
|
|
414
|
+
return (
|
|
415
|
+
context.pullRequestPath === 'decide-then-code' &&
|
|
416
|
+
isBranchSuccessValue(childOutputOf(event))
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
295
420
|
// CODE's canonical successful terminal output discriminates completion with
|
|
296
421
|
// `status: 'complete'`, carries the exact last CODE-owned commit, and
|
|
297
422
|
// affirms that every phase's review passed.
|
|
@@ -304,8 +429,44 @@ function isCodeSuccessValue(value: unknown): boolean {
|
|
|
304
429
|
);
|
|
305
430
|
}
|
|
306
431
|
|
|
307
|
-
|
|
308
|
-
|
|
432
|
+
// A plain path completes DEV on that proof alone, exactly as before DR-050.
|
|
433
|
+
function isPlainCodeSuccess({
|
|
434
|
+
context,
|
|
435
|
+
event,
|
|
436
|
+
}: {
|
|
437
|
+
context: DevContext;
|
|
438
|
+
event: unknown;
|
|
439
|
+
}): boolean {
|
|
440
|
+
return (
|
|
441
|
+
context.deliveryViaPullRequest !== true &&
|
|
442
|
+
isCodeSuccessValue(childOutputOf(event))
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// A pull-request path additionally consumes the exact final evaluated
|
|
447
|
+
// repository revision for the `pr` call, so a CODE result lacking it does not
|
|
448
|
+
// prove the success that path requires.
|
|
449
|
+
function isCodeSuccessValueForPullRequest(
|
|
450
|
+
value: unknown,
|
|
451
|
+
): value is CodeSuccessOutput & Record<string, unknown> {
|
|
452
|
+
return (
|
|
453
|
+
isCodeSuccessValue(value) &&
|
|
454
|
+
isRecord(value) &&
|
|
455
|
+
isNonEmptyString(value.finalEvaluatedRevision)
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function isCodeSuccessViaPullRequest({
|
|
460
|
+
context,
|
|
461
|
+
event,
|
|
462
|
+
}: {
|
|
463
|
+
context: DevContext;
|
|
464
|
+
event: unknown;
|
|
465
|
+
}): boolean {
|
|
466
|
+
return (
|
|
467
|
+
context.deliveryViaPullRequest === true &&
|
|
468
|
+
isCodeSuccessValueForPullRequest(childOutputOf(event))
|
|
469
|
+
);
|
|
309
470
|
}
|
|
310
471
|
|
|
311
472
|
function isStateValue(value: unknown, ancestors = new Set<object>()): boolean {
|
|
@@ -626,6 +787,38 @@ function codeAfterDecideCallText(context: DevContext): string {
|
|
|
626
787
|
]);
|
|
627
788
|
}
|
|
628
789
|
|
|
790
|
+
function branchCallText(context: DevContext): string {
|
|
791
|
+
return quotedRelay(planningRelayValues(context));
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// DEV-6: every placeholder is substituted from typed context that only a
|
|
795
|
+
// child's canonical structured result populated — never from player prose.
|
|
796
|
+
function pullRequestCallText(context: DevContext): string {
|
|
797
|
+
return quotedRelay([
|
|
798
|
+
['Original request', context.developmentRequest ?? ''],
|
|
799
|
+
['Issue summary', context.issueSummary ?? ''],
|
|
800
|
+
['Branch', context.branch ?? ''],
|
|
801
|
+
['Base revision', context.baseRevision ?? ''],
|
|
802
|
+
['CODE commit', context.lastCodeCommit ?? ''],
|
|
803
|
+
['Evaluated revision', context.finalEvaluatedRevision ?? ''],
|
|
804
|
+
]);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
function acceptedPlanningPath(
|
|
808
|
+
context: DevContext,
|
|
809
|
+
event: unknown,
|
|
810
|
+
pullRequestPath?: DevPullRequestPath,
|
|
811
|
+
) {
|
|
812
|
+
return {
|
|
813
|
+
planningResult: outputString(event, 'planningResult'),
|
|
814
|
+
discussionExchanges: archivedExchanges(context),
|
|
815
|
+
deliveryViaPullRequest: pullRequestPath !== undefined,
|
|
816
|
+
pullRequestPath,
|
|
817
|
+
pendingBossQuestion: undefined,
|
|
818
|
+
bossReply: undefined,
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
|
|
629
822
|
const machineSetup = setup({
|
|
630
823
|
types: {} as {
|
|
631
824
|
context: DevContext;
|
|
@@ -645,11 +838,18 @@ const machineSetup = setup({
|
|
|
645
838
|
isDiscussionComplete,
|
|
646
839
|
isCodePath,
|
|
647
840
|
isDecideThenCode,
|
|
841
|
+
isCodeViaPullRequest,
|
|
842
|
+
isDecideThenCodeViaPullRequest,
|
|
648
843
|
needsBossReply,
|
|
649
|
-
|
|
844
|
+
isBranchSuccessForCode,
|
|
845
|
+
isBranchSuccessForDecide,
|
|
846
|
+
isCodeSuccessViaPullRequest,
|
|
847
|
+
isPlainCodeSuccess,
|
|
650
848
|
isDecideSuccess,
|
|
849
|
+
authoredBranchFailure: authoredChildFailureGuard('branch'),
|
|
651
850
|
authoredCodeFailure: authoredChildFailureGuard('code'),
|
|
652
851
|
authoredDecideFailure: authoredChildFailureGuard('decide'),
|
|
852
|
+
authoredPrFailure: authoredChildFailureGuard('pr'),
|
|
653
853
|
emptyBossReply: ({ event }) =>
|
|
654
854
|
event.type === 'BOSS_REPLY' && event.answer.trim().length === 0,
|
|
655
855
|
resumesPlanAnalysis: ({ context, event }) =>
|
|
@@ -676,6 +876,13 @@ const machineSetup = setup({
|
|
|
676
876
|
planningResult: undefined,
|
|
677
877
|
decideCommit: undefined,
|
|
678
878
|
evaluatedRevision: undefined,
|
|
879
|
+
deliveryViaPullRequest: false,
|
|
880
|
+
pullRequestPath: undefined,
|
|
881
|
+
branch: undefined,
|
|
882
|
+
baseRevision: undefined,
|
|
883
|
+
issueSummary: undefined,
|
|
884
|
+
lastCodeCommit: undefined,
|
|
885
|
+
finalEvaluatedRevision: undefined,
|
|
679
886
|
completion: undefined,
|
|
680
887
|
childOutput: undefined,
|
|
681
888
|
childFailure: undefined,
|
|
@@ -690,18 +897,18 @@ const machineSetup = setup({
|
|
|
690
897
|
pendingBossQuestion: undefined,
|
|
691
898
|
bossReply: undefined,
|
|
692
899
|
})),
|
|
693
|
-
rememberCodePath: assign(({ context, event }) =>
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
900
|
+
rememberCodePath: assign(({ context, event }) =>
|
|
901
|
+
acceptedPlanningPath(context, event),
|
|
902
|
+
),
|
|
903
|
+
rememberDecidePath: assign(({ context, event }) =>
|
|
904
|
+
acceptedPlanningPath(context, event),
|
|
905
|
+
),
|
|
906
|
+
rememberCodeViaPullRequestPath: assign(({ context, event }) =>
|
|
907
|
+
acceptedPlanningPath(context, event, 'code'),
|
|
908
|
+
),
|
|
909
|
+
rememberDecideThenCodeViaPullRequestPath: assign(({ context, event }) =>
|
|
910
|
+
acceptedPlanningPath(context, event, 'decide-then-code'),
|
|
911
|
+
),
|
|
705
912
|
rememberPendingQuestion: assign(({ context, event }) => {
|
|
706
913
|
const question = outputString(event, 'question');
|
|
707
914
|
if (question === undefined || !outputGuard(event, 'needsBossReply')) {
|
|
@@ -727,6 +934,15 @@ const machineSetup = setup({
|
|
|
727
934
|
pendingBossQuestion: undefined,
|
|
728
935
|
bossReply: undefined,
|
|
729
936
|
}),
|
|
937
|
+
rememberBranchResult: assign(({ event }) => {
|
|
938
|
+
const output = childOutputOf(event);
|
|
939
|
+
if (!isBranchSuccessValue(output)) return {};
|
|
940
|
+
return {
|
|
941
|
+
branch: output.branch,
|
|
942
|
+
baseRevision: output.baseRevision,
|
|
943
|
+
issueSummary: output.issueSummary,
|
|
944
|
+
};
|
|
945
|
+
}),
|
|
730
946
|
rememberDecideResult: assign(({ event }) => {
|
|
731
947
|
const output = childOutputOf(event);
|
|
732
948
|
if (!isDecideSuccessValue(output)) return {};
|
|
@@ -735,6 +951,14 @@ const machineSetup = setup({
|
|
|
735
951
|
evaluatedRevision: output.evaluatedRevision,
|
|
736
952
|
};
|
|
737
953
|
}),
|
|
954
|
+
rememberCodeResult: assign(({ event }) => {
|
|
955
|
+
const output = childOutputOf(event);
|
|
956
|
+
if (!isCodeSuccessValueForPullRequest(output)) return {};
|
|
957
|
+
return {
|
|
958
|
+
lastCodeCommit: output.lastCodeCommit,
|
|
959
|
+
finalEvaluatedRevision: output.finalEvaluatedRevision,
|
|
960
|
+
};
|
|
961
|
+
}),
|
|
738
962
|
completeWithChildSuccess: assign(({ event }) => {
|
|
739
963
|
const output = childOutputOf(event);
|
|
740
964
|
return {
|
|
@@ -742,6 +966,10 @@ const machineSetup = setup({
|
|
|
742
966
|
...(output === undefined ? {} : { childOutput: output as JsonValue }),
|
|
743
967
|
};
|
|
744
968
|
}),
|
|
969
|
+
completeWithInsufficientBranchResult: assign(({ event }) => ({
|
|
970
|
+
completion: 'child-failed' as const,
|
|
971
|
+
childFailure: insufficientChildResult(event, 'branch'),
|
|
972
|
+
})),
|
|
745
973
|
completeWithInsufficientCodeResult: assign(({ event }) => ({
|
|
746
974
|
completion: 'child-failed' as const,
|
|
747
975
|
childFailure: insufficientChildResult(event, 'code'),
|
|
@@ -750,6 +978,10 @@ const machineSetup = setup({
|
|
|
750
978
|
completion: 'child-failed' as const,
|
|
751
979
|
childFailure: insufficientChildResult(event, 'decide'),
|
|
752
980
|
})),
|
|
981
|
+
completeWithBranchFailure: assign(({ event }) => ({
|
|
982
|
+
completion: 'child-failed' as const,
|
|
983
|
+
childFailure: relayedChildFailure(event, 'branch'),
|
|
984
|
+
})),
|
|
753
985
|
completeWithCodeFailure: assign(({ event }) => ({
|
|
754
986
|
completion: 'child-failed' as const,
|
|
755
987
|
childFailure: relayedChildFailure(event, 'code'),
|
|
@@ -758,6 +990,10 @@ const machineSetup = setup({
|
|
|
758
990
|
completion: 'child-failed' as const,
|
|
759
991
|
childFailure: relayedChildFailure(event, 'decide'),
|
|
760
992
|
})),
|
|
993
|
+
completeWithPrFailure: assign(({ event }) => ({
|
|
994
|
+
completion: 'child-failed' as const,
|
|
995
|
+
childFailure: relayedChildFailure(event, 'pr'),
|
|
996
|
+
})),
|
|
761
997
|
rememberActorError: assign(({ event }) => ({
|
|
762
998
|
lastError: (event as unknown as { readonly error?: unknown }).error,
|
|
763
999
|
})),
|
|
@@ -774,6 +1010,7 @@ export const devMachine = machineSetup.createMachine({
|
|
|
774
1010
|
context: ({ input }) => ({
|
|
775
1011
|
runResults: typeof input.runResults === 'string' ? input.runResults : '',
|
|
776
1012
|
discussionExchanges: [],
|
|
1013
|
+
deliveryViaPullRequest: false,
|
|
777
1014
|
}),
|
|
778
1015
|
output: ({ context }): DevPlaybookOutput => {
|
|
779
1016
|
if (context.completion === 'discussion-complete') {
|
|
@@ -782,7 +1019,9 @@ export const devMachine = machineSetup.createMachine({
|
|
|
782
1019
|
if (context.completion === 'complete') {
|
|
783
1020
|
return {
|
|
784
1021
|
status: 'complete',
|
|
785
|
-
|
|
1022
|
+
// `done` is entered by `pr` on a pull-request path and by `code` on a
|
|
1023
|
+
// plain path; no other arm completes the workflow.
|
|
1024
|
+
childPlaybookId: context.deliveryViaPullRequest ? 'pr' : 'code',
|
|
786
1025
|
...(context.childOutput === undefined
|
|
787
1026
|
? {}
|
|
788
1027
|
: { childOutput: context.childOutput }),
|
|
@@ -877,6 +1116,36 @@ export const devMachine = machineSetup.createMachine({
|
|
|
877
1116
|
'rememberDecidePath',
|
|
878
1117
|
],
|
|
879
1118
|
},
|
|
1119
|
+
{
|
|
1120
|
+
guard: 'isCodeViaPullRequest',
|
|
1121
|
+
target: 'createBranch',
|
|
1122
|
+
actions: [
|
|
1123
|
+
{
|
|
1124
|
+
type: 'playbook.acceptedOutcome',
|
|
1125
|
+
params: {
|
|
1126
|
+
source: 'planAnalysis',
|
|
1127
|
+
target: 'createBranch',
|
|
1128
|
+
acceptedOutcome: 'codeViaPullRequest',
|
|
1129
|
+
},
|
|
1130
|
+
},
|
|
1131
|
+
'rememberCodeViaPullRequestPath',
|
|
1132
|
+
],
|
|
1133
|
+
},
|
|
1134
|
+
{
|
|
1135
|
+
guard: 'isDecideThenCodeViaPullRequest',
|
|
1136
|
+
target: 'createBranch',
|
|
1137
|
+
actions: [
|
|
1138
|
+
{
|
|
1139
|
+
type: 'playbook.acceptedOutcome',
|
|
1140
|
+
params: {
|
|
1141
|
+
source: 'planAnalysis',
|
|
1142
|
+
target: 'createBranch',
|
|
1143
|
+
acceptedOutcome: 'decideThenCodeViaPullRequest',
|
|
1144
|
+
},
|
|
1145
|
+
},
|
|
1146
|
+
'rememberDecideThenCodeViaPullRequestPath',
|
|
1147
|
+
],
|
|
1148
|
+
},
|
|
880
1149
|
{
|
|
881
1150
|
guard: 'needsBossReply',
|
|
882
1151
|
target: 'awaitBossReply',
|
|
@@ -900,6 +1169,45 @@ export const devMachine = machineSetup.createMachine({
|
|
|
900
1169
|
onError: { target: 'failed', actions: 'rememberActorError' },
|
|
901
1170
|
},
|
|
902
1171
|
},
|
|
1172
|
+
createBranch: {
|
|
1173
|
+
id: 'createBranch',
|
|
1174
|
+
description: STATE_DESCRIPTIONS.createBranch,
|
|
1175
|
+
meta: playbookMeta('createBranch'),
|
|
1176
|
+
tags: ['playbook.suspended'],
|
|
1177
|
+
invoke: {
|
|
1178
|
+
src: 'playbook',
|
|
1179
|
+
input: ({ context }): PlaybookInput => ({
|
|
1180
|
+
stateId: 'createBranch',
|
|
1181
|
+
sourceItem: 'DEV-5',
|
|
1182
|
+
playbookId: 'branch',
|
|
1183
|
+
text: branchCallText(context),
|
|
1184
|
+
}),
|
|
1185
|
+
onDone: [
|
|
1186
|
+
{
|
|
1187
|
+
guard: 'isBranchSuccessForCode',
|
|
1188
|
+
target: 'callCode',
|
|
1189
|
+
actions: 'rememberBranchResult',
|
|
1190
|
+
},
|
|
1191
|
+
{
|
|
1192
|
+
guard: 'isBranchSuccessForDecide',
|
|
1193
|
+
target: 'callDecide',
|
|
1194
|
+
actions: 'rememberBranchResult',
|
|
1195
|
+
},
|
|
1196
|
+
{
|
|
1197
|
+
target: 'reportedChildFailure',
|
|
1198
|
+
actions: 'completeWithInsufficientBranchResult',
|
|
1199
|
+
},
|
|
1200
|
+
],
|
|
1201
|
+
onError: [
|
|
1202
|
+
{
|
|
1203
|
+
guard: 'authoredBranchFailure',
|
|
1204
|
+
target: 'reportedChildFailure',
|
|
1205
|
+
actions: 'completeWithBranchFailure',
|
|
1206
|
+
},
|
|
1207
|
+
{ target: 'failed', actions: 'rememberActorError' },
|
|
1208
|
+
],
|
|
1209
|
+
},
|
|
1210
|
+
},
|
|
903
1211
|
callCode: {
|
|
904
1212
|
id: 'callCode',
|
|
905
1213
|
description: STATE_DESCRIPTIONS.callCode,
|
|
@@ -915,7 +1223,12 @@ export const devMachine = machineSetup.createMachine({
|
|
|
915
1223
|
}),
|
|
916
1224
|
onDone: [
|
|
917
1225
|
{
|
|
918
|
-
guard: '
|
|
1226
|
+
guard: 'isCodeSuccessViaPullRequest',
|
|
1227
|
+
target: 'openPullRequest',
|
|
1228
|
+
actions: 'rememberCodeResult',
|
|
1229
|
+
},
|
|
1230
|
+
{
|
|
1231
|
+
guard: 'isPlainCodeSuccess',
|
|
919
1232
|
target: 'done',
|
|
920
1233
|
actions: 'completeWithChildSuccess',
|
|
921
1234
|
},
|
|
@@ -983,7 +1296,12 @@ export const devMachine = machineSetup.createMachine({
|
|
|
983
1296
|
}),
|
|
984
1297
|
onDone: [
|
|
985
1298
|
{
|
|
986
|
-
guard: '
|
|
1299
|
+
guard: 'isCodeSuccessViaPullRequest',
|
|
1300
|
+
target: 'openPullRequest',
|
|
1301
|
+
actions: 'rememberCodeResult',
|
|
1302
|
+
},
|
|
1303
|
+
{
|
|
1304
|
+
guard: 'isPlainCodeSuccess',
|
|
987
1305
|
target: 'done',
|
|
988
1306
|
actions: 'completeWithChildSuccess',
|
|
989
1307
|
},
|
|
@@ -1002,6 +1320,32 @@ export const devMachine = machineSetup.createMachine({
|
|
|
1002
1320
|
],
|
|
1003
1321
|
},
|
|
1004
1322
|
},
|
|
1323
|
+
openPullRequest: {
|
|
1324
|
+
id: 'openPullRequest',
|
|
1325
|
+
description: STATE_DESCRIPTIONS.openPullRequest,
|
|
1326
|
+
meta: playbookMeta('openPullRequest'),
|
|
1327
|
+
tags: ['playbook.suspended'],
|
|
1328
|
+
invoke: {
|
|
1329
|
+
src: 'playbook',
|
|
1330
|
+
input: ({ context }): PlaybookInput => ({
|
|
1331
|
+
stateId: 'openPullRequest',
|
|
1332
|
+
sourceItem: 'DEV-6',
|
|
1333
|
+
playbookId: 'pr',
|
|
1334
|
+
text: pullRequestCallText(context),
|
|
1335
|
+
}),
|
|
1336
|
+
// DR-048: `pr` declares its terminal kinds, so `onDone` alone proves
|
|
1337
|
+
// its success; DEV consumes none of its fields by name.
|
|
1338
|
+
onDone: { target: 'done', actions: 'completeWithChildSuccess' },
|
|
1339
|
+
onError: [
|
|
1340
|
+
{
|
|
1341
|
+
guard: 'authoredPrFailure',
|
|
1342
|
+
target: 'reportedChildFailure',
|
|
1343
|
+
actions: 'completeWithPrFailure',
|
|
1344
|
+
},
|
|
1345
|
+
{ target: 'failed', actions: 'rememberActorError' },
|
|
1346
|
+
],
|
|
1347
|
+
},
|
|
1348
|
+
},
|
|
1005
1349
|
awaitBossReply: {
|
|
1006
1350
|
id: 'awaitBossReply',
|
|
1007
1351
|
description: STATE_DESCRIPTIONS.awaitBossReply,
|
|
@@ -27,6 +27,7 @@ At the start of `dev` and after each Boss reply, Captain shall relay the develop
|
|
|
27
27
|
> - If the discussion has concluded after a Boss reply and no repository work should follow, choose `discussion complete`.
|
|
28
28
|
> - If implementation can proceed under the existing decisions, choose `code`.
|
|
29
29
|
> - If implementation first requires a new or amended durable decision that the existing specs do not settle, choose `decide then code`.
|
|
30
|
+
> - If the request names a GitHub issue (number or URL) or explicitly asks for pull-request delivery, read the issue and its comments as part of the analysis (`gh issue view --comments` with the issue number) and choose `code via pull request` or `decide then code via pull request` in place of `code` or `decide then code`.
|
|
30
31
|
>
|
|
31
32
|
> A question or exploratory discussion is not by itself authorization to create a durable decision or implement changes.
|
|
32
33
|
> Do not choose `decide then code` merely because the work is large.
|
|
@@ -36,9 +37,11 @@ Results:
|
|
|
36
37
|
- `discussionComplete`: Analyst concluded the discussion after a Boss reply, with no repository work to follow.
|
|
37
38
|
- `code`: Analyst determined implementation can proceed under the existing decisions. Output shall include `planningResult: <verbatim final text>`.
|
|
38
39
|
- `decideThenCode`: Analyst determined implementation first requires a new or amended durable decision that the existing specs do not settle. Output shall include `planningResult: <verbatim final text>`.
|
|
40
|
+
- `codeViaPullRequest`: Analyst determined implementation can proceed under the existing decisions and the request names a GitHub issue or explicitly asks for pull-request delivery. Output shall include `planningResult: <verbatim final text>`.
|
|
41
|
+
- `decideThenCodeViaPullRequest`: Analyst determined implementation first requires a new or amended durable decision that the existing specs do not settle and the request names a GitHub issue or explicitly asks for pull-request delivery. Output shall include `planningResult: <verbatim final text>`.
|
|
39
42
|
|
|
40
43
|
Workflow outcomes:
|
|
41
|
-
- The planning result has
|
|
44
|
+
- The planning result has six semantic outcomes: needs Boss reply, discussion complete, code, decide then code, code via pull request, and decide then code via pull request.
|
|
42
45
|
- Each outcome requires affirmative support in Analyst's result; absence of a reason to choose another outcome is not support, and no outcome depends on a fixed presentation format of Analyst's reply.
|
|
43
46
|
- Needs Boss reply uses the standard Boss-question suspension with Analyst's complete response; after Boss replies, `dev` resumes with the answer in the same Analyst conversation; the previous question is included only when that conversation must start fresh.
|
|
44
47
|
- Discussion complete is available only after a Boss reply, when any useful analysis has already been presented through needs Boss reply; it completes `dev` without a child call or repository change.
|
|
@@ -48,21 +51,22 @@ Workflow outcomes:
|
|
|
48
51
|
|
|
49
52
|
### DEV-2
|
|
50
53
|
|
|
51
|
-
When the accepted planning result selects `code`, Captain shall call playbook `code`:
|
|
54
|
+
When the accepted planning result selects `code`, or `branch` succeeds for `code via pull request`, Captain shall call playbook `code`:
|
|
52
55
|
|
|
53
56
|
> > Original request: <development-request>
|
|
54
57
|
> > Prior discussion: <discussion-context>
|
|
55
58
|
> > Planning result: <planning-result>
|
|
56
59
|
|
|
57
60
|
Workflow outcomes:
|
|
58
|
-
- `code` success completes `dev` with the successful `code` result.
|
|
61
|
+
- On a plain path, `code` success completes `dev` with the successful `code` result.
|
|
62
|
+
- On a pull-request path, `code` success provides the exact last `code`-owned commit and the exact final evaluated repository revision from `code`'s canonical structured result and continues with the `pr` call.
|
|
59
63
|
- An authored `code` abort or failure, or a terminal `code` result that does not prove the success required for the selected path, terminates `dev` with that canonical result relayed and no later child call.
|
|
60
64
|
- Any other nested-call error parks `dev` as failed and retains the control-plane error.
|
|
61
|
-
- `dev` consumes commit identities only from each child's canonical structured result, never from player prose.
|
|
65
|
+
- `dev` consumes commit, revision, branch, and pull-request identities only from each child's canonical structured result, never from player prose.
|
|
62
66
|
|
|
63
67
|
### DEV-3
|
|
64
68
|
|
|
65
|
-
When the accepted planning result selects `decide then code`, Captain shall call playbook `decide`:
|
|
69
|
+
When the accepted planning result selects `decide then code`, or `branch` succeeds for `decide then code via pull request`, Captain shall call playbook `decide`:
|
|
66
70
|
|
|
67
71
|
> > Original request: <development-request>
|
|
68
72
|
> > Prior discussion: <discussion-context>
|
|
@@ -85,7 +89,41 @@ When `decide` succeeds, Captain shall call playbook `code`:
|
|
|
85
89
|
> > Evaluated revision: <evaluated-revision>
|
|
86
90
|
|
|
87
91
|
Workflow outcomes:
|
|
88
|
-
- `code` success completes `dev` with the successful `code` result.
|
|
92
|
+
- On a plain path, `code` success completes `dev` with the successful `code` result.
|
|
93
|
+
- On a pull-request path, `code` success provides the exact last `code`-owned commit and the exact final evaluated repository revision from `code`'s canonical structured result and continues with the `pr` call.
|
|
89
94
|
- An authored `code` abort or failure, or a terminal `code` result that does not prove the success required for the selected path, terminates `dev` with that canonical result relayed and no later child call.
|
|
90
95
|
- Any other nested-call error parks `dev` as failed and retains the control-plane error.
|
|
91
|
-
- `dev` consumes commit identities only from each child's canonical structured result, never from player prose.
|
|
96
|
+
- `dev` consumes commit, revision, branch, and pull-request identities only from each child's canonical structured result, never from player prose.
|
|
97
|
+
|
|
98
|
+
## Pull-request delivery
|
|
99
|
+
|
|
100
|
+
### DEV-5
|
|
101
|
+
|
|
102
|
+
When the accepted planning result selects `code via pull request` or `decide then code via pull request`, Captain shall call playbook `branch`:
|
|
103
|
+
|
|
104
|
+
> > Original request: <development-request>
|
|
105
|
+
> > Prior discussion: <discussion-context>
|
|
106
|
+
> > Planning result: <planning-result>
|
|
107
|
+
|
|
108
|
+
Workflow outcomes:
|
|
109
|
+
- `branch` success provides the exact branch name, the exact base revision, and the issue summary from `branch`'s canonical structured result and continues with the `code` call for code via pull request, or the `decide` call and then the `code` call for decide then code via pull request, each with the same input as its plain path.
|
|
110
|
+
- An authored `branch` abort or failure, or a terminal `branch` result that does not prove that success, terminates `dev` with that canonical result relayed and no later child call.
|
|
111
|
+
- Any other nested-call error parks `dev` as failed and retains the control-plane error.
|
|
112
|
+
- A plain request calls neither `branch` nor `pr`.
|
|
113
|
+
|
|
114
|
+
### DEV-6
|
|
115
|
+
|
|
116
|
+
When `code` succeeds on a pull-request path, Captain shall call playbook `pr`:
|
|
117
|
+
|
|
118
|
+
> > Original request: <development-request>
|
|
119
|
+
> > Issue summary: <issue-summary>
|
|
120
|
+
> > Branch: <branch>
|
|
121
|
+
> > Base revision: <base-revision>
|
|
122
|
+
> > CODE commit: <last-code-commit>
|
|
123
|
+
> > Evaluated revision: <final-evaluated-revision>
|
|
124
|
+
|
|
125
|
+
Workflow outcomes:
|
|
126
|
+
- `pr` success completes `dev` with the successful `pr` result.
|
|
127
|
+
- An authored `pr` abort or failure, or a terminal `pr` result that does not prove the success required for the selected path, terminates `dev` with that canonical result relayed and no later child call.
|
|
128
|
+
- Any other nested-call error parks `dev` as failed and retains the control-plane error.
|
|
129
|
+
- `dev` consumes commit, revision, branch, and pull-request identities only from each child's canonical structured result, never from player prose.
|