@sublang/playbook 12.0.0 → 12.2.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.
@@ -4080,7 +4080,10 @@ function validateEffectLedgerAuthority(value, record, owner) {
4080
4080
  return authority;
4081
4081
  }
4082
4082
 
4083
- function applyEffectLedgerCommands(
4083
+ // Exported for the private worktree host-capability constructor in
4084
+ // repository-effects.js, so an external host's in-memory ledger applies the
4085
+ // exact command semantics the durable Captain record applies.
4086
+ export function applyEffectLedgerCommands(
4084
4087
  ledgerValue,
4085
4088
  authority,
4086
4089
  uncertain,
@@ -0,0 +1,291 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
3
+
4
+ export type JsonValue =
5
+ | null
6
+ | boolean
7
+ | number
8
+ | string
9
+ | readonly JsonValue[]
10
+ | { readonly [key: string]: JsonValue };
11
+
12
+ export type PlaybookRepositoryDisposition =
13
+ | 'unchanged'
14
+ | 'one-descendant-commit'
15
+ | 'deferred';
16
+ export type RepositoryReceiptClassification =
17
+ | 'unchanged'
18
+ | 'one-descendant-commit'
19
+ | 'multiple-commits'
20
+ | 'rewritten-or-non-descendant'
21
+ | 'worktree-only-change'
22
+ | 'concurrent-or-foreign-change'
23
+ | 'observation-ambiguous';
24
+ export declare const REPOSITORY_RECEIPT_CLASSIFICATIONS: readonly RepositoryReceiptClassification[];
25
+
26
+ export interface RepositoryIdentity {
27
+ readonly worktree: string;
28
+ readonly gitDir: string;
29
+ }
30
+ export interface PlaybookRepositoryObservation extends RepositoryIdentity {
31
+ readonly head: string;
32
+ readonly projection: Readonly<Record<string, JsonValue>>;
33
+ readonly projectionDigest: string;
34
+ }
35
+ export interface PlaybookRepositoryReceipt {
36
+ readonly classification: RepositoryReceiptClassification;
37
+ readonly baseline: PlaybookRepositoryObservation;
38
+ readonly after?: PlaybookRepositoryObservation;
39
+ readonly commitOid?: string;
40
+ }
41
+ export interface RepositoryReceiptOptions {
42
+ readonly allowedDispositions: readonly PlaybookRepositoryDisposition[];
43
+ }
44
+
45
+ export declare function observeGitRepository(
46
+ cwd: string,
47
+ ): Promise<PlaybookRepositoryObservation>;
48
+ export declare function classifyRepositoryReceipt(
49
+ baseline: PlaybookRepositoryObservation,
50
+ after: PlaybookRepositoryObservation,
51
+ options: RepositoryReceiptOptions,
52
+ ): Promise<PlaybookRepositoryReceipt>;
53
+ export declare function captureRepositoryReceipt(
54
+ baseline: PlaybookRepositoryObservation,
55
+ options: RepositoryReceiptOptions,
56
+ ): Promise<PlaybookRepositoryReceipt>;
57
+
58
+ export interface PlaybookPendingBossQuestion {
59
+ readonly questionId: string;
60
+ readonly asker:
61
+ | { readonly kind: 'captain' }
62
+ | { readonly kind: 'role'; readonly roleId: string };
63
+ readonly question: string;
64
+ readonly sourceItem?: string;
65
+ }
66
+ export interface PlaybookEffectBoundary {
67
+ readonly sequence: number;
68
+ readonly boundaryId: string;
69
+ readonly attemptId: string;
70
+ readonly attemptNumber: number;
71
+ readonly playbookId: string;
72
+ readonly runtimeSessionId: string;
73
+ readonly turnId: number;
74
+ readonly callId: string;
75
+ readonly roleId: string;
76
+ readonly sourceStateId: string;
77
+ readonly sourceOutcomeSchema: JsonValue;
78
+ readonly dispositions: readonly PlaybookRepositoryDisposition[];
79
+ readonly canonicalWorktree: RepositoryIdentity;
80
+ readonly baseline: PlaybookRepositoryObservation;
81
+ readonly after?: PlaybookRepositoryObservation;
82
+ readonly physicalReceipt?: PlaybookRepositoryReceipt;
83
+ readonly finalText?: string;
84
+ readonly semanticCandidate?: JsonValue;
85
+ readonly initialSemanticCandidate?: JsonValue;
86
+ readonly correctionBudget: {
87
+ readonly limit: 1;
88
+ readonly spent: boolean;
89
+ };
90
+ readonly cohortId?: string;
91
+ readonly logicalOperationId?: string;
92
+ }
93
+ export type PlaybookEffectBoundaryStart = Omit<
94
+ PlaybookEffectBoundary,
95
+ | 'sequence'
96
+ | 'attemptId'
97
+ | 'attemptNumber'
98
+ | 'after'
99
+ | 'physicalReceipt'
100
+ | 'finalText'
101
+ | 'semanticCandidate'
102
+ | 'initialSemanticCandidate'
103
+ >;
104
+ export type EffectBoundarySeed = Omit<
105
+ PlaybookEffectBoundaryStart,
106
+ 'playbookId' | 'canonicalWorktree' | 'baseline' | 'cohortId'
107
+ >;
108
+ export interface PlaybookEffectLogicalOperation {
109
+ readonly sequence: number;
110
+ readonly operationId: string;
111
+ readonly playbookId: string;
112
+ readonly runtimeSessionId: string;
113
+ readonly boundaryIds: readonly string[];
114
+ readonly originalBaseline: PlaybookRepositoryObservation;
115
+ readonly checkpoint?: PlaybookRepositoryObservation;
116
+ readonly pendingQuestion?: PlaybookPendingBossQuestion;
117
+ readonly playerContinuation?: JsonValue;
118
+ readonly checkpointRestorationEligible: boolean;
119
+ readonly logicalReceipt?: PlaybookRepositoryReceipt;
120
+ }
121
+ export interface PlaybookEffectLedger {
122
+ readonly schemaVersion: 1;
123
+ readonly revision: number;
124
+ readonly boundaries: readonly PlaybookEffectBoundary[];
125
+ readonly logicalOperations: readonly PlaybookEffectLogicalOperation[];
126
+ }
127
+ export type PlaybookEffectLedgerCommand =
128
+ | {
129
+ readonly kind: 'start-boundaries';
130
+ readonly boundaries: readonly [
131
+ PlaybookEffectBoundaryStart,
132
+ ...PlaybookEffectBoundaryStart[],
133
+ ];
134
+ }
135
+ | {
136
+ readonly kind: 'replace-boundaries';
137
+ readonly replacements: readonly [
138
+ {
139
+ readonly expected: PlaybookEffectBoundary;
140
+ readonly next: PlaybookEffectBoundary;
141
+ },
142
+ ...{
143
+ readonly expected: PlaybookEffectBoundary;
144
+ readonly next: PlaybookEffectBoundary;
145
+ }[],
146
+ ];
147
+ }
148
+ | {
149
+ readonly kind: 'append-logical-operations';
150
+ readonly operations: readonly [
151
+ Omit<PlaybookEffectLogicalOperation, 'sequence'>,
152
+ ...Omit<PlaybookEffectLogicalOperation, 'sequence'>[],
153
+ ];
154
+ }
155
+ | {
156
+ readonly kind: 'replace-logical-operations';
157
+ readonly replacements: readonly [
158
+ {
159
+ readonly expected: PlaybookEffectLogicalOperation;
160
+ readonly next: PlaybookEffectLogicalOperation;
161
+ },
162
+ ...{
163
+ readonly expected: PlaybookEffectLogicalOperation;
164
+ readonly next: PlaybookEffectLogicalOperation;
165
+ }[],
166
+ ];
167
+ };
168
+ export type PlaybookEffectLedgerCommandBatch = readonly [
169
+ PlaybookEffectLedgerCommand,
170
+ ...PlaybookEffectLedgerCommand[],
171
+ ];
172
+ export interface PlaybookEffectLedgerCapability {
173
+ snapshot(): PlaybookEffectLedger;
174
+ writeAhead(
175
+ commands: PlaybookEffectLedgerCommandBatch,
176
+ ): Promise<PlaybookEffectLedger>;
177
+ }
178
+
179
+ interface RepositoryOperationSettlement<T> {
180
+ readonly status: 'fulfilled';
181
+ readonly value: T;
182
+ }
183
+ interface RepositoryOperationRejection {
184
+ readonly status: 'rejected';
185
+ readonly reason: unknown;
186
+ }
187
+ export interface RepositoryExclusiveCompletion<T> {
188
+ readonly boundary: PlaybookEffectBoundary;
189
+ readonly operation:
190
+ | RepositoryOperationSettlement<T>
191
+ | RepositoryOperationRejection;
192
+ readonly receipt: PlaybookRepositoryReceipt;
193
+ readonly outcomeReceipt: PlaybookRepositoryReceipt;
194
+ }
195
+ interface RepositoryDeferredBinding {
196
+ readonly operationId: string;
197
+ readonly pendingQuestion: PlaybookPendingBossQuestion;
198
+ readonly playerContinuation: JsonValue;
199
+ }
200
+ export interface RepositoryCompletionEvidence {
201
+ readonly finalText?: string;
202
+ readonly semanticCandidate?: JsonValue;
203
+ readonly deferred?: RepositoryDeferredBinding;
204
+ readonly unresolved?: true;
205
+ }
206
+ export interface RepositoryExclusiveResult<T> {
207
+ readonly operation:
208
+ | RepositoryOperationSettlement<T>
209
+ | RepositoryOperationRejection;
210
+ readonly receipt: PlaybookRepositoryReceipt;
211
+ readonly effectLedger: PlaybookEffectLedger;
212
+ readonly deferredStatus?: 'bound' | 'unresolved';
213
+ }
214
+ interface RepositoryDeferredContinuationResult<T> {
215
+ readonly status: 'continued';
216
+ readonly operation:
217
+ | RepositoryOperationSettlement<T>
218
+ | RepositoryOperationRejection;
219
+ readonly receipt: PlaybookRepositoryReceipt;
220
+ readonly logicalReceipt?: PlaybookRepositoryReceipt;
221
+ readonly effectLedger: PlaybookEffectLedger;
222
+ readonly deferredStatus?: 'bound' | 'unresolved';
223
+ }
224
+ interface RepositoryDeferredCheckpointMismatch {
225
+ readonly status: 'checkpoint-mismatch' | 'ineligible';
226
+ readonly effectLedger: PlaybookEffectLedger;
227
+ }
228
+ interface RepositoryDeferredParked {
229
+ readonly status: 'parked';
230
+ readonly effectLedger: PlaybookEffectLedger;
231
+ }
232
+ interface RepositoryDeferredRestoreResult {
233
+ readonly status: 'restored' | 'checkpoint-mismatch' | 'ineligible';
234
+ readonly effectLedger: PlaybookEffectLedger;
235
+ }
236
+ export interface RepositoryCapability {
237
+ runExclusive<T>(options: {
238
+ readonly signal?: AbortSignal;
239
+ readonly effectBoundary: EffectBoundarySeed;
240
+ readonly operation: (context: {
241
+ readonly baseline: PlaybookRepositoryObservation;
242
+ readonly identity: RepositoryIdentity;
243
+ }) => Promise<T>;
244
+ readonly completeEffectBoundary: (
245
+ completion: RepositoryExclusiveCompletion<T>,
246
+ ) => RepositoryCompletionEvidence | Promise<RepositoryCompletionEvidence>;
247
+ }): Promise<RepositoryExclusiveResult<T>>;
248
+ runDeferred<T>(options: {
249
+ readonly mode: 'continue';
250
+ readonly signal?: AbortSignal;
251
+ readonly operationId: string;
252
+ readonly effectBoundary: EffectBoundarySeed;
253
+ readonly operation: (context: {
254
+ readonly baseline: PlaybookRepositoryObservation;
255
+ readonly identity: RepositoryIdentity;
256
+ readonly playerContinuation: JsonValue;
257
+ }) => Promise<T>;
258
+ readonly completeEffectBoundary: (
259
+ completion: RepositoryExclusiveCompletion<T>,
260
+ ) => RepositoryCompletionEvidence | Promise<RepositoryCompletionEvidence>;
261
+ }): Promise<
262
+ RepositoryDeferredContinuationResult<T> | RepositoryDeferredCheckpointMismatch
263
+ >;
264
+ runDeferred(options: {
265
+ readonly mode: 'park' | 'restore';
266
+ readonly signal?: AbortSignal;
267
+ readonly operationId: string;
268
+ }): Promise<RepositoryDeferredParked | RepositoryDeferredRestoreResult>;
269
+ }
270
+ export interface HostCapabilities {
271
+ readonly repository: RepositoryCapability;
272
+ readonly effectLedger: PlaybookEffectLedgerCapability;
273
+ }
274
+ export interface WorktreeRepositoryCapability extends RepositoryCapability {
275
+ readonly identity: RepositoryIdentity;
276
+ observe(): Promise<PlaybookRepositoryObservation>;
277
+ }
278
+ export interface WorktreeHostCapabilities extends HostCapabilities {
279
+ readonly repository: WorktreeRepositoryCapability;
280
+ }
281
+ export interface WorktreeHostCapabilitiesOptions {
282
+ readonly cwd: string;
283
+ readonly playbookId: string;
284
+ readonly requiredRoleIds: readonly string[];
285
+ readonly concurrentRoleSets?: readonly (readonly string[])[];
286
+ readonly effectLedger?: PlaybookEffectLedger;
287
+ }
288
+ export declare function createWorktreeHostCapabilities(
289
+ options: WorktreeHostCapabilitiesOptions,
290
+ ): Promise<WorktreeHostCapabilities>;
291
+ export declare function createFailClosedHostCapabilities(): HostCapabilities;
@@ -0,0 +1,40 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
3
+
4
+ // DR-046: the public `@sublang/playbook/host-capabilities` facade. Every
5
+ // member is the CLI host's own repository-effect implementation; this module
6
+ // only narrows the accepted arguments to the declared surface.
7
+
8
+ import {
9
+ REPOSITORY_RECEIPT_CLASSIFICATIONS,
10
+ captureRepositoryReceipt as capture,
11
+ classifyRepositoryReceipt as classify,
12
+ createFailClosedHostCapabilities,
13
+ createWorktreeHostCapabilities,
14
+ observeGitRepository as observe,
15
+ } from './bin/repository-effects.js';
16
+
17
+ export {
18
+ REPOSITORY_RECEIPT_CLASSIFICATIONS,
19
+ createFailClosedHostCapabilities,
20
+ createWorktreeHostCapabilities,
21
+ };
22
+
23
+ export async function observeGitRepository(cwd) {
24
+ return observe(cwd);
25
+ }
26
+
27
+ export async function classifyRepositoryReceipt(baseline, after, options) {
28
+ return classify(baseline, after, receiptOptions(options));
29
+ }
30
+
31
+ export async function captureRepositoryReceipt(baseline, options) {
32
+ return capture(baseline, receiptOptions(options));
33
+ }
34
+
35
+ function receiptOptions(options) {
36
+ if (options === null || typeof options !== 'object' || Array.isArray(options)) {
37
+ throw new TypeError('repository receipt options must be an object');
38
+ }
39
+ return { allowedDispositions: options.allowedDispositions };
40
+ }
@@ -64,6 +64,10 @@ const ROLE_ID_PATTERN = /^[a-z][a-z0-9_-]*$/;
64
64
  const HOST_CAPABILITIES_OPTION_KEY = 'hostCapabilities';
65
65
  const UNRESOLVED_EFFECT_RECONCILIATION_ACTION_ID = 'reconcile:unresolved-effect';
66
66
  const UNRESOLVED_EFFECT_ABANDONMENT_ACTION_ID = 'abandon:unresolved-effect';
67
+ // The fixed machine-syntax guard of a player's Boss-question suspension
68
+ // (slc/link.md §Boss-reply suspension): the accepted outcome that parks on
69
+ // Boss rather than sparing Boss a relay.
70
+ const BOSS_QUESTION_OUTCOME = 'needsBossReply';
67
71
  const RESUMPTION_DUPLICATE_EFFECT_WARNING = 'Warning: resumption may duplicate external effects attempted after the retained boundary; verify the current world before continuing.';
68
72
  function parseRegisteredCommand(prompt) {
69
73
  const match = /^\/([A-Za-z][A-Za-z0-9_-]*)(?:\s+([\s\S]*))?$/.exec(prompt.trim());
@@ -2550,6 +2554,12 @@ export function createPlaybookCaptainShell(options, deps = {}) {
2550
2554
  if (summary.acceptedOutcomeTraceKeys.has(traceKey))
2551
2555
  return;
2552
2556
  summary.acceptedOutcomeTraceKeys.add(traceKey);
2557
+ // CAPTAIN-19/20: a saved interruption is a player reply Boss did not
2558
+ // have to relay. A Boss-question suspension is the one accepted outcome
2559
+ // that parks on Boss instead, so it saves nothing and counts nothing —
2560
+ // a turn that only parked must not claim it saved an interruption.
2561
+ if (receipt.acceptedOutcome === BOSS_QUESTION_OUTCOME)
2562
+ return;
2553
2563
  summary.counts.interruptions++;
2554
2564
  if (frame.entry.summaryPolicy?.copyPasteGuardNames.includes(receipt.acceptedOutcome)) {
2555
2565
  summary.counts.copyPastes++;
@@ -554,6 +554,10 @@ const HOST_CAPABILITIES_OPTION_KEY = 'hostCapabilities';
554
554
  const UNRESOLVED_EFFECT_RECONCILIATION_ACTION_ID =
555
555
  'reconcile:unresolved-effect';
556
556
  const UNRESOLVED_EFFECT_ABANDONMENT_ACTION_ID = 'abandon:unresolved-effect';
557
+ // The fixed machine-syntax guard of a player's Boss-question suspension
558
+ // (slc/link.md §Boss-reply suspension): the accepted outcome that parks on
559
+ // Boss rather than sparing Boss a relay.
560
+ const BOSS_QUESTION_OUTCOME = 'needsBossReply';
557
561
  const RESUMPTION_DUPLICATE_EFFECT_WARNING =
558
562
  'Warning: resumption may duplicate external effects attempted after the retained boundary; verify the current world before continuing.';
559
563
 
@@ -4293,6 +4297,11 @@ export function createPlaybookCaptainShell(
4293
4297
  const traceKey = `${frame.sessionId}:${trace.sequence}`;
4294
4298
  if (summary.acceptedOutcomeTraceKeys.has(traceKey)) return;
4295
4299
  summary.acceptedOutcomeTraceKeys.add(traceKey);
4300
+ // CAPTAIN-19/20: a saved interruption is a player reply Boss did not
4301
+ // have to relay. A Boss-question suspension is the one accepted outcome
4302
+ // that parks on Boss instead, so it saves nothing and counts nothing —
4303
+ // a turn that only parked must not claim it saved an interruption.
4304
+ if (receipt.acceptedOutcome === BOSS_QUESTION_OUTCOME) return;
4296
4305
  summary.counts.interruptions++;
4297
4306
  if (
4298
4307
  frame.entry.summaryPolicy?.copyPasteGuardNames.includes(
@@ -19,7 +19,7 @@ import { randomUUID } from 'node:crypto';
19
19
  import PQueue from 'p-queue';
20
20
  import { createActor, fromPromise } from 'xstate';
21
21
  import { createAcceptedOutcomeConsumer, } from '../../../src/accepted-outcome.js';
22
- import { assertJsonSafe, assertPlaybookEffectLedger, assertPlaybookRuntimeSnapshot, combineAbortSignals, createNestedPlaybookBridge, detachPersistedMachineSnapshot, normalizeError, normalizePlaybookSnapshot, PlaybookSemanticCandidateStructureError, reconcilePlaybookSemanticEvidence, snapshotJsonValue, snapshotPlaybookSession, validatePlayerResult, waitForPlaybookQuiescence, } from '../../../src/xstate-runtime.js';
22
+ import { assertJsonSafe, assertPlaybookEffectLedger, assertPlaybookRuntimeSnapshot, combineAbortSignals, createNestedPlaybookBridge, detachPersistedMachineSnapshot, normalizeError, normalizePlaybookSnapshot, PlaybookSemanticCandidateStructureError, reconcilePlaybookSemanticEvidence, renderGovernedOutcomeContract, snapshotJsonValue, snapshotPlaybookSession, validatePlayerResult, waitForPlaybookQuiescence, } from '../../../src/xstate-runtime.js';
23
23
  import decideMachine from './decide.fsm.js';
24
24
  function snapshotDecideRuntimeOptions(value) {
25
25
  const captured = snapshotJsonValue(value, 'DECIDE runtime options');
@@ -429,15 +429,19 @@ function buildAdjudicatorPrompt(input, playerOutput, correction) {
429
429
  lines.push('"""');
430
430
  lines.push('');
431
431
  lines.push('Guards (choose exactly one; the descriptions are authoritative and must be applied as written):');
432
+ // The shared engine's renderer (slc/link.md §Captain adjudication): each
433
+ // arm's meaning verbatim, with its `Output shall include` clause — authored
434
+ // for the complete actor output — replaced by the reply contract the
435
+ // outcome authority gives the judge. Rendering the clause verbatim asked
436
+ // the judge for presentation-owned `coderProposal` or `question`, which the
437
+ // reconciler rejects, spending the single correction on a self-inflicted
438
+ // defect.
432
439
  for (const [guard, description] of Object.entries(input.result)) {
433
- const semanticFields = Object.entries(outcomes[guard]?.fields ?? {})
434
- .filter(([, authority]) => authority === 'semantic')
435
- .map(([field]) => field);
436
- lines.push(`- ${guard}: semantic fields: ${semanticFields.length === 0 ? '(none)' : semanticFields.join(', ')}; ${description}`);
440
+ lines.push(...renderGovernedOutcomeContract(guard, description, outcomes[guard]));
437
441
  }
438
442
  lines.push('');
439
- lines.push('Reply with exactly the chosen `guard` and every semantic-owned field for that guard, and no other field.');
440
- lines.push('Do not include presentation-, effect-, or runtime-owned fields; the runtime supplies those from authoritative evidence.');
443
+ lines.push("Pick exactly one declared `guard` and reply with exactly that outcome's reply shape above: `guard` plus its semantic-owned fields and nothing else.");
444
+ lines.push('A field listed as runtime-supplied is owned by presentation, effect, or runtime evidence; the runtime fills it itself, and a reply that includes one is structurally invalid.');
441
445
  if (correction !== undefined) {
442
446
  lines.push('');
443
447
  lines.push('Your first reply was structurally invalid:');
@@ -38,6 +38,7 @@ import {
38
38
  normalizePlaybookSnapshot,
39
39
  PlaybookSemanticCandidateStructureError,
40
40
  reconcilePlaybookSemanticEvidence,
41
+ renderGovernedOutcomeContract,
41
42
  snapshotJsonValue,
42
43
  snapshotPlaybookSession,
43
44
  validatePlayerResult,
@@ -660,22 +661,24 @@ function buildAdjudicatorPrompt(
660
661
  lines.push(
661
662
  'Guards (choose exactly one; the descriptions are authoritative and must be applied as written):',
662
663
  );
664
+ // The shared engine's renderer (slc/link.md §Captain adjudication): each
665
+ // arm's meaning verbatim, with its `Output shall include` clause — authored
666
+ // for the complete actor output — replaced by the reply contract the
667
+ // outcome authority gives the judge. Rendering the clause verbatim asked
668
+ // the judge for presentation-owned `coderProposal` or `question`, which the
669
+ // reconciler rejects, spending the single correction on a self-inflicted
670
+ // defect.
663
671
  for (const [guard, description] of Object.entries(input.result)) {
664
- const semanticFields = Object.entries(outcomes[guard]?.fields ?? {})
665
- .filter(([, authority]) => authority === 'semantic')
666
- .map(([field]) => field);
667
672
  lines.push(
668
- `- ${guard}: semantic fields: ${
669
- semanticFields.length === 0 ? '(none)' : semanticFields.join(', ')
670
- }; ${description}`,
673
+ ...renderGovernedOutcomeContract(guard, description, outcomes[guard]),
671
674
  );
672
675
  }
673
676
  lines.push('');
674
677
  lines.push(
675
- 'Reply with exactly the chosen `guard` and every semantic-owned field for that guard, and no other field.',
678
+ "Pick exactly one declared `guard` and reply with exactly that outcome's reply shape above: `guard` plus its semantic-owned fields and nothing else.",
676
679
  );
677
680
  lines.push(
678
- 'Do not include presentation-, effect-, or runtime-owned fields; the runtime supplies those from authoritative evidence.',
681
+ 'A field listed as runtime-supplied is owned by presentation, effect, or runtime evidence; the runtime fills it itself, and a reply that includes one is structurally invalid.',
679
682
  );
680
683
  if (correction !== undefined) {
681
684
  lines.push('');
package/slc/gears2fsm.md CHANGED
@@ -540,6 +540,10 @@ The artifact shall not bake them into machine input, options, or context; model
540
540
  Host-owned configuration such as an enabled-playbook catalog shall remain
541
541
  immutable machine input/context for the session. Boss events and actor outputs
542
542
  shall not carry, replace, append to, or otherwise overwrite that catalog.
543
+ A placeholder whose value Source assigns to the host — for example the
544
+ `<definition>` a phase host supplies to a compiled phase — is such host-owned
545
+ configuration: a required machine `input` field carried into typed context and
546
+ the acting actor's input, never a Boss-event or actor-output payload.
543
547
  Every machine with a dynamic call shall receive its own registered or authored
544
548
  playbook id as immutable machine input/context named `selfPlaybookId`, and its
545
549
  dynamic-call guard shall reject that target. The leaf-level `stateId` name is
@@ -776,6 +780,22 @@ compile as `{ response: string }`, not `{ response?: string }`; reaching the
776
780
  final state without a non-empty response shall be guarded out before the
777
781
  machine output is constructed.
778
782
 
783
+ ## Compiled execution
784
+
785
+ This section governs compiled execution of this phase; the rules above remain the transformation's normative content for both execution paths.
786
+
787
+ Where the phase host supplies `<definition>` as the exact bytes of the definition file the request names, when a transformation request names a `gears` Source (`.md`) and an `fsm` Target (`.ts`), Captain shall carry out the GEARS-to-FSM transformation as specified:
788
+
789
+ > Follow the definition relayed between the `--- DEFINITION ---` and `--- END DEFINITION ---` lines exactly, adding no rules of your own: read the named Source and write the named Target as the definition specifies.
790
+ > If the Source cannot be transformed under the definition, do not guess: leave the Target unwritten and report the concrete reason.
791
+ > --- DEFINITION ---
792
+ > \<definition\>
793
+ > --- END DEFINITION ---
794
+
795
+ Results:
796
+ - `compiled`: Captain wrote the named Target as the relayed definition specifies.
797
+ - `rejected`: Captain reported that the Source cannot be transformed under the relayed definition and left the Target unwritten.
798
+
779
799
  ## References
780
800
 
781
801
  [1]: https://stately.ai/docs/xstate 'XState Official Documentation'
package/slc/link.md CHANGED
@@ -1079,6 +1079,15 @@ runtime-owned payload field; `guard` shall name exactly one outcome declared
1079
1079
  by both the live result map and `outcomeAuthority`; and every semantic-owned
1080
1080
  field shall satisfy the result map's required-field type before any actor
1081
1081
  output is delivered.
1082
+ The judge prompt shall render each governed outcome's description with its
1083
+ meaning verbatim and its `Output shall include` clause replaced by that reply
1084
+ contract — exactly `guard` plus the semantic-owned fields, each keeping its
1085
+ authored placeholder or guidance, with every presentation-, effect-, or
1086
+ runtime-owned field named as runtime-supplied to omit — so the judge is never asked for a
1087
+ field it does not own; the artifact's description text stays unchanged.
1088
+ The shared engine shall export that rendering as `renderGovernedOutcomeContract`
1089
+ on `@sublang/playbook/xstate-runtime`, and a bespoke linked runtime shall
1090
+ render its judge prompt through it rather than restate the contract.
1082
1091
  The reconciler shall construct the complete actor output rather than accept a
1083
1092
  cross-authority object from the judge: every presentation-owned payload field
1084
1093
  shall receive the canonical `finalText.trim()` value; every effect-owned
@@ -1170,7 +1179,9 @@ Two default adjudication strategies, in selection order:
1170
1179
  to decide only from the supplied actor output and declared outcomes, and
1171
1180
  require exactly one JSON object with no prose. The judge prompt shall not
1172
1181
  interpret the player's output, paraphrase it, or alter the FSM's `result`
1173
- text — it carries the description verbatim.
1182
+ text — it carries the description verbatim, except that a governed
1183
+ schema-3 outcome's `Output shall include` clause is rendered as the
1184
+ authority-derived reply contract of §Captain adjudication.
1174
1185
  - **Marker-parse** (delegated-player alternative): a deterministic parser that
1175
1186
  scans the player output for a terminal control line such as
1176
1187
  `FSM-RESULT: { "guard": "...", ... }`. Useful when player adapters can
@@ -2451,6 +2462,22 @@ This spec is silent on the choice; the contract is the same in any location.
2451
2462
 
2452
2463
  New behavior in any of these areas requires a separate slc spec.
2453
2464
 
2465
+ ## Compiled execution
2466
+
2467
+ This section governs compiled execution of this phase; the rules above remain the transformation's normative content for both execution paths.
2468
+
2469
+ Where the phase host supplies `<definition>` as the exact bytes of the definition file the request names, when a transformation request names an `fsm` Source (`.ts`) and a `playbook` Target (`.ts`), Captain shall carry out the FSM-to-runtime linking as specified:
2470
+
2471
+ > Follow the definition relayed between the `--- DEFINITION ---` and `--- END DEFINITION ---` lines exactly, adding no rules of your own: read the named Source and write the named Target as the definition specifies.
2472
+ > If the Source cannot be transformed under the definition, do not guess: leave the Target unwritten and report the concrete reason.
2473
+ > --- DEFINITION ---
2474
+ > \<definition\>
2475
+ > --- END DEFINITION ---
2476
+
2477
+ Results:
2478
+ - `compiled`: Captain wrote the named Target as the relayed definition specifies.
2479
+ - `rejected`: Captain reported that the Source cannot be transformed under the relayed definition and left the Target unwritten.
2480
+
2454
2481
  ## References
2455
2482
 
2456
2483
  [1]: text2gears.md "First phase: text → GEARS spec items."
package/slc/text2gears.md CHANGED
@@ -321,7 +321,9 @@ exact English form regardless of Source language.
321
321
  ## Transformation-spec sources
322
322
 
323
323
  A Source may itself be the normative specification of a transformation — e.g., a compiler phase definition, as when a meta pipeline compiles this file.
324
- Such a Source declares no roles and prompts none; its implied procedure is that Captain performs the specified transformation on request.
324
+ Such a Source declares no roles and prompts none; Captain performs the specified transformation on request.
325
+ Where such a Source carries a `## Compiled execution` section, text2gears shall compile it from that section alone: the section is the Source's complete behavior — its acting item, prompt, and `Results:` contract — and the remaining definition text is relayed content, not behaviors to transcribe, so the composition below applies only to a Source without that section.
326
+ That section's blockquote is complete as authored: text2gears shall emit it verbatim and shall append no relay line to it — the `<definition>` placeholder is its only runtime value, and the undelivered-value rule above does not add `<boss-intent>` or any other placeholder to it.
325
327
  Compose Captain-acting spec items for it: when a transformation request names the specification's source and target, Captain shall carry out the transformation as specified.
326
328
  Prompts shall carry the specification's normative requirements as instructions to Captain — deduplicated, one point per line — without inventing roles, triggers, or requirements the specification does not state.
327
329
 
@@ -352,6 +354,22 @@ Partition items by every variable that determines prompt content — including a
352
354
  Drop disjunctive branches incompatible with the rest of an item's condition or prompt.
353
355
  Dead branches mislead readers and downstream phases.
354
356
 
357
+ ## Compiled execution
358
+
359
+ This section governs compiled execution of this phase; the rules above remain the transformation's normative content for both execution paths.
360
+
361
+ Where the phase host supplies `<definition>` as the exact bytes of the definition file the request names, when a transformation request names a `text` Source (`.md`) and a `gears` Target (`.md`), Captain shall carry out the text-to-GEARS transformation as specified:
362
+
363
+ > Follow the definition relayed between the `--- DEFINITION ---` and `--- END DEFINITION ---` lines exactly, adding no rules of your own: read the named Source and write the named Target as the definition specifies.
364
+ > If the Source cannot be transformed under the definition, do not guess: leave the Target unwritten and report the concrete reason.
365
+ > --- DEFINITION ---
366
+ > \<definition\>
367
+ > --- END DEFINITION ---
368
+
369
+ Results:
370
+ - `compiled`: Captain wrote the named Target as the relayed definition specifies.
371
+ - `rejected`: Captain reported that the Source cannot be transformed under the relayed definition and left the Target unwritten.
372
+
355
373
  ## References
356
374
 
357
375
  [1]: GEARS definition shipped by the installed `@sublang/spex` package: `@sublang/spex/scaffold/specs/meta.md` (English) and `@sublang/spex/scaffold/i18n/zh/specs/meta.md` (Chinese); canonical renditions [GEARS: AI-Ready Spec Syntax](https://sublang.ai/ref/gears-ai-ready-spec-syntax) (en) and [GEARS:面向 AI 的规约语法](https://sublang.ai/zh/ref/gears-ai-ready-spec-syntax) (zh)
@@ -412,6 +412,21 @@ export declare function defaultComposeCaptainPrompt(input: PlaybookCaptainInput,
412
412
  export declare function defaultExtractRequiredFields(description: string): string[];
413
413
  /** Default delegated-player adjudicator prompt. */
414
414
  export declare function defaultBuildJudgePrompt(input: PlaybookPlayerInput, finalText: string): string;
415
+ /**
416
+ * Judge-facing rendering of one governed outcome (DR-040 §1). The artifact's
417
+ * description is not altered: its meaning is carried through verbatim, while
418
+ * its `Output shall include` clause — authored for the complete actor output
419
+ * — is replaced by the reply contract `outcomeAuthority` gives the judge:
420
+ * exactly `guard` plus the outcome's semantic-owned fields, each keeping the
421
+ * placeholder or guidance the clause authors for it, and every
422
+ * presentation-, effect-, or runtime-owned field named as runtime-supplied
423
+ * so the judge omits it. Rendering the clause verbatim asked the judge for
424
+ * `question`, `planningResult`, or `evaluatedRevision`, which the reconciler
425
+ * rejects as a structural error, spending the single correction on a
426
+ * self-inflicted defect. Exported so a bespoke linked runtime (DECIDE's
427
+ * parallel machinery) renders the identical contract instead of restating it.
428
+ */
429
+ export declare function renderGovernedOutcomeContract(guard: string, description: string, outcome: XStateGovernedOutcomeSpec | undefined): string[];
415
430
  export interface PlayerAdjudicationSpec {
416
431
  buildJudgePrompt?: (input: PlaybookPlayerInput, finalText: string) => string;
417
432
  extractRequiredFields?: (description: string) => string[];