@sublang/playbook 11.0.0 → 12.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 (49) hide show
  1. package/docs/cli.md +9 -6
  2. package/docs/configuration.md +15 -1
  3. package/docs/embedding.md +83 -1
  4. package/package.json +28 -3
  5. package/reference/sdlc/code.playbook/bin/repository-effects.js +501 -170
  6. package/reference/sdlc/code.playbook/bin/session-store.js +4 -1
  7. package/reference/sdlc/code.playbook/code.fsm.d.ts +22 -19
  8. package/reference/sdlc/code.playbook/code.fsm.js +116 -52
  9. package/reference/sdlc/code.playbook/code.fsm.ts +149 -64
  10. package/reference/sdlc/code.playbook/code.gears.md +40 -20
  11. package/reference/sdlc/code.playbook/code.playbook.js +23 -2
  12. package/reference/sdlc/code.playbook/code.playbook.ts +23 -2
  13. package/reference/sdlc/code.playbook/host-capabilities.d.ts +291 -0
  14. package/reference/sdlc/code.playbook/host-capabilities.js +40 -0
  15. package/reference/sdlc/code.playbook/playbook.config.template.yaml +18 -2
  16. package/reference/sdlc/decide.playbook/decide.fsm.d.ts +13 -6
  17. package/reference/sdlc/decide.playbook/decide.fsm.js +54 -27
  18. package/reference/sdlc/decide.playbook/decide.fsm.ts +68 -29
  19. package/reference/sdlc/decide.playbook/decide.gears.md +25 -19
  20. package/reference/sdlc/decide.playbook/decide.playbook.js +11 -3
  21. package/reference/sdlc/decide.playbook/decide.playbook.ts +11 -3
  22. package/reference/sdlc/decide.playbook/decide.registry.js +1 -1
  23. package/reference/sdlc/decide.playbook/decide.registry.ts +1 -1
  24. package/reference/sdlc/dev.md +52 -0
  25. package/reference/sdlc/dev.playbook/dev.fsm.d.ts +261 -0
  26. package/reference/sdlc/dev.playbook/dev.fsm.js +723 -0
  27. package/reference/sdlc/dev.playbook/dev.fsm.ts +988 -0
  28. package/reference/sdlc/dev.playbook/dev.gears.md +91 -0
  29. package/reference/sdlc/dev.playbook/dev.playbook.d.ts +21 -0
  30. package/reference/sdlc/dev.playbook/dev.playbook.js +143 -0
  31. package/reference/sdlc/dev.playbook/dev.playbook.ts +246 -0
  32. package/reference/sdlc/dev.playbook/dev.registry.d.ts +40 -0
  33. package/reference/sdlc/dev.playbook/dev.registry.js +64 -0
  34. package/reference/sdlc/dev.playbook/dev.registry.ts +120 -0
  35. package/reference/sdlc/review.playbook/review.fsm.d.ts +15 -2
  36. package/reference/sdlc/review.playbook/review.fsm.js +77 -27
  37. package/reference/sdlc/review.playbook/review.fsm.ts +96 -30
  38. package/reference/sdlc/review.playbook/review.gears.md +52 -26
  39. package/reference/sdlc/review.playbook/review.playbook.js +17 -7
  40. package/reference/sdlc/review.playbook/review.playbook.ts +17 -7
  41. package/reference/sdlc/review.playbook/review.registry.js +1 -1
  42. package/reference/sdlc/review.playbook/review.registry.ts +1 -1
  43. package/slc/gears2fsm.md +20 -0
  44. package/slc/link.md +28 -5
  45. package/slc/text2gears.md +21 -1
  46. package/src/xstate-playbook-runtime.js +5 -2
  47. package/src/xstate-playbook-runtime.ts +5 -2
  48. package/src/xstate-runtime.js +13 -1
  49. package/src/xstate-runtime.ts +13 -1
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
@@ -423,7 +423,7 @@ After a governed operation settles, the host shall retain any exact proposed com
423
423
  Each state shall name exactly the outcomes in that state's `invoke.input.result`, and each outcome shall contain exactly `fields` and `repositoryDisposition`.
