@sublang/playbook 14.1.0 → 15.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.
Files changed (32) hide show
  1. package/README.md +2 -2
  2. package/docs/configuration.md +15 -9
  3. package/docs/embedding.md +7 -5
  4. package/package.json +3 -1
  5. package/reference/sdlc/code.md +1 -1
  6. package/reference/sdlc/code.playbook/bin/launch-config.js +55 -16
  7. package/reference/sdlc/code.playbook/bin/playbook.js +14 -9
  8. package/reference/sdlc/code.playbook/bin/repository-effects.js +54 -13
  9. package/reference/sdlc/code.playbook/bin/run.js +12 -8
  10. package/reference/sdlc/code.playbook/code.fsm.js +1 -1
  11. package/reference/sdlc/code.playbook/code.fsm.ts +1 -1
  12. package/reference/sdlc/code.playbook/code.gears.md +2 -2
  13. package/reference/sdlc/decide.md +1 -1
  14. package/reference/sdlc/decide.playbook/decide.fsm.js +1 -1
  15. package/reference/sdlc/decide.playbook/decide.fsm.ts +1 -1
  16. package/reference/sdlc/decide.playbook/decide.gears.md +1 -1
  17. package/reference/sdlc/decide.playbook/decide.playbook.d.ts +1 -9
  18. package/reference/sdlc/decide.playbook/decide.playbook.js +158 -32
  19. package/reference/sdlc/decide.playbook/decide.playbook.ts +229 -46
  20. package/reference/sdlc/review.md +1 -1
  21. package/reference/sdlc/review.playbook/review.fsm.js +1 -1
  22. package/reference/sdlc/review.playbook/review.fsm.ts +1 -1
  23. package/reference/sdlc/review.playbook/review.gears.md +1 -1
  24. package/slc/prefix-prompts.mjs +190 -0
  25. package/slc/prefix.md +200 -0
  26. package/slc/slc.pin-inputs.json +1 -0
  27. package/src/xstate-playbook-runtime.d.ts +35 -1
  28. package/src/xstate-playbook-runtime.js +82 -47
  29. package/src/xstate-playbook-runtime.ts +107 -60
  30. package/src/xstate-runtime.d.ts +3 -1
  31. package/src/xstate-runtime.js +9 -2
  32. package/src/xstate-runtime.ts +12 -2
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env node
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
4
+
5
+ // Deterministic realization of the prompt-prefix pass (slc/prefix.md): every
6
+ // standalone relay block of an eligible item moves after its last instruction
7
+ // line, byte-for-byte, and one `## Prefixed prompts` section at the end lists
8
+ // the items this and every earlier application rewrote. `--keep <ITEM-ID>`
9
+ // excludes an item the pass judged ineligible; the tool never modifies the
10
+ // source.
11
+
12
+ import { readFile, writeFile } from 'node:fs/promises';
13
+ import { resolve } from 'node:path';
14
+ import { fileURLToPath } from 'node:url';
15
+
16
+ const HEADING = /^#{1,3}\s/;
17
+ const ITEM_HEADING = /^###\s+([^\s]+)\s*$/;
18
+ const PROMPT_LINE = /^>\s?(.*)$/;
19
+ const SECTION = '## Prefixed prompts';
20
+ const SECTION_HEADING = /^##\s+Prefixed prompts\s*$/;
21
+ const LISTED = /^-\s+([^\s:]+):\s+relays → tail\s*$/;
22
+ const bullet = (id) => `- ${id}: relays → tail`;
23
+
24
+ /** Classify one prompt line by its content inside the outer blockquote marker. */
25
+ function classify(line) {
26
+ const inner = PROMPT_LINE.exec(line)[1];
27
+ if (inner === '') return 'blank';
28
+ return inner.startsWith('>') ? 'relay' : 'instruction';
29
+ }
30
+
31
+ /**
32
+ * Rewrite one blockquote (its raw `> …` file lines). Returns the new lines, or
33
+ * null when no relay block precedes an instruction line.
34
+ */
35
+ function prefixBlockquote(quote) {
36
+ const kinds = quote.map(classify);
37
+ // A relay block is a maximal run of relay lines bounded by blank lines or
38
+ // the blockquote edges; a relay line adjacent to an instruction line is
39
+ // authored content of that instruction and stays with it.
40
+ const inBlock = new Array(quote.length).fill(false);
41
+ for (let start = 0; start < quote.length; ) {
42
+ if (kinds[start] !== 'relay') {
43
+ start++;
44
+ continue;
45
+ }
46
+ let end = start;
47
+ while (end < quote.length && kinds[end] === 'relay') end++;
48
+ const boundedBefore = start === 0 || kinds[start - 1] === 'blank';
49
+ const boundedAfter = end === quote.length || kinds[end] === 'blank';
50
+ if (boundedBefore && boundedAfter) inBlock.fill(true, start, end);
51
+ start = end;
52
+ }
53
+ const firstBlock = inBlock.indexOf(true);
54
+ if (firstBlock === -1) return null;
55
+ const lastInstruction = Math.max(
56
+ ...kinds.map((kind, index) =>
57
+ kind === 'blank' || inBlock[index] ? -1 : index,
58
+ ),
59
+ );
60
+ if (lastInstruction < firstBlock) return null; // relays already trail
61
+
62
+ // Instruction lines keep their order and their authored blank lines; a
63
+ // removed block takes the blank lines bounding it and leaves the first of
64
+ // them where it separated two remaining lines, and none leads or trails the
65
+ // region.
66
+ const removed = [...inBlock];
67
+ inBlock.forEach((inside, index) => {
68
+ if (!inside) return;
69
+ for (let at = index - 1; at >= 0 && kinds[at] === 'blank'; at--) removed[at] = true;
70
+ for (let at = index + 1; at < quote.length && kinds[at] === 'blank'; at++) removed[at] = true;
71
+ });
72
+ const statics = [];
73
+ let separator;
74
+ for (let index = 0; index < quote.length; index++) {
75
+ if (removed[index]) {
76
+ separator ??= quote[index];
77
+ continue;
78
+ }
79
+ if (statics.length === 0 && kinds[index] === 'blank') continue;
80
+ if (separator !== undefined && statics.length > 0) statics.push(separator);
81
+ separator = undefined;
82
+ statics.push(quote[index]);
83
+ }
84
+ while (statics.length > 0 && classify(statics[statics.length - 1]) === 'blank') {
85
+ statics.pop();
86
+ }
87
+ const blocks = [];
88
+ for (let index = 0; index < quote.length; index++) {
89
+ if (!inBlock[index]) continue;
90
+ if (index === 0 || !inBlock[index - 1]) blocks.push([]);
91
+ blocks[blocks.length - 1].push(quote[index]);
92
+ }
93
+ const relays = blocks.flatMap((block, index) =>
94
+ index === 0 ? block : ['>', ...block],
95
+ );
96
+ return [...statics, '>', ...relays];
97
+ }
98
+
99
+ /**
100
+ * Rewrite every eligible item of a GEARS package not named by `keep`.
101
+ * Returns the rewritten text with its provenance section, or the source text
102
+ * unchanged when no item was eligible, plus the rewritten item ids.
103
+ */
104
+ export function prefixPrompts(text, { keep = [] } = {}) {
105
+ // Keep the source's own line-ending convention so untouched lines stay bytes.
106
+ const newline = text.includes('\r\n') ? '\r\n' : '\n';
107
+ const lines = text.split(/\r?\n/);
108
+ const starts = [];
109
+ lines.forEach((line, index) => {
110
+ const match = ITEM_HEADING.exec(line);
111
+ if (match !== null) starts.push({ index, id: match[1] });
112
+ });
113
+ const out = [];
114
+ let cursor = 0;
115
+ const rewritten = [];
116
+ for (const start of starts) {
117
+ let end = start.index + 1;
118
+ while (end < lines.length && !HEADING.test(lines[end])) end++;
119
+ let quoteStart = start.index + 1;
120
+ while (quoteStart < end && !PROMPT_LINE.test(lines[quoteStart])) quoteStart++;
121
+ if (quoteStart === end) continue;
122
+ let quoteEnd = quoteStart;
123
+ while (quoteEnd < end && PROMPT_LINE.test(lines[quoteEnd])) quoteEnd++;
124
+ // A script item's blockquote is shell text, not a prompt (optimize.md).
125
+ const acting = lines.slice(start.index + 1, quoteStart).join(' ');
126
+ if (/\bCaptain shall run:/.test(acting) || keep.includes(start.id)) continue;
127
+ const replaced = prefixBlockquote(lines.slice(quoteStart, quoteEnd));
128
+ if (replaced === null) continue;
129
+ out.push(...lines.slice(cursor, quoteStart), ...replaced);
130
+ cursor = quoteEnd;
131
+ rewritten.push(start.id);
132
+ }
133
+ if (rewritten.length === 0) return { text, rewritten };
134
+ out.push(...lines.slice(cursor));
135
+ // One provenance section follows every other section, ending in one newline;
136
+ // it replaces every section an earlier application appended and lists, in
137
+ // item order, each item this or that application rewrote.
138
+ const listed = new Set(rewritten);
139
+ for (let index = out.length - 1; index >= 0; index--) {
140
+ if (!SECTION_HEADING.test(out[index])) continue;
141
+ let end = index + 1;
142
+ for (; end < out.length && !HEADING.test(out[end]); end++) {
143
+ const entry = LISTED.exec(out[end]);
144
+ if (entry !== null) listed.add(entry[1]);
145
+ }
146
+ out.splice(index, end - index);
147
+ }
148
+ while (out.length > 0 && out[out.length - 1] === '') out.pop();
149
+ const ids = starts.map((start) => start.id).filter((id) => listed.has(id));
150
+ out.push('', SECTION, '', ...ids.map(bullet), '');
151
+ return { text: out.join(newline), rewritten };
152
+ }
153
+
154
+ async function main(argv) {
155
+ let source;
156
+ let target;
157
+ const keep = [];
158
+ for (let index = 0; index < argv.length; index++) {
159
+ const flag = argv[index];
160
+ const value = argv[index + 1];
161
+ if (value === undefined || value.startsWith('--')) {
162
+ throw new Error(`${flag} needs a value`);
163
+ }
164
+ if (flag === '--source') source = value;
165
+ else if (flag === '--target') target = value;
166
+ else if (flag === '--keep') keep.push(value);
167
+ else throw new Error(`unknown argument ${flag}`);
168
+ index++;
169
+ }
170
+ if (source === undefined || target === undefined) {
171
+ throw new Error(
172
+ 'usage: prefix-prompts.mjs --source <gears.md> --target <gears.md> [--keep <ITEM-ID>]...',
173
+ );
174
+ }
175
+ const { text, rewritten } = prefixPrompts(await readFile(resolve(source), 'utf8'), { keep });
176
+ await writeFile(resolve(target), text);
177
+ process.stdout.write(
178
+ rewritten.length === 0
179
+ ? 'no eligible item; target equals source\n'
180
+ : `${rewritten.join('\n')}\n`,
181
+ );
182
+ }
183
+
184
+ const invokedPath = process.argv[1] === undefined ? undefined : resolve(process.argv[1]);
185
+ if (invokedPath === fileURLToPath(import.meta.url)) {
186
+ main(process.argv.slice(2)).catch((error) => {
187
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
188
+ process.exitCode = 1;
189
+ });
190
+ }
package/slc/prefix.md ADDED
@@ -0,0 +1,200 @@
1
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
2
+ <!-- SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai> -->
3
+
4
+ # GEARS Prompt-Prefix Pass
5
+
6
+ Optional optimization pass of a playbook (a state-machine agent orchestrating
7
+ other agents).
8
+ Reorders each acting prompt so that its static instructions come first and the
9
+ runtime values relayed into it come last, giving every run of the same item an
10
+ identical prompt prefix that an LLM provider's prompt cache can serve.
11
+
12
+ - Source: a package of GEARS spec items produced by [text2gears](text2gears.md)
13
+ and, when scheduled, already rewritten by [optimize](optimize.md).
14
+ - Target: the same package with eligible prompts laid out prefix-first.
15
+
16
+ The pass is format-preserving: source and target are both GEARS packages, and
17
+ the pass sits between [text2gears](text2gears.md) and
18
+ [gears2fsm](gears2fsm.md), after [optimize](optimize.md) by pass-name order.
19
+ A playbook compiled without this pass has identical observable behavior; the
20
+ pass trades a compile-time rewrite for cheaper prompt processing at run time.
21
+
22
+ Prompt caches are prefix caches: a provider serves the longest prefix it has
23
+ already seen and processes everything after the first differing token afresh
24
+ [[1]], [[2]], [[3]].
25
+ A prompt that opens with this run's relayed request therefore shares nothing
26
+ with the previous run's prompt for the same item, while one that opens with
27
+ the item's instructions shares them all.
28
+
29
+ ## Formats
30
+
31
+ | Role | Format | Extension |
32
+ | ------ | ------ | --------- |
33
+ | source | gears | .md |
34
+ | target | gears | .md |
35
+
36
+ ## Prompt regions
37
+
38
+ Within an item's blockquote, each prompt line is one of:
39
+
40
+ - a **relay line** — prompt content that begins with the literal quote marker
41
+ `>` (written `> > …` in the GEARS file), which is how
42
+ [text2gears](text2gears.md#authored-prompt-fragments) relays a runtime value
43
+ such as `> Original request: <caller-input>`;
44
+ - a **blank line** — an empty prompt line, written `>`;
45
+ - an **instruction line** — any other prompt line.
46
+
47
+ A **relay block** is a maximal run of consecutive relay lines bounded by blank
48
+ lines or the blockquote's edges, whether Source authored it as a separate
49
+ quoted relay or set it apart with blank lines inside a fenced instruction.
50
+ A relay line adjacent to an instruction line is authored content of that
51
+ instruction — a quoted example inside a fenced instruction, for instance — and
52
+ belongs to the instruction, not to a relay block.
53
+
54
+ An instruction line may carry an inline `<placeholder>`, such as a configured
55
+ model name; the pass never splits or rewrites an instruction line to isolate
56
+ it.
57
+
58
+ ## Eligibility
59
+
60
+ The pass shall rewrite an item only when **all** of the following hold:
61
+
62
+ - The item is an acting item with a prompt: a direct-Captain, delegated-role,
63
+ or nested-playbook-call blockquote.
64
+ A script item (`Captain shall run:`) has no prompt and is never rewritten.
65
+ - At least one relay block precedes an instruction line.
66
+ An item whose relay blocks already trail every instruction line is already
67
+ prefix-first and stays unchanged.
68
+ - No instruction line depends on a relayed value standing before it — one
69
+ that refers to the relayed text as above or preceding, or that continues a
70
+ sentence the relay began.
71
+ A reference to the relayed text as below or following stays true after the
72
+ move.
73
+
74
+ Judgment stays conservative: when eligibility is uncertain, the pass shall
75
+ leave the item unchanged rather than guess.
76
+ The pass shall not invent prompt lines, labels, or separators, and shall not
77
+ rewrite, merge, split, or drop any line.
78
+
79
+ Source prose that places a relay after an instruction, or an instruction at
80
+ the end of the prompt, tells [text2gears](text2gears.md) how to compose the
81
+ prompt faithfully; it does not make the item ineligible.
82
+ This pass overrides that composition order by design, records the override in
83
+ its provenance section, and `--no-optimize` restores it.
84
+
85
+ ## Rewriting
86
+
87
+ For each eligible item, the pass shall rewrite only the blockquote:
88
+
89
+ - Emit every line that is not part of a relay block, in its original order,
90
+ keeping each line byte-for-byte, dropping leading and trailing blank lines,
91
+ and replacing each run of removed relay blocks together with the blank lines
92
+ bounding it by the first of those blank lines where it separated two
93
+ remaining lines; every other blank line, such as one inside a fenced
94
+ template, stays where it is.
95
+ - Emit one blank line.
96
+ - Emit the relay blocks in their original order, each byte-for-byte, with one
97
+ blank line between consecutive blocks.
98
+ - Keep the item's ID, heading, condition, acting clause, `Results:`, and any
99
+ other metadata unchanged.
100
+ - Preserve every other item and every non-item section byte-for-byte,
101
+ including an `## Optimizations` section the optimize pass appended.
102
+
103
+ Because no line changes, the target stays in the Source language and every
104
+ authored fragment remains intact; only the order of relay blocks relative to
105
+ instructions changes.
106
+
107
+ E.g., the source item
108
+
109
+ ```markdown
110
+ ### REVIEW-2
111
+
112
+ When Reviewer raises or keeps any finding, Captain shall relay the caller input and Reviewer's findings to Coder with the disposition prompt:
113
+
114
+ > > Original request: <caller-input>
115
+ > > Reviewer findings: <reviewer-output>
116
+ >
117
+ > For each review item, accept or reject it.
118
+ > Report every disposition, all relevant run results, and every rebuttal.
119
+
120
+ Results:
121
+ - `committed`: Coder accepted at least one item and added one new review-fix commit. Output shall include `coderOutput: <verbatim final text>` and `latestCommit: <commit identity>`.
122
+ - `rejectedAll`: Coder rejected every item and made no commit. Output shall include `coderOutput: <verbatim final text>`.
123
+ ```
124
+
125
+ becomes
126
+
127
+ ```markdown
128
+ ### REVIEW-2
129
+
130
+ When Reviewer raises or keeps any finding, Captain shall relay the caller input and Reviewer's findings to Coder with the disposition prompt:
131
+
132
+ > For each review item, accept or reject it.
133
+ > Report every disposition, all relevant run results, and every rebuttal.
134
+ >
135
+ > > Original request: <caller-input>
136
+ > > Reviewer findings: <reviewer-output>
137
+
138
+ Results:
139
+ - `committed`: Coder accepted at least one item and added one new review-fix commit. Output shall include `coderOutput: <verbatim final text>` and `latestCommit: <commit identity>`.
140
+ - `rejectedAll`: Coder rejected every item and made no commit. Output shall include `coderOutput: <verbatim final text>`.
141
+ ```
142
+
143
+ ## Provenance
144
+
145
+ The target shall end with one `## Prefixed prompts` section — after an
146
+ `## Optimizations` section when one is present — listing every rewritten
147
+ item, one bullet per item in item order: `- <ITEM-ID>: relays → tail`.
148
+ A section an earlier application left in the source is replaced, and the
149
+ items it listed stay listed.
150
+ When no item is eligible, the target shall be the source content unchanged;
151
+ a package the pass never rewrote carries no `## Prefixed prompts` section.
152
+
153
+ The section is what lets a Source-to-GEARS fidelity checker accept the new
154
+ order: for a listed item it requires each instruction and relay block of the
155
+ fragments the item carries intact, blank lines inside a block included, and
156
+ used exactly once, the instruction blocks in Source order, the relay blocks in
157
+ Source order, and every relay after the last instruction, a relay Source joined
158
+ directly to an instruction staying beside it with its authored boundary, a bare
159
+ relay the prose authored free to trail, and one occurrence standing for one
160
+ authored fragment; for any other item it requires Source order throughout.
161
+
162
+ ## Deterministic rewriting
163
+
164
+ The adjacent `prefix-prompts.mjs` tool performs this rewrite exactly:
165
+
166
+ ```sh
167
+ node "<definition-directory>/prefix-prompts.mjs" --source "<source.gears.md>" --target "<target.gears.md>" [--keep <ITEM-ID>]...
168
+ ```
169
+
170
+ It reads the source, rewrites every item eligible by the mechanical rules
171
+ above, writes the one provenance section and the target, and prints the
172
+ rewritten item IDs — or reports that no item was eligible and the target
173
+ equals the source.
174
+ `--keep` excludes an item the tool would otherwise rewrite.
175
+
176
+ The pass shall use the tool rather than rewrite by hand:
177
+
178
+ 1. Read the source and decide, for each item with a relay block preceding an
179
+ instruction line, whether an instruction depends on a relay standing before
180
+ it; that judgment is the pass's only non-mechanical step.
181
+ 2. Run the tool with `--keep` for each item so excluded.
182
+ 3. Read the target and confirm that every listed item's instructions and
183
+ relays are intact and that nothing else changed.
184
+
185
+ The tool writes only the declared target and never modifies the source.
186
+
187
+ ## Out of scope
188
+
189
+ - Any change to prompt wording, conditions, result contracts, or item order.
190
+ - Rewriting behaviors into one another; that is the [optimize](optimize.md)
191
+ pass.
192
+ - Where a transport sends a prompt as one content block, the provider's cache
193
+ boundary is the transport's concern; this pass only makes the shared prefix
194
+ exist.
195
+
196
+ ## References
197
+
198
+ [1]: https://platform.claude.com/docs/en/docs/build-with-claude/prompt-caching "Anthropic — Prompt caching: place static content at the beginning of the prompt"
199
+ [2]: https://developers.openai.com/api/docs/guides/prompt-caching "OpenAI — Prompt caching: put stable instructions first, dynamic content at the end"
200
+ [3]: https://ai.google.dev/gemini-api/docs/caching "Google — Gemini context caching: put large and common contents at the beginning of the prompt"
@@ -2,6 +2,7 @@
2
2
  "schema": "sublang.slc.pin-inputs.v1",
3
3
  "closures": {
4
4
  "gears2fsm": ["text2gears.md", "link.md", "workflow-contracts.json"],
5
+ "prefix": ["prefix-prompts.mjs"],
5
6
  "link": [
6
7
  "text2gears.md",
7
8
  "gears2fsm.md",
@@ -1,5 +1,5 @@
1
1
  import type { AnyStateMachine, EventObject, PromiseActorLogic } from 'xstate';
2
- import type { CaptainResult, JsonValue, PlaybookEffectBoundary, PlaybookEffectBoundaryStart, PlaybookEffectLedger, PlaybookEffectLedgerCapability, NormalizedError, PlaybookPendingBossQuestion, PlaybookPorts, PlaybookRepositoryReceipt, PlaybookRuntimeFactory, PlaybookSession, PlaybookState, PlayerResult } from './runtime.js';
2
+ import type { CaptainResult, JsonValue, PlaybookEffectBoundary, PlaybookEffectBoundaryStart, PlaybookEffectLedger, PlaybookEffectLedgerCapability, NormalizedError, PlaybookFailureCause, PlaybookPendingBossQuestion, PlaybookPorts, PlaybookRepositoryReceipt, PlaybookRuntimeFactory, PlaybookSession, PlaybookState, PlayerResult } from './runtime.js';
3
3
  export interface PlaybookPendingBossQuestionContext {
4
4
  questionId: string;
5
5
  resumeStateId: string;
@@ -115,6 +115,33 @@ export declare const BOSS_REPLY_ERRORS: {
115
115
  readonly missingQuestion: "needsBossReply outcome missing 'question' field";
116
116
  readonly unregisteredState: (stateId: string) => string;
117
117
  };
118
+ export declare const ABORTED_FAILURE_CAUSE: PlaybookFailureCause;
119
+ export declare function runtimeDefectCause(reason: string): PlaybookFailureCause;
120
+ export declare function playerFailureCause(input: {
121
+ readonly roleId: string;
122
+ readonly playerId?: string;
123
+ readonly error: unknown;
124
+ }): PlaybookFailureCause;
125
+ /**
126
+ * DR-063 §1: the cause of an unresolved governed settlement. A reconciled
127
+ * mismatch supplies its own receipt-read cause; the reasons a runtime owns map
128
+ * to adjudication, abort, and runtime-defect codes. Shared with DECIDE's
129
+ * bespoke runtime, which decides the same reasons.
130
+ */
131
+ export declare function governedSettlementCause(reason: string, error: unknown, aborted: boolean, supplied: PlaybookFailureCause | undefined): PlaybookFailureCause;
132
+ /**
133
+ * DR-063 §2: the causes decided for thrown values that cannot carry the
134
+ * marker — a string, a frozen error — kept by identity for as long as the
135
+ * failure stands, so every surface that reads the FSM's own `lastError`
136
+ * publishes the cause decided for exactly that value, whatever turn reads it.
137
+ * A value that carries the marker answers from it; the map is bounded, since
138
+ * only values that refuse the marker need an entry.
139
+ */
140
+ export interface PlaybookFailureCauseRetention {
141
+ retain(error: unknown, cause: PlaybookFailureCause): void;
142
+ causeOf(error: unknown): PlaybookFailureCause | undefined;
143
+ }
144
+ export declare function createFailureCauseRetention(): PlaybookFailureCauseRetention;
118
145
  interface XStateRepositoryOperationSettlement<T> {
119
146
  readonly status: 'fulfilled';
120
147
  readonly value: T;
@@ -389,6 +416,13 @@ export declare function normalizeErrorFull(err: unknown): NormalizedError | unde
389
416
  export declare function pendingBossQuestionFromContext(context: Record<string, unknown>): PlaybookPendingBossQuestionContext | undefined;
390
417
  /** Add clarification context without repeating the question in a live conversation. */
391
418
  export declare function composePlayerContinuation(input: Pick<PlaybookPlayerInput, 'pendingBossQuestion' | 'bossReply'>, body: string, resuming?: boolean): string;
419
+ /**
420
+ * The block for one governed call, or `undefined` where the call is not
421
+ * effect-authorized — a call whose declared outcomes carry no
422
+ * `one-descendant-commit` disposition may commit nothing, so it is told
423
+ * nothing.
424
+ */
425
+ export declare function effectAuthorizedPreExistingBlock(effectBoundary: Pick<PlaybookEffectBoundaryStart, 'dispositions'>, baseline: PlaybookRepositoryReceipt['baseline'] | undefined): string | undefined;
392
426
  /**
393
427
  * Default player-prompt composer (slc/link.md §Player prompt composition).
394
428
  * One callback-based pass substitutes each `<fieldName>` placeholder whose