@sublang/playbook 14.0.0 → 14.1.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/docs/cli.md +14 -14
- package/package.json +1 -1
- package/reference/sdlc/branch.playbook/branch.fsm.d.ts +1 -1
- package/reference/sdlc/code.playbook/bin/repository-effects.js +187 -14
- package/reference/sdlc/code.playbook/code.fsm.d.ts +1 -1
- package/reference/sdlc/code.playbook/host-capabilities.d.ts +6 -0
- package/reference/sdlc/code.playbook/playbook-captain.d.ts +3 -1
- package/reference/sdlc/code.playbook/playbook-captain.js +357 -16
- package/reference/sdlc/code.playbook/playbook-captain.ts +459 -34
- package/reference/sdlc/code.playbook/session-host.d.ts +6 -3
- package/reference/sdlc/decide.playbook/decide.fsm.d.ts +1 -1
- package/reference/sdlc/decide.playbook/decide.playbook.js +25 -1
- package/reference/sdlc/decide.playbook/decide.playbook.ts +35 -2
- package/reference/sdlc/dev.md +15 -8
- package/reference/sdlc/dev.playbook/dev.fsm.d.ts +1 -1
- package/reference/sdlc/dev.playbook/dev.fsm.js +18 -12
- package/reference/sdlc/dev.playbook/dev.fsm.ts +18 -13
- package/reference/sdlc/dev.playbook/dev.gears.md +19 -12
- package/reference/sdlc/dev.playbook/dev.playbook.js +1 -1
- package/reference/sdlc/dev.playbook/dev.playbook.ts +1 -2
- package/reference/sdlc/dev.playbook/dev.registry.js +1 -1
- package/reference/sdlc/dev.playbook/dev.registry.ts +1 -1
- package/reference/sdlc/pr.playbook/pr.fsm.d.ts +1 -1
- package/reference/sdlc/review.playbook/review.fsm.d.ts +1 -1
- package/slc/link.md +32 -0
- package/src/runtime.d.ts +70 -0
- package/src/runtime.js +232 -1
- package/src/runtime.ts +358 -1
- package/src/xstate-playbook-runtime.d.ts +9 -10
- package/src/xstate-playbook-runtime.js +372 -20
- package/src/xstate-playbook-runtime.ts +460 -19
- package/src/xstate-runtime.d.ts +9 -1
- package/src/xstate-runtime.js +299 -19
- package/src/xstate-runtime.ts +362 -21
|
@@ -2481,20 +2481,42 @@ function createDecidePlaybookRuntime(options, deferredEffects) {
|
|
|
2481
2481
|
}
|
|
2482
2482
|
return 'restored';
|
|
2483
2483
|
};
|
|
2484
|
+
/**
|
|
2485
|
+
* DR-063 §3: reconciliation re-reads the host's ledger, which the control
|
|
2486
|
+
* view has just done. With no eligible checkpoint restoration and a complete
|
|
2487
|
+
* receipt on every unresolved boundary, re-reading resolves nothing.
|
|
2488
|
+
*/
|
|
2489
|
+
const reconciliationStanding = (restorationEligible) => {
|
|
2490
|
+
if (restorationEligible)
|
|
2491
|
+
return { standing: 'ready' };
|
|
2492
|
+
const envelopes = unresolvedEffectEnvelopeIdentities();
|
|
2493
|
+
if (envelopes.length === 0)
|
|
2494
|
+
return { standing: 'ready' };
|
|
2495
|
+
const boundaryIds = envelopes.flatMap((envelope) => envelope.kind === 'boundary'
|
|
2496
|
+
? [envelope.boundaryId]
|
|
2497
|
+
: (effectLedgerMirror.logicalOperations.find(({ operationId }) => operationId === envelope.operationId)?.boundaryIds ?? []));
|
|
2498
|
+
if (boundaryIds.length === 0)
|
|
2499
|
+
return { standing: 'ready' };
|
|
2500
|
+
return boundaryIds.every((boundaryId) => effectLedgerMirror.boundaries.find((candidate) => candidate.boundaryId === boundaryId)?.physicalReceipt !== undefined)
|
|
2501
|
+
? { standing: 'no-op', reason: 'receipt-complete' }
|
|
2502
|
+
: { standing: 'ready' };
|
|
2503
|
+
};
|
|
2484
2504
|
const unresolvedControlCandidates = () => {
|
|
2485
2505
|
if (!hasUnresolvedReconciliation())
|
|
2486
2506
|
return [];
|
|
2487
2507
|
const operation = hiddenDeferredOperationId === undefined
|
|
2488
2508
|
? undefined
|
|
2489
2509
|
: effectLedgerMirror.logicalOperations.find(({ operationId }) => operationId === hiddenDeferredOperationId);
|
|
2510
|
+
const restorationEligible = operation?.checkpointRestorationEligible === true;
|
|
2490
2511
|
return [
|
|
2491
2512
|
{
|
|
2492
2513
|
action: {
|
|
2493
2514
|
id: UNRESOLVED_EFFECT_RECONCILIATION_ACTION_ID,
|
|
2494
2515
|
label: 'Retry unresolved effect reconciliation',
|
|
2516
|
+
...reconciliationStanding(restorationEligible),
|
|
2495
2517
|
},
|
|
2496
2518
|
kind: 'reconcile',
|
|
2497
|
-
...(
|
|
2519
|
+
...(restorationEligible
|
|
2498
2520
|
? { deferredRestoreOperationId: operation.operationId }
|
|
2499
2521
|
: {}),
|
|
2500
2522
|
},
|
|
@@ -2502,6 +2524,8 @@ function createDecidePlaybookRuntime(options, deferredEffects) {
|
|
|
2502
2524
|
action: {
|
|
2503
2525
|
id: UNRESOLVED_EFFECT_ABANDONMENT_ACTION_ID,
|
|
2504
2526
|
label: 'Abandon unresolved workflow attempt',
|
|
2527
|
+
// DR-063 §3: abandonment always changes the session's standing.
|
|
2528
|
+
standing: 'ready',
|
|
2505
2529
|
},
|
|
2506
2530
|
kind: 'abandon',
|
|
2507
2531
|
},
|
|
@@ -3850,6 +3850,35 @@ function createDecidePlaybookRuntime(
|
|
|
3850
3850
|
};
|
|
3851
3851
|
type UnresolvedControlCandidates = readonly UnresolvedControlCandidate[];
|
|
3852
3852
|
|
|
3853
|
+
/**
|
|
3854
|
+
* DR-063 §3: reconciliation re-reads the host's ledger, which the control
|
|
3855
|
+
* view has just done. With no eligible checkpoint restoration and a complete
|
|
3856
|
+
* receipt on every unresolved boundary, re-reading resolves nothing.
|
|
3857
|
+
*/
|
|
3858
|
+
const reconciliationStanding = (
|
|
3859
|
+
restorationEligible: boolean,
|
|
3860
|
+
): Pick<PlaybookControlAction, 'standing' | 'reason'> => {
|
|
3861
|
+
if (restorationEligible) return { standing: 'ready' };
|
|
3862
|
+
const envelopes = unresolvedEffectEnvelopeIdentities();
|
|
3863
|
+
if (envelopes.length === 0) return { standing: 'ready' };
|
|
3864
|
+
const boundaryIds = envelopes.flatMap((envelope) =>
|
|
3865
|
+
envelope.kind === 'boundary'
|
|
3866
|
+
? [envelope.boundaryId]
|
|
3867
|
+
: (effectLedgerMirror.logicalOperations.find(
|
|
3868
|
+
({ operationId }) => operationId === envelope.operationId,
|
|
3869
|
+
)?.boundaryIds ?? []),
|
|
3870
|
+
);
|
|
3871
|
+
if (boundaryIds.length === 0) return { standing: 'ready' };
|
|
3872
|
+
return boundaryIds.every(
|
|
3873
|
+
(boundaryId) =>
|
|
3874
|
+
effectLedgerMirror.boundaries.find(
|
|
3875
|
+
(candidate) => candidate.boundaryId === boundaryId,
|
|
3876
|
+
)?.physicalReceipt !== undefined,
|
|
3877
|
+
)
|
|
3878
|
+
? { standing: 'no-op', reason: 'receipt-complete' }
|
|
3879
|
+
: { standing: 'ready' };
|
|
3880
|
+
};
|
|
3881
|
+
|
|
3853
3882
|
const unresolvedControlCandidates = (): UnresolvedControlCandidates => {
|
|
3854
3883
|
if (!hasUnresolvedReconciliation()) return [];
|
|
3855
3884
|
const operation =
|
|
@@ -3859,21 +3888,25 @@ function createDecidePlaybookRuntime(
|
|
|
3859
3888
|
({ operationId }) =>
|
|
3860
3889
|
operationId === hiddenDeferredOperationId,
|
|
3861
3890
|
);
|
|
3891
|
+
const restorationEligible = operation?.checkpointRestorationEligible === true;
|
|
3862
3892
|
return [
|
|
3863
3893
|
{
|
|
3864
3894
|
action: {
|
|
3865
3895
|
id: UNRESOLVED_EFFECT_RECONCILIATION_ACTION_ID,
|
|
3866
3896
|
label: 'Retry unresolved effect reconciliation',
|
|
3897
|
+
...reconciliationStanding(restorationEligible),
|
|
3867
3898
|
},
|
|
3868
3899
|
kind: 'reconcile',
|
|
3869
|
-
...(
|
|
3870
|
-
? { deferredRestoreOperationId: operation
|
|
3900
|
+
...(restorationEligible
|
|
3901
|
+
? { deferredRestoreOperationId: operation!.operationId }
|
|
3871
3902
|
: {}),
|
|
3872
3903
|
},
|
|
3873
3904
|
{
|
|
3874
3905
|
action: {
|
|
3875
3906
|
id: UNRESOLVED_EFFECT_ABANDONMENT_ACTION_ID,
|
|
3876
3907
|
label: 'Abandon unresolved workflow attempt',
|
|
3908
|
+
// DR-063 §3: abandonment always changes the session's standing.
|
|
3909
|
+
standing: 'ready',
|
|
3877
3910
|
},
|
|
3878
3911
|
kind: 'abandon',
|
|
3879
3912
|
},
|
package/reference/sdlc/dev.md
CHANGED
|
@@ -12,6 +12,7 @@ The caller supplies a development request including any desired outcome, scope,
|
|
|
12
12
|
|
|
13
13
|
`dev` is an optional repository-aware planner for a development request that needs more analysis before choosing a development path.
|
|
14
14
|
It coordinates existing playbooks and owns no repository commit itself.
|
|
15
|
+
Analyst chooses the path and states why in a short planning note; analysis, design, and implementation belong to the playbooks `dev` calls, and a question to Boss serves only the choice of path.
|
|
15
16
|
|
|
16
17
|
At the start of `dev` and after each Boss reply, Captain shall relay the development request, relevant discussion context, and any relevant run results to Analyst in quotes (`>`), along with the following instruction:
|
|
17
18
|
|
|
@@ -20,17 +21,23 @@ At the start of `dev` and after each Boss reply, Captain shall relay the develop
|
|
|
20
21
|
> Run results: <run-results>
|
|
21
22
|
|
|
22
23
|
```markdown
|
|
23
|
-
|
|
24
|
+
Plan which playbooks run for this request; the playbooks do the work.
|
|
25
|
+
Read the request, then the specs and the repository only as far as choosing the path requires.
|
|
24
26
|
Do not change files or commit while planning or discussing the request.
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
- If the discussion has concluded after a Boss reply and no repository work should follow, choose `discussion complete`.
|
|
28
|
-
- If implementation can proceed under the existing decisions, choose `code`.
|
|
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`.
|
|
28
|
+
Choose exactly one:
|
|
31
29
|
|
|
30
|
+
- `code`: the existing decisions and spec items settle how the work is done.
|
|
31
|
+
- `decide then code`: the work turns on a rule, concept, term, shape, or trade-off the specs leave open or contradict; name what is open, do not settle it.
|
|
32
|
+
- `code via pull request` or `decide then code via pull request`, in place of the two above, when the request names a GitHub issue (number or URL) or explicitly asks for pull-request delivery; read the issue and its comments (`gh issue view --comments` with the issue number) while choosing.
|
|
33
|
+
- A question to Boss, only when the answer would change which path runs or whether any work is wanted: one short question naming the alternatives it decides between, and nothing else. When every answer leads to the same path, choose it; the playbook settles the open point.
|
|
34
|
+
- `discussion complete`, after a Boss reply, when no repository work should follow.
|
|
35
|
+
|
|
36
|
+
Your reply is the planning note the chosen playbook receives. It holds only the path and, in at most ten lines, why — the decisions and spec items that settle the work, or the open point a decision must settle — plus the scope the request implies and any fact from the issue the playbooks need.
|
|
37
|
+
It holds no design, proposal, implementation instruction, or file-level finding: the playbooks own those.
|
|
38
|
+
A reply that chooses a path asks Boss nothing; a reply that asks Boss chooses no path.
|
|
32
39
|
A question or exploratory discussion is not by itself authorization to create a durable decision or implement changes.
|
|
33
|
-
Do not choose `decide then code` merely because the work is large.
|
|
40
|
+
Do not choose `decide then code` merely because the work is large, nor `code` merely because it is small.
|
|
34
41
|
Consult @specs/map.md for relevant context and @specs/meta.md for spec requirements, if needed.
|
|
35
42
|
```
|
|
36
43
|
|
|
@@ -42,7 +49,7 @@ No outcome depends on a fixed presentation format of Analyst's reply.
|
|
|
42
49
|
For needs Boss reply, `dev` shall use the standard Boss-question suspension with Analyst's complete response.
|
|
43
50
|
The session Captain shall present that response to Boss and, after Boss replies, resume `dev` with the answer in the same Analyst conversation; include the previous question only when that conversation must start fresh.
|
|
44
51
|
|
|
45
|
-
Discussion complete is available only after a Boss reply, when
|
|
52
|
+
Discussion complete is available only after a Boss reply, when that reply settles that no repository work should follow.
|
|
46
53
|
It completes `dev` without a child call or repository change.
|
|
47
54
|
|
|
48
55
|
For code, `dev` shall directly call playbook `code` with the development request, relevant discussion context, and planning result in quotes (`>`).
|
|
@@ -296,7 +296,7 @@ export declare const devMachine: import("xstate").StateMachine<DevContext, {
|
|
|
296
296
|
} | {
|
|
297
297
|
type: "resumesPlanAnalysis";
|
|
298
298
|
params: unknown;
|
|
299
|
-
}, never, "done" | "failed" | "
|
|
299
|
+
}, never, "done" | "failed" | "ready" | "awaitBossReply" | "planAnalysis" | "createBranch" | "callCode" | "callDecide" | "callCodeAfterDecide" | "openPullRequest" | "discussionComplete" | "reportedChildFailure", string, DevInput, {
|
|
300
300
|
readonly status: "discussion-complete";
|
|
301
301
|
} | {
|
|
302
302
|
readonly status: "complete";
|
|
@@ -8,30 +8,36 @@ const PLAN_ANALYSIS_PROMPT = [
|
|
|
8
8
|
'> Prior discussion: <discussion-context>',
|
|
9
9
|
'> Run results: <run-results>',
|
|
10
10
|
'',
|
|
11
|
-
'
|
|
11
|
+
'Plan which playbooks run for this request; the playbooks do the work.',
|
|
12
|
+
'Read the request, then the specs and the repository only as far as choosing the path requires.',
|
|
12
13
|
'Do not change files or commit while planning or discussing the request.',
|
|
13
14
|
'',
|
|
14
|
-
'
|
|
15
|
-
'- If the discussion has concluded after a Boss reply and no repository work should follow, choose `discussion complete`.',
|
|
16
|
-
'- If implementation can proceed under the existing decisions, choose `code`.',
|
|
17
|
-
'- If implementation first requires a new or amended durable decision that the existing specs do not settle, choose `decide then code`.',
|
|
18
|
-
'- 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`.',
|
|
15
|
+
'Choose exactly one:',
|
|
19
16
|
'',
|
|
17
|
+
'- `code`: the existing decisions and spec items settle how the work is done.',
|
|
18
|
+
'- `decide then code`: the work turns on a rule, concept, term, shape, or trade-off the specs leave open or contradict; name what is open, do not settle it.',
|
|
19
|
+
'- `code via pull request` or `decide then code via pull request`, in place of the two above, when the request names a GitHub issue (number or URL) or explicitly asks for pull-request delivery; read the issue and its comments (`gh issue view --comments` with the issue number) while choosing.',
|
|
20
|
+
'- A question to Boss, only when the answer would change which path runs or whether any work is wanted: one short question naming the alternatives it decides between, and nothing else. When every answer leads to the same path, choose it; the playbook settles the open point.',
|
|
21
|
+
'- `discussion complete`, after a Boss reply, when no repository work should follow.',
|
|
22
|
+
'',
|
|
23
|
+
'Your reply is the planning note the chosen playbook receives. It holds only the path and, in at most ten lines, why — the decisions and spec items that settle the work, or the open point a decision must settle — plus the scope the request implies and any fact from the issue the playbooks need.',
|
|
24
|
+
'It holds no design, proposal, implementation instruction, or file-level finding: the playbooks own those.',
|
|
25
|
+
'A reply that chooses a path asks Boss nothing; a reply that asks Boss chooses no path.',
|
|
20
26
|
'A question or exploratory discussion is not by itself authorization to create a durable decision or implement changes.',
|
|
21
|
-
'Do not choose `decide then code` merely because the work is large.',
|
|
27
|
+
'Do not choose `decide then code` merely because the work is large, nor `code` merely because it is small.',
|
|
22
28
|
'Consult @specs/map.md for relevant context and @specs/meta.md for spec requirements, if needed.',
|
|
23
29
|
].join('\n');
|
|
24
30
|
const PLAN_ANALYSIS_RESULTS = {
|
|
25
31
|
discussionComplete: 'Analyst concluded the discussion after a Boss reply, with no repository work to follow.',
|
|
26
|
-
code: 'Analyst
|
|
27
|
-
decideThenCode: 'Analyst
|
|
28
|
-
codeViaPullRequest: 'Analyst
|
|
29
|
-
decideThenCodeViaPullRequest: 'Analyst
|
|
32
|
+
code: 'Analyst chose `code`: the existing decisions and spec items settle how the work is done. Output shall include `planningResult: <verbatim final text>`.',
|
|
33
|
+
decideThenCode: 'Analyst chose `decide then code`: the work turns on a point the specs leave open or contradict. Output shall include `planningResult: <verbatim final text>`.',
|
|
34
|
+
codeViaPullRequest: 'Analyst chose `code via pull request`: the existing decisions settle the work, and the request names a GitHub issue or explicitly asks for pull-request delivery. Output shall include `planningResult: <verbatim final text>`.',
|
|
35
|
+
decideThenCodeViaPullRequest: 'Analyst chose `decide then code via pull request`: the work turns on a point the specs leave open or contradict, and the request names a GitHub issue or explicitly asks for pull-request delivery. Output shall include `planningResult: <verbatim final text>`.',
|
|
30
36
|
needsBossReply: "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>`.",
|
|
31
37
|
};
|
|
32
38
|
const STATE_DESCRIPTIONS = {
|
|
33
39
|
ready: 'Waiting for a development request.',
|
|
34
|
-
planAnalysis: 'Analyst is
|
|
40
|
+
planAnalysis: 'Analyst is choosing the development path.',
|
|
35
41
|
createBranch: 'The BRANCH playbook is preparing the pull-request branch for the planned development path.',
|
|
36
42
|
callCode: 'The CODE playbook is implementing the planned development path.',
|
|
37
43
|
callDecide: 'The DECIDE playbook is settling the durable decision the planned path requires.',
|
|
@@ -198,17 +198,23 @@ const PLAN_ANALYSIS_PROMPT = [
|
|
|
198
198
|
'> Prior discussion: <discussion-context>',
|
|
199
199
|
'> Run results: <run-results>',
|
|
200
200
|
'',
|
|
201
|
-
'
|
|
201
|
+
'Plan which playbooks run for this request; the playbooks do the work.',
|
|
202
|
+
'Read the request, then the specs and the repository only as far as choosing the path requires.',
|
|
202
203
|
'Do not change files or commit while planning or discussing the request.',
|
|
203
204
|
'',
|
|
204
|
-
'
|
|
205
|
-
'- If the discussion has concluded after a Boss reply and no repository work should follow, choose `discussion complete`.',
|
|
206
|
-
'- If implementation can proceed under the existing decisions, choose `code`.',
|
|
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`.',
|
|
205
|
+
'Choose exactly one:',
|
|
209
206
|
'',
|
|
207
|
+
'- `code`: the existing decisions and spec items settle how the work is done.',
|
|
208
|
+
'- `decide then code`: the work turns on a rule, concept, term, shape, or trade-off the specs leave open or contradict; name what is open, do not settle it.',
|
|
209
|
+
'- `code via pull request` or `decide then code via pull request`, in place of the two above, when the request names a GitHub issue (number or URL) or explicitly asks for pull-request delivery; read the issue and its comments (`gh issue view --comments` with the issue number) while choosing.',
|
|
210
|
+
'- A question to Boss, only when the answer would change which path runs or whether any work is wanted: one short question naming the alternatives it decides between, and nothing else. When every answer leads to the same path, choose it; the playbook settles the open point.',
|
|
211
|
+
'- `discussion complete`, after a Boss reply, when no repository work should follow.',
|
|
212
|
+
'',
|
|
213
|
+
'Your reply is the planning note the chosen playbook receives. It holds only the path and, in at most ten lines, why — the decisions and spec items that settle the work, or the open point a decision must settle — plus the scope the request implies and any fact from the issue the playbooks need.',
|
|
214
|
+
'It holds no design, proposal, implementation instruction, or file-level finding: the playbooks own those.',
|
|
215
|
+
'A reply that chooses a path asks Boss nothing; a reply that asks Boss chooses no path.',
|
|
210
216
|
'A question or exploratory discussion is not by itself authorization to create a durable decision or implement changes.',
|
|
211
|
-
'Do not choose `decide then code` merely because the work is large.',
|
|
217
|
+
'Do not choose `decide then code` merely because the work is large, nor `code` merely because it is small.',
|
|
212
218
|
'Consult @specs/map.md for relevant context and @specs/meta.md for spec requirements, if needed.',
|
|
213
219
|
].join('\n');
|
|
214
220
|
|
|
@@ -216,21 +222,20 @@ const PLAN_ANALYSIS_RESULTS = {
|
|
|
216
222
|
discussionComplete:
|
|
217
223
|
'Analyst concluded the discussion after a Boss reply, with no repository work to follow.',
|
|
218
224
|
code:
|
|
219
|
-
'Analyst
|
|
225
|
+
'Analyst chose `code`: the existing decisions and spec items settle how the work is done. Output shall include `planningResult: <verbatim final text>`.',
|
|
220
226
|
decideThenCode:
|
|
221
|
-
'Analyst
|
|
227
|
+
'Analyst chose `decide then code`: the work turns on a point the specs leave open or contradict. Output shall include `planningResult: <verbatim final text>`.',
|
|
222
228
|
codeViaPullRequest:
|
|
223
|
-
'Analyst
|
|
229
|
+
'Analyst chose `code via pull request`: the existing decisions settle the work, and the request names a GitHub issue or explicitly asks for pull-request delivery. Output shall include `planningResult: <verbatim final text>`.',
|
|
224
230
|
decideThenCodeViaPullRequest:
|
|
225
|
-
'Analyst
|
|
231
|
+
'Analyst chose `decide then code via pull request`: the work turns on a point the specs leave open or contradict, and the request names a GitHub issue or explicitly asks for pull-request delivery. Output shall include `planningResult: <verbatim final text>`.',
|
|
226
232
|
needsBossReply:
|
|
227
233
|
"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>`.",
|
|
228
234
|
} as const;
|
|
229
235
|
|
|
230
236
|
const STATE_DESCRIPTIONS = {
|
|
231
237
|
ready: 'Waiting for a development request.',
|
|
232
|
-
planAnalysis:
|
|
233
|
-
'Analyst is analyzing the development request to choose the smallest sound next step.',
|
|
238
|
+
planAnalysis: 'Analyst is choosing the development path.',
|
|
234
239
|
createBranch:
|
|
235
240
|
'The BRANCH playbook is preparing the pull-request branch for the planned development path.',
|
|
236
241
|
callCode: 'The CODE playbook is implementing the planned development path.',
|
|
@@ -9,6 +9,7 @@ Roles:
|
|
|
9
9
|
|
|
10
10
|
`dev` is an optional repository-aware planner for a development request that needs more analysis before choosing a development path.
|
|
11
11
|
It coordinates existing playbooks and owns no repository commit itself.
|
|
12
|
+
Analyst chooses the path and states why in a short planning note; analysis, design, and implementation belong to the playbooks `dev` calls, and a question to Boss serves only the choice of path.
|
|
12
13
|
|
|
13
14
|
## Analyst
|
|
14
15
|
|
|
@@ -20,31 +21,37 @@ At the start of `dev` and after each Boss reply, Captain shall relay the develop
|
|
|
20
21
|
> > Prior discussion: <discussion-context>
|
|
21
22
|
> > Run results: <run-results>
|
|
22
23
|
>
|
|
23
|
-
>
|
|
24
|
+
> Plan which playbooks run for this request; the playbooks do the work.
|
|
25
|
+
> Read the request, then the specs and the repository only as far as choosing the path requires.
|
|
24
26
|
> Do not change files or commit while planning or discussing the request.
|
|
25
27
|
>
|
|
26
|
-
>
|
|
27
|
-
> - If the discussion has concluded after a Boss reply and no repository work should follow, choose `discussion complete`.
|
|
28
|
-
> - If implementation can proceed under the existing decisions, choose `code`.
|
|
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`.
|
|
28
|
+
> Choose exactly one:
|
|
31
29
|
>
|
|
30
|
+
> - `code`: the existing decisions and spec items settle how the work is done.
|
|
31
|
+
> - `decide then code`: the work turns on a rule, concept, term, shape, or trade-off the specs leave open or contradict; name what is open, do not settle it.
|
|
32
|
+
> - `code via pull request` or `decide then code via pull request`, in place of the two above, when the request names a GitHub issue (number or URL) or explicitly asks for pull-request delivery; read the issue and its comments (`gh issue view --comments` with the issue number) while choosing.
|
|
33
|
+
> - A question to Boss, only when the answer would change which path runs or whether any work is wanted: one short question naming the alternatives it decides between, and nothing else. When every answer leads to the same path, choose it; the playbook settles the open point.
|
|
34
|
+
> - `discussion complete`, after a Boss reply, when no repository work should follow.
|
|
35
|
+
>
|
|
36
|
+
> Your reply is the planning note the chosen playbook receives. It holds only the path and, in at most ten lines, why — the decisions and spec items that settle the work, or the open point a decision must settle — plus the scope the request implies and any fact from the issue the playbooks need.
|
|
37
|
+
> It holds no design, proposal, implementation instruction, or file-level finding: the playbooks own those.
|
|
38
|
+
> A reply that chooses a path asks Boss nothing; a reply that asks Boss chooses no path.
|
|
32
39
|
> A question or exploratory discussion is not by itself authorization to create a durable decision or implement changes.
|
|
33
|
-
> Do not choose `decide then code` merely because the work is large.
|
|
40
|
+
> Do not choose `decide then code` merely because the work is large, nor `code` merely because it is small.
|
|
34
41
|
> Consult @specs/map.md for relevant context and @specs/meta.md for spec requirements, if needed.
|
|
35
42
|
|
|
36
43
|
Results:
|
|
37
44
|
- `discussionComplete`: Analyst concluded the discussion after a Boss reply, with no repository work to follow.
|
|
38
|
-
- `code`: Analyst
|
|
39
|
-
- `decideThenCode`: Analyst
|
|
40
|
-
- `codeViaPullRequest`: Analyst
|
|
41
|
-
- `decideThenCodeViaPullRequest`: Analyst
|
|
45
|
+
- `code`: Analyst chose `code`: the existing decisions and spec items settle how the work is done. Output shall include `planningResult: <verbatim final text>`.
|
|
46
|
+
- `decideThenCode`: Analyst chose `decide then code`: the work turns on a point the specs leave open or contradict. Output shall include `planningResult: <verbatim final text>`.
|
|
47
|
+
- `codeViaPullRequest`: Analyst chose `code via pull request`: the existing decisions settle the work, and the request names a GitHub issue or explicitly asks for pull-request delivery. Output shall include `planningResult: <verbatim final text>`.
|
|
48
|
+
- `decideThenCodeViaPullRequest`: Analyst chose `decide then code via pull request`: the work turns on a point the specs leave open or contradict, and the request names a GitHub issue or explicitly asks for pull-request delivery. Output shall include `planningResult: <verbatim final text>`.
|
|
42
49
|
|
|
43
50
|
Workflow outcomes:
|
|
44
51
|
- 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.
|
|
45
52
|
- 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.
|
|
46
53
|
- 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.
|
|
47
|
-
- Discussion complete is available only after a Boss reply, when
|
|
54
|
+
- Discussion complete is available only after a Boss reply, when that reply settles that no repository work should follow; it completes `dev` without a child call or repository change.
|
|
48
55
|
- `dev` acts on the accepted outcome itself and does not return to the session Captain for another routing decision.
|
|
49
56
|
|
|
50
57
|
## Nested development paths
|
|
@@ -92,7 +92,7 @@ const runtimeSpec = {
|
|
|
92
92
|
roleStates: {
|
|
93
93
|
planAnalysis: {
|
|
94
94
|
role: 'analyst',
|
|
95
|
-
label: 'Analyst is
|
|
95
|
+
label: 'Analyst is choosing the development path.',
|
|
96
96
|
},
|
|
97
97
|
},
|
|
98
98
|
// DR-044: DEV owns no repository commit — every Analyst outcome is
|
|
@@ -179,8 +179,7 @@ const runtimeSpec = {
|
|
|
179
179
|
roleStates: {
|
|
180
180
|
planAnalysis: {
|
|
181
181
|
role: 'analyst',
|
|
182
|
-
label:
|
|
183
|
-
'Analyst is analyzing the development request to choose the smallest sound next step.',
|
|
182
|
+
label: 'Analyst is choosing the development path.',
|
|
184
183
|
},
|
|
185
184
|
},
|
|
186
185
|
// DR-044: DEV owns no repository commit — every Analyst outcome is
|
|
@@ -49,7 +49,7 @@ export function validateDevOptions(optionSlice) {
|
|
|
49
49
|
export const devPlaybookRegistryEntry = {
|
|
50
50
|
id: 'dev',
|
|
51
51
|
command: 'dev',
|
|
52
|
-
intent: '
|
|
52
|
+
intent: 'plan the development path for a request: direct implementation, or a durable decision first, delivered through a pull request when the request names a GitHub issue or asks for one',
|
|
53
53
|
artifactSchema: 3,
|
|
54
54
|
runtimeProfile: Object.freeze({
|
|
55
55
|
kind: 'shared-factory',
|
|
@@ -104,7 +104,7 @@ export const devPlaybookRegistryEntry: DevPlaybookRegistryEntry = {
|
|
|
104
104
|
id: 'dev',
|
|
105
105
|
command: 'dev',
|
|
106
106
|
intent:
|
|
107
|
-
'
|
|
107
|
+
'plan the development path for a request: direct implementation, or a durable decision first, delivered through a pull request when the request names a GitHub issue or asks for one',
|
|
108
108
|
artifactSchema: 3,
|
|
109
109
|
runtimeProfile: Object.freeze({
|
|
110
110
|
kind: 'shared-factory',
|
|
@@ -278,7 +278,7 @@ export declare const prMachine: import("xstate").StateMachine<PrContext, {
|
|
|
278
278
|
} | {
|
|
279
279
|
type: "resumesOpenPullRequest";
|
|
280
280
|
params: unknown;
|
|
281
|
-
}, never, "failed" | "
|
|
281
|
+
}, never, "failed" | "ready" | "awaitBossReply" | "openPullRequest" | "waitForChecks" | "fixChecks" | "publishFix" | "waitForChecksAfterFix" | "mergePullRequest" | "updateLocalDefault" | "notPublished" | "fixNotPublished" | "checksStillFailing" | "merged" | "mergeRefused" | "mergedLocalBehind" | "fixFailed", string, Readonly<Record<never, never>>, {
|
|
282
282
|
readonly status: "merged";
|
|
283
283
|
/** The pull request number, exactly as Coder reported it. */
|
|
284
284
|
readonly pullRequest: string;
|
|
@@ -169,7 +169,7 @@ export declare const reviewMachine: import("xstate").StateMachine<ReviewContext,
|
|
|
169
169
|
} | {
|
|
170
170
|
type: "restartInitialReview";
|
|
171
171
|
params: unknown;
|
|
172
|
-
}, never, "done" | "failed" | "
|
|
172
|
+
}, never, "done" | "failed" | "ready" | "awaitBossReply" | "reviewInitial" | "addressFindings" | "reviewAfterCommit" | "reviewAfterRebuttal", string, Readonly<Record<string, never>>, ReviewOutput, import("xstate").EventObject, import("xstate").MetaObject, {
|
|
173
173
|
id: "review";
|
|
174
174
|
states: {
|
|
175
175
|
readonly ready: {
|
package/slc/link.md
CHANGED
|
@@ -247,10 +247,36 @@ type JsonValue =
|
|
|
247
247
|
| readonly JsonValue[]
|
|
248
248
|
| { readonly [key: string]: JsonValue };
|
|
249
249
|
|
|
250
|
+
// DR-063: the closed failure-cause contract. `code` is one of
|
|
251
|
+
// PLAYBOOK_FAILURE_CODES and `evidence` holds exactly the members that code
|
|
252
|
+
// names — repository paths, dispositions, classifications, and revisions, never
|
|
253
|
+
// content or internal identity.
|
|
254
|
+
type PlaybookFailureCode =
|
|
255
|
+
| 'commit-missing'
|
|
256
|
+
| 'commit-residual'
|
|
257
|
+
| 'pre-existing-lost'
|
|
258
|
+
| 'commits-more-than-one'
|
|
259
|
+
| 'history-rewritten'
|
|
260
|
+
| 'foreign-change'
|
|
261
|
+
| 'observation-unstable'
|
|
262
|
+
| 'attribution-ambiguous'
|
|
263
|
+
| 'receipt-missing'
|
|
264
|
+
| 'judge-failed'
|
|
265
|
+
| 'player-failed'
|
|
266
|
+
| 'aborted'
|
|
267
|
+
| 'child-failed'
|
|
268
|
+
| 'runtime-defect';
|
|
269
|
+
|
|
270
|
+
interface PlaybookFailureCause {
|
|
271
|
+
readonly code: PlaybookFailureCode;
|
|
272
|
+
readonly evidence: PlaybookFailureEvidence;
|
|
273
|
+
}
|
|
274
|
+
|
|
250
275
|
interface NormalizedError {
|
|
251
276
|
name: string;
|
|
252
277
|
message: string;
|
|
253
278
|
stack?: string;
|
|
279
|
+
cause?: PlaybookFailureCause; // present when the error carried a valid one
|
|
254
280
|
}
|
|
255
281
|
|
|
256
282
|
type PlaybookStateValue =
|
|
@@ -2045,9 +2071,15 @@ parked-session snapshot capability; the pair changes no runtime ABI and no
|
|
|
2045
2071
|
artifact or snapshot schema.
|
|
2046
2072
|
|
|
2047
2073
|
```typescript
|
|
2074
|
+
type PlaybookControlStanding = 'ready' | 'no-op' | 'blocked';
|
|
2075
|
+
type PlaybookControlActionReason = 'receipt-complete';
|
|
2076
|
+
|
|
2048
2077
|
interface PlaybookControlAction {
|
|
2049
2078
|
id: string; // stable within the returned view
|
|
2050
2079
|
label: string; // runtime-written, Boss-appropriate
|
|
2080
|
+
standing?: PlaybookControlStanding; // what running it would do (DR-063);
|
|
2081
|
+
// absent reads as `ready`
|
|
2082
|
+
reason?: PlaybookControlActionReason; // why it is not `ready`
|
|
2051
2083
|
}
|
|
2052
2084
|
|
|
2053
2085
|
interface PlaybookControlView {
|
package/src/runtime.d.ts
CHANGED
|
@@ -32,10 +32,65 @@ export interface CaptainResult {
|
|
|
32
32
|
export type JsonValue = null | boolean | number | string | readonly JsonValue[] | {
|
|
33
33
|
readonly [key: string]: JsonValue;
|
|
34
34
|
};
|
|
35
|
+
export declare const PLAYBOOK_FAILURE_CODES: readonly ["commit-missing", "commit-residual", "pre-existing-lost", "commits-more-than-one", "history-rewritten", "foreign-change", "observation-unstable", "attribution-ambiguous", "receipt-missing", "judge-failed", "player-failed", "aborted", "child-failed", "runtime-defect"];
|
|
36
|
+
export type PlaybookFailureCode = (typeof PLAYBOOK_FAILURE_CODES)[number];
|
|
37
|
+
/** The bounded path lists one failure code's evidence may carry (DR-063 §1). */
|
|
38
|
+
export interface PlaybookFailurePaths {
|
|
39
|
+
/** Paths changed in the worktree that no commit carries. */
|
|
40
|
+
readonly uncommitted?: readonly string[];
|
|
41
|
+
/** Pre-existing baseline paths the call changed before committing. */
|
|
42
|
+
readonly altered?: readonly string[];
|
|
43
|
+
/** Pre-existing baseline paths whose content is nowhere. */
|
|
44
|
+
readonly lost?: readonly string[];
|
|
45
|
+
/** Paths whose entry differs or is missing on either side. */
|
|
46
|
+
readonly changed?: readonly string[];
|
|
47
|
+
/** Paths omitted from the lists above by the 32-path bound. */
|
|
48
|
+
readonly truncated?: number;
|
|
49
|
+
}
|
|
50
|
+
/** The bounded error record a failure cause may carry (DR-063 §1). */
|
|
51
|
+
export interface PlaybookFailureErrorEvidence {
|
|
52
|
+
readonly name: string;
|
|
53
|
+
readonly message: string;
|
|
54
|
+
}
|
|
55
|
+
/** The closed evidence object of one failure cause (DR-063 §1). */
|
|
56
|
+
export interface PlaybookFailureEvidence {
|
|
57
|
+
readonly required?: PlaybookRepositoryDisposition;
|
|
58
|
+
readonly observed?: PlaybookRepositoryReceipt['classification'];
|
|
59
|
+
readonly baselineHead?: string;
|
|
60
|
+
readonly afterHead?: string;
|
|
61
|
+
readonly commitOid?: string;
|
|
62
|
+
readonly paths?: PlaybookFailurePaths;
|
|
63
|
+
readonly reason?: string;
|
|
64
|
+
readonly error?: PlaybookFailureErrorEvidence;
|
|
65
|
+
readonly errorCode?: string;
|
|
66
|
+
readonly roleId?: string;
|
|
67
|
+
readonly playerId?: string;
|
|
68
|
+
readonly playbookId?: string;
|
|
69
|
+
readonly cause?: PlaybookFailureCause;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Why a parked workflow failed (DR-063 §1): one code from the closed list and
|
|
73
|
+
* the closed evidence object that code names. Evidence holds repository paths,
|
|
74
|
+
* dispositions, classifications, and revision identities only — never file
|
|
75
|
+
* content, player prose, or internal call and session identities.
|
|
76
|
+
*/
|
|
77
|
+
export interface PlaybookFailureCause {
|
|
78
|
+
readonly code: PlaybookFailureCode;
|
|
79
|
+
readonly evidence: PlaybookFailureEvidence;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Validate, detach, and freeze one failure cause (DR-063 §1). The check is
|
|
83
|
+
* closed per code: exactly the evidence members that code names, nothing else,
|
|
84
|
+
* and a `child-failed` cause nests at most four deep. A value this rejects is
|
|
85
|
+
* not a cause, so a caller omits it rather than publishing an invented one.
|
|
86
|
+
*/
|
|
87
|
+
export declare function assertPlaybookFailureCause(value: unknown): PlaybookFailureCause;
|
|
35
88
|
export interface NormalizedError {
|
|
36
89
|
name: string;
|
|
37
90
|
message: string;
|
|
38
91
|
stack?: string;
|
|
92
|
+
/** DR-063 §2: present exactly when the underlying error carried a valid one. */
|
|
93
|
+
cause?: PlaybookFailureCause;
|
|
39
94
|
}
|
|
40
95
|
export type PlaybookStateValue = string | {
|
|
41
96
|
readonly [key: string]: PlaybookStateValue;
|
|
@@ -181,12 +236,23 @@ export interface PlaybookRepositoryObservation {
|
|
|
181
236
|
readonly projection: Readonly<Record<string, JsonValue>>;
|
|
182
237
|
readonly projectionDigest: string;
|
|
183
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* The fate of the baseline projection entries a governed call absorbed into
|
|
241
|
+
* its one commit, altered, or lost (DR-062). Each list holds sorted unique
|
|
242
|
+
* baseline paths and the three are pairwise disjoint.
|
|
243
|
+
*/
|
|
244
|
+
export interface PlaybookRepositoryPreExistingChanges {
|
|
245
|
+
readonly absorbed: readonly string[];
|
|
246
|
+
readonly altered: readonly string[];
|
|
247
|
+
readonly lost: readonly string[];
|
|
248
|
+
}
|
|
184
249
|
/** The fail-closed classification of one complete physical or logical receipt. */
|
|
185
250
|
export interface PlaybookRepositoryReceipt {
|
|
186
251
|
readonly classification: 'unchanged' | 'one-descendant-commit' | 'multiple-commits' | 'rewritten-or-non-descendant' | 'worktree-only-change' | 'concurrent-or-foreign-change' | 'observation-ambiguous';
|
|
187
252
|
readonly baseline: PlaybookRepositoryObservation;
|
|
188
253
|
readonly after?: PlaybookRepositoryObservation;
|
|
189
254
|
readonly commitOid?: string;
|
|
255
|
+
readonly preExisting?: PlaybookRepositoryPreExistingChanges;
|
|
190
256
|
}
|
|
191
257
|
/** One durably ordered physical governed-player boundary (DR-040). */
|
|
192
258
|
export interface PlaybookEffectBoundary {
|
|
@@ -324,9 +390,13 @@ export interface PlaybookRuntimeSnapshot {
|
|
|
324
390
|
};
|
|
325
391
|
suspendedCall?: PlaybookSuspendedCall;
|
|
326
392
|
}
|
|
393
|
+
export type PlaybookControlStanding = 'ready' | 'no-op' | 'blocked';
|
|
394
|
+
export type PlaybookControlActionReason = 'receipt-complete';
|
|
327
395
|
export interface PlaybookControlAction {
|
|
328
396
|
id: string;
|
|
329
397
|
label: string;
|
|
398
|
+
standing?: PlaybookControlStanding;
|
|
399
|
+
reason?: PlaybookControlActionReason;
|
|
330
400
|
}
|
|
331
401
|
export interface PlaybookControlView {
|
|
332
402
|
state: PlaybookState;
|