424
424
  The outcome key owns the semantic discriminator, so `guard` shall not appear in `fields`; the `fields` keys shall equal every additional payload field named by that outcome's result description.
425
425
  Each field shall have exactly one authority from `presentation`, `semantic`, `effect`, or `runtime`; every linker-declared verbatim payload field and `question` shall be `presentation`, `latestCommit` shall be `effect`, and the payload fields `irNumber` and `irTask` shall be `semantic`, while outcome keys such as `moreTasks` and `finalTask` remain semantic discriminators.
426
- Each repository disposition shall be exactly `unchanged`, `one-descendant-commit`, or `deferred`; an effect-owned field is valid only on `one-descendant-commit`, and `deferred` is valid only on `needsBossReply` with presentation-owned `question` and another outcome in that state declaring `one-descendant-commit`.
426
+ Each repository disposition shall be exactly `unchanged`, `one-descendant-commit`, or `deferred`; an effect-owned field is valid on `one-descendant-commit` and `unchanged` and never on `deferred`, and `deferred` is valid only on `needsBossReply` with presentation-owned `question` and another outcome in that state declaring `one-descendant-commit`.
427
427
  The shared factory shall reject every legacy artifact schema and reject schema-3 missing, extra, unknown, wrongly owned, or inconsistent metadata before the affected player call.
428
428
 
429
429
  `init` receives the host-owned playbook session identity and ports, constructs the XState actor with FSM `input` derived from `options`, and starts the actor.
@@ -1081,8 +1081,11 @@ field shall satisfy the result map's required-field type before any actor
1081
1081
  output is delivered.
1082
1082
  The reconciler shall construct the complete actor output rather than accept a
1083
1083
  cross-authority object from the judge: every presentation-owned payload field
1084
- shall receive the canonical `finalText.trim()` value, effect-owned
1085
- `latestCommit` shall receive only the qualifying receipt's exact commit OID,
1084
+ shall receive the canonical `finalText.trim()` value; every effect-owned
1085
+ field shall receive only the qualifying receipt's repository fact selected by
1086
+ the accepted outcome's declared disposition — the exact new-descendant commit
1087
+ OID on `one-descendant-commit`, or the matching `unchanged` receipt's
1088
+ observed HEAD OID on `unchanged` — never a value keyed on the field's name;
1086
1089
  and no authority may supply, overwrite, or contradict another authority's
1087
1090
  field.
1088
1091
  It shall reject an absent required field, an undeclared or extra field, a
@@ -1092,8 +1095,12 @@ inconsistent candidate before FSM delivery.
1092
1095
  For a non-deferred candidate, reconciliation shall require a complete durable
1093
1096
  physical receipt, or the complete cumulative logical receipt of a deferred
1094
1097
  operation, whose classification is exactly the outcome's declared
1095
- `unchanged` or `one-descendant-commit` disposition; the latter shall carry
1096
- exactly the after-HEAD OID used for `latestCommit`.
1098
+ `unchanged` or `one-descendant-commit` disposition; a `one-descendant-commit`
1099
+ receipt shall carry exactly the after-HEAD OID used for the arm's effect-owned
1100
+ fields, while an `unchanged` receipt's complete validated observation supplies
1101
+ its observed HEAD OID for them, and a receipt that cannot prove that observed
1102
+ HEAD shall leave the envelope unresolved rather than inject a fabricated
1103
+ value.
1097
1104
  A `deferred` candidate shall be admissible only for its already-validated
1098
1105
  effect-authorized `needsBossReply` outcome and only from a complete after
1099
1106
  observation whose HEAD equals the logical operation's original baseline HEAD
@@ -2444,6 +2451,22 @@ This spec is silent on the choice; the contract is the same in any location.
2444
2451
 
2445
2452
  New behavior in any of these areas requires a separate slc spec.
2446
2453
 
2454
+ ## Compiled execution
2455
+
2456
+ This section governs compiled execution of this phase; the rules above remain the transformation's normative content for both execution paths.
2457
+
2458
+ 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:
2459
+
2460
+ > 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.
2461
+ > If the Source cannot be transformed under the definition, do not guess: leave the Target unwritten and report the concrete reason.
2462
+ > --- DEFINITION ---
2463
+ > \<definition\>
2464
+ > --- END DEFINITION ---
2465
+
2466
+ Results:
2467
+ - `compiled`: Captain wrote the named Target as the relayed definition specifies.
2468
+ - `rejected`: Captain reported that the Source cannot be transformed under the relayed definition and left the Target unwritten.
2469
+
2447
2470
  ## References
2448
2471
 
2449
2472
  [1]: text2gears.md "First phase: text → GEARS spec items."
package/slc/text2gears.md CHANGED
@@ -79,6 +79,9 @@ If Source supplies a blockquoted template for that relay, text2gears shall keep
79
79
  If Source names the relayed value but supplies no template, text2gears shall emit its canonical typed placeholder on a line beginning with literal `> ` and shall not summarize, paraphrase, or invent a value in its place.
80
80
  An ordinary Source blockquote that specifies a complete acting prompt without requiring quoted relay retains the existing rule above: its one leading marker is Source syntax and is not prompt content.
81
81
 
82
+ An acting prompt whose instructions refer to a runtime value the acting role cannot otherwise observe — for example the Boss input task that triggered the workflow — shall relay that value as a quoted `<placeholder>` line appended to the prompt even when Source states no explicit relay.
83
+ A prompt that references an undelivered value asks its player to act on data it never received; omitting the relay is a compilation defect, not a faithful rendering of Source.
84
+
82
85
  Source statements that assign active-leaf routing, call identity, suspension,
83
86
  or return matching to the host describe execution preconditions rather than
84
87
  behaviors for Captain to perform. text2gears shall use such a statement only as
@@ -318,7 +321,8 @@ exact English form regardless of Source language.
318
321
  ## Transformation-spec sources
319
322
 
320
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.
321
- 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.
322
326
  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.
323
327
  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.
324
328
 
@@ -349,6 +353,22 @@ Partition items by every variable that determines prompt content — including a
349
353
  Drop disjunctive branches incompatible with the rest of an item's condition or prompt.
350
354
  Dead branches mislead readers and downstream phases.
351
355
 
356
+ ## Compiled execution
357
+
358
+ This section governs compiled execution of this phase; the rules above remain the transformation's normative content for both execution paths.
359
+
360
+ 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:
361
+
362
+ > 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.
363
+ > If the Source cannot be transformed under the definition, do not guess: leave the Target unwritten and report the concrete reason.
364
+ > --- DEFINITION ---
365
+ > \<definition\>
366
+ > --- END DEFINITION ---
367
+
368
+ Results:
369
+ - `compiled`: Captain wrote the named Target as the relayed definition specifies.
370
+ - `rejected`: Captain reported that the Source cannot be transformed under the relayed definition and left the Target unwritten.
371
+
352
372
  ## References
353
373
 
354
374
  [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)
@@ -1242,9 +1242,12 @@ function snapshotOutcomeAuthority(descriptor, label, playerStates, verbatimPaylo
1242
1242
  !REPOSITORY_DISPOSITIONS.has(disposition)) {
1243
1243
  throw new TypeError(`${outcomePath}.repositoryDisposition must be unchanged, one-descendant-commit, or deferred`);
1244
1244
  }
1245
- if (disposition !== 'one-descendant-commit' &&
1245
+ // DR-045: an unchanged arm may declare effect-owned fields (injected
1246
+ // from the matching unchanged receipt's observed HEAD); only deferred
1247
+ // arms remain barred from effect ownership.
1248
+ if (disposition === 'deferred' &&
1246
1249
  Object.values(fields).includes('effect')) {
1247
- throw new TypeError(`${outcomePath} may declare effect-owned fields only for one-descendant-commit`);
1250
+ throw new TypeError(`${outcomePath} may not declare effect-owned fields for deferred`);
1248
1251
  }
1249
1252
  outcomes[outcome] = Object.freeze({
1250
1253
  fields: Object.freeze(fields),
@@ -2226,12 +2226,15 @@ function snapshotOutcomeAuthority(
2226
2226
  `${outcomePath}.repositoryDisposition must be unchanged, one-descendant-commit, or deferred`,
2227
2227
  );
2228
2228
  }
2229
+ // DR-045: an unchanged arm may declare effect-owned fields (injected
2230
+ // from the matching unchanged receipt's observed HEAD); only deferred
2231
+ // arms remain barred from effect ownership.
2229
2232
  if (
2230
- disposition !== 'one-descendant-commit' &&
2233
+ disposition === 'deferred' &&
2231
2234
  Object.values(fields).includes('effect')
2232
2235
  ) {
2233
2236
  throw new TypeError(
2234
- `${outcomePath} may declare effect-owned fields only for one-descendant-commit`,
2237
+ `${outcomePath} may not declare effect-owned fields for deferred`,
2235
2238
  );
2236
2239
  }
2237
2240
  outcomes[outcome] = Object.freeze({
@@ -892,7 +892,19 @@ export function reconcilePlaybookSemanticEvidence(input) {
892
892
  value = finalText;
893
893
  }
894
894
  else if (authority === 'effect') {
895
- value = field === 'latestCommit' ? receipt.commitOid : undefined;
895
+ // DR-045: effect injection selects by the accepted arm's declared
896
+ // repository disposition, never by the field's name. A
897
+ // one-descendant-commit arm's effect fields carry the qualifying
898
+ // receipt's exact new-descendant commit OID; an unchanged arm's effect
899
+ // fields carry the matching unchanged receipt's observed HEAD OID. A
900
+ // deferred arm declares no effect field, and any shape the validated
901
+ // receipt cannot prove fails closed as unresolved.
902
+ value =
903
+ disposition === 'one-descendant-commit'
904
+ ? receipt.commitOid
905
+ : disposition === 'unchanged'
906
+ ? receipt.after?.head
907
+ : undefined;
896
908
  if (value === undefined) {
897
909
  return unresolvedSemanticEvidence('missing-effect-evidence', evidence);
898
910
  }
@@ -1416,7 +1416,19 @@ export function reconcilePlaybookSemanticEvidence(
1416
1416
  } else if (authority === 'presentation') {
1417
1417
  value = finalText;
1418
1418
  } else if (authority === 'effect') {
1419
- value = field === 'latestCommit' ? receipt.commitOid : undefined;
1419
+ // DR-045: effect injection selects by the accepted arm's declared
1420
+ // repository disposition, never by the field's name. A
1421
+ // one-descendant-commit arm's effect fields carry the qualifying
1422
+ // receipt's exact new-descendant commit OID; an unchanged arm's effect
1423
+ // fields carry the matching unchanged receipt's observed HEAD OID. A
1424
+ // deferred arm declares no effect field, and any shape the validated
1425
+ // receipt cannot prove fails closed as unresolved.
1426
+ value =
1427
+ disposition === 'one-descendant-commit'
1428
+ ? receipt.commitOid
1429
+ : disposition === 'unchanged'
1430
+ ? receipt.after?.head
1431
+ : undefined;
1420
1432
  if (value === undefined) {
1421
1433
  return unresolvedSemanticEvidence('missing-effect-evidence', evidence);
1422
1434
  }