@rulvar/core 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +524 -532
  2. package/dist/index.js +316 -326
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
14
14
  //#region src/l0/errors.ts
15
15
  /**
16
16
  * Base class for all engine-raised errors. "Retryable" means the engine's
17
- * own retry machinery (RetryPolicy under the journal, docs/04) MAY retry;
17
+ * own retry machinery (RetryPolicy under the journal) MAY retry;
18
18
  * it never means a provider SDK autoretry, which is disabled.
19
19
  */
20
20
  var RulvarError = class extends Error {
@@ -79,8 +79,8 @@ var ScriptRejected = class extends RulvarError {
79
79
  };
80
80
  /**
81
81
  * Refusal to open a journal whose hashVersion falls outside the engine's
82
- * support window (docs/03, section "hashVersion"; producers ship in M2).
83
- * The registry code is 'journal_compat'; the docs/03 sub-codes live on
82
+ * support window (producers ship in M2).
83
+ * The registry code is 'journal_compat'; the sub-codes live on
84
84
  * `subCode` and in `data`.
85
85
  */
86
86
  var JournalCompatibilityError = class extends RulvarError {
@@ -118,8 +118,7 @@ var JournalCompatibilityError = class extends RulvarError {
118
118
  };
119
119
  /**
120
120
  * A resolution attempt against an already-closed suspension, rejected under
121
- * the first-closing-wins fold; appends no entry (docs/03, section
122
- * "Suspension and resolutions"; producers ship in M2).
121
+ * the first-closing-wins fold; appends no entry (producers ship in M2).
123
122
  */
124
123
  var InvalidResolutionError = class extends RulvarError {
125
124
  code = "invalid_resolution";
@@ -132,7 +131,7 @@ var InvalidResolutionError = class extends RulvarError {
132
131
  };
133
132
  /**
134
133
  * A breach of the total per-run append order: an unfenced concurrent writer
135
- * or a store violating contract A2 (docs/03, section "Storage SPI").
134
+ * or a store violating contract A2 (https://docs.rulvar.com/guide/stores).
136
135
  */
137
136
  var JournalOrderViolation = class extends RulvarError {
138
137
  code = "journal_order_violation";
@@ -143,7 +142,7 @@ var JournalOrderViolation = class extends RulvarError {
143
142
  });
144
143
  }
145
144
  };
146
- /** PlanRunner plan-invariant rejection (docs/07; producers ship in M7). */
145
+ /** PlanRunner plan-invariant rejection (producers ship in M7). */
147
146
  var PlanInvariantError = class extends RulvarError {
148
147
  code = "plan_invariant";
149
148
  constructor(message, opts) {
@@ -155,7 +154,7 @@ var PlanInvariantError = class extends RulvarError {
155
154
  };
156
155
  /**
157
156
  * Raised at resume when the refolded plan state disagrees with the
158
- * journaled planHash chain (docs/07; producers ship in M7).
157
+ * journaled planHash chain (producers ship in M7).
159
158
  */
160
159
  var ReplayPlanHashMismatch = class extends RulvarError {
161
160
  code = "replay_plan_hash_mismatch";
@@ -168,8 +167,7 @@ var ReplayPlanHashMismatch = class extends RulvarError {
168
167
  };
169
168
  /**
170
169
  * Invalid orchestrator cap and finalize-reserve configuration, thrown
171
- * before the first LLM call (docs/06, section "Three-layer budget", DEF-7;
172
- * producers ship in M6/M7).
170
+ * before the first LLM call (DEF-7; producers ship in M6/M7).
173
171
  */
174
172
  var OrchestratorCapConfigError = class extends RulvarError {
175
173
  code = "orchestrator_cap_config";
@@ -196,8 +194,7 @@ var JournalMissError = class extends RulvarError {
196
194
  /**
197
195
  * The run budget ceiling blocked further work. The budget guard denial is
198
196
  * a decision entry; ctx primitives throw this as AgentError kind 'budget';
199
- * the run reports outcome 'exhausted', overriding 'error' (docs/06, section
200
- * "Three-layer budget").
197
+ * the run reports outcome 'exhausted', overriding 'error'.
201
198
  */
202
199
  var BudgetExhaustedError = class extends RulvarError {
203
200
  code = "budget_exhausted";
@@ -210,13 +207,12 @@ var BudgetExhaustedError = class extends RulvarError {
210
207
  };
211
208
  /**
212
209
  * A structural admission rejection (maxDepth, maxChildrenPerNode,
213
- * maxTotalSpawns) from the AdmissionController (docs/07, section
214
- * "AdmissionController"; M6-T06). The rejection verdict is embedded in
210
+ * maxTotalSpawns) from the AdmissionController (M6-T06). The rejection verdict is embedded in
215
211
  * the carrying spawn-admission decision entry and replays identically;
216
212
  * the error surfaces the embedded AdmitRejectReason in `data` to the
217
213
  * caller (a typed tool error for orchestrators) and MUST NOT tear down
218
214
  * the run. Budget-code rejections throw BudgetExhaustedError instead,
219
- * keeping the docs/06 5.7 exhaustion semantics.
215
+ * keeping the budget exhaustion semantics (https://docs.rulvar.com/guide/budgets).
220
216
  */
221
217
  var AdmissionRejectedError = class extends RulvarError {
222
218
  code = "admission_rejected";
@@ -228,8 +224,8 @@ var AdmissionRejectedError = class extends RulvarError {
228
224
  }
229
225
  };
230
226
  /**
231
- * A WorkerSandboxRunner resource-limit breach (docs/06, section 8.2;
232
- * M6-T02): crossing timeoutMs or memoryMb terminates the worker and the
227
+ * A WorkerSandboxRunner resource-limit breach (M6-T02): crossing
228
+ * timeoutMs or memoryMb terminates the worker and the
233
229
  * run completes with outcome 'error' carrying this error's WireError
234
230
  * projection; `data` records { reason: 'timeout' | 'memory', limit }.
235
231
  * The class itself is never journaled as an entry of its own.
@@ -245,8 +241,7 @@ var SandboxError = class extends RulvarError {
245
241
  };
246
242
  /**
247
243
  * acquire() on a currently held lease. Retryable by contract: retry after
248
- * the lease ttl elapses or the holder releases (docs/03, section
249
- * "Storage SPI").
244
+ * the lease ttl elapses or the holder releases.
250
245
  */
251
246
  var LeaseHeldError = class extends RulvarError {
252
247
  code = "lease_held";
@@ -260,8 +255,7 @@ var LeaseHeldError = class extends RulvarError {
260
255
  /**
261
256
  * commit() on a ModelKnowledgeStore against a snapshot version that is
262
257
  * no longer current. Retryable by contract: re-read current(), rebase
263
- * the ops, commit again, mirroring the lease fencing discipline
264
- * (docs/05, section "Commit discipline").
258
+ * the ops, commit again, mirroring the lease fencing discipline.
265
259
  */
266
260
  var KnowledgeCasError = class extends RulvarError {
267
261
  code = "knowledge_cas";
@@ -274,8 +268,8 @@ var KnowledgeCasError = class extends RulvarError {
274
268
  };
275
269
  /**
276
270
  * Projects an AgentError to its WireError form: code 'agent', with kind,
277
- * retryAfterMs, and issues carried in data (docs/02, section "Error
278
- * taxonomy"). Issue paths are flattened to JSON-safe segments.
271
+ * retryAfterMs, and issues carried in data. Issue paths are flattened to
272
+ * JSON-safe segments.
279
273
  */
280
274
  function agentErrorToWire(error, message) {
281
275
  const data = { kind: error.kind };
@@ -319,8 +313,7 @@ function agentErrorFromWire(wire) {
319
313
  //#region src/l0/serialization.ts
320
314
  /**
321
315
  * The L0 serialization hook and the default secret-masking policy
322
- * (M8-T04; docs/03, section "Serialization hook"; docs/09, section
323
- * "Redaction and sensitive data"; OQ-20/OQ-22 interim rules executed).
316
+ * (M8-T04; OQ-20/OQ-22 interim rules executed).
324
317
  *
325
318
  * The hook is the single policy point between the engine and
326
319
  * persistence: redact/encrypt at the append and put boundaries,
@@ -336,13 +329,13 @@ function agentErrorFromWire(wire) {
336
329
  * emitted WorkflowEvent passes it (opt out per engine via
337
330
  * `redaction: { maskEvents: false }`); the OTel exporter applies it to
338
331
  * string attributes. It masks strings that look like credentials; it is
339
- * deliberately conservative (docs/09, section 8: the pattern set is
332
+ * deliberately conservative (the pattern set is
340
333
  * tuned on dogfood payloads, OQ-22 stays open for that).
341
334
  */
342
335
  /**
343
336
  * The kernel orders and matches on these BEFORE values are consulted;
344
337
  * a hook that rewrites them would corrupt replay silently, so drift is
345
- * a loud ConfigError at the boundary (docs/03, 12.8).
338
+ * a loud ConfigError at the boundary.
346
339
  */
347
340
  const PINNED_FIELDS = [
348
341
  "hashVersion",
@@ -543,8 +536,7 @@ function monotonicUlidFactory(options) {
543
536
  //#region src/l0/messages.ts
544
537
  /**
545
538
  * Returns a per-engine minter of CanonicalId values. Monotonic within the
546
- * factory instance; never a module-level singleton (docs/02, section
547
- * "Dependency rules": no module state).
539
+ * factory instance; never a module-level singleton (no module state).
548
540
  */
549
541
  function createCanonicalIdMinter(options) {
550
542
  return monotonicUlidFactory(options);
@@ -1442,8 +1434,7 @@ var Validator = class {
1442
1434
  /**
1443
1435
  * RFC 8785 (JSON Canonicalization Scheme) serializer.
1444
1436
  *
1445
- * Backs content-key derivation and schema hashing (docs/03, sections
1446
- * "Identity model" and "schemaHash and toolsetHash derivation"):
1437
+ * Backs content-key derivation and schema hashing:
1447
1438
  * lexicographically sorted object members (UTF-16 code units), minimal
1448
1439
  * escaping, no insignificant whitespace, ECMAScript number formatting.
1449
1440
  *
@@ -1488,8 +1479,8 @@ function jcsSerialize(value) {
1488
1479
  * SchemaSpec, Out<S> inference, JSON Schema projection, canonical schema
1489
1480
  * derivation, and the schemaHash/toolsetHash functions (M1-T03).
1490
1481
  *
1491
- * Owning specs: docs/08-tools-permissions-spec.md, section "SchemaSpec";
1492
- * docs/03-journal-spec.md, section "schemaHash and toolsetHash derivation".
1482
+ * Public contracts: https://docs.rulvar.com/guide/tools (SchemaSpec) and
1483
+ * https://docs.rulvar.com/guide/journal (hash derivation).
1493
1484
  */
1494
1485
  /**
1495
1486
  * Form-1 guard: the value implements the Standard Schema interface. Some
@@ -1504,8 +1495,7 @@ function isSchemaPairSpec(spec) {
1504
1495
  return typeof spec === "object" && spec !== null && !("~standard" in spec) && "jsonSchema" in spec && typeof spec.validate === "function";
1505
1496
  }
1506
1497
  /**
1507
- * Derives the JSON Schema of a SchemaSpec (docs/08, section "JSON Schema
1508
- * derivation and acceptance rules"). Form 1 projects via the
1498
+ * Derives the JSON Schema of a SchemaSpec. Form 1 projects via the
1509
1499
  * StandardJSONSchemaV1 input() converter, target draft 2020-12 with
1510
1500
  * draft-07 fallback; a library without the projection is a typed
1511
1501
  * ConfigError at definition time, never at first call. Transforming
@@ -1532,8 +1522,7 @@ function projectToJsonSchema(spec) {
1532
1522
  }
1533
1523
  /**
1534
1524
  * Annotation-only keywords stripped by canonicalization; `format` is
1535
- * retained because it is validation-relevant in the vendored validator
1536
- * (docs/03, section "schemaHash and toolsetHash derivation").
1525
+ * retained because it is validation-relevant in the vendored validator.
1537
1526
  */
1538
1527
  const ANNOTATION_KEYWORDS = /* @__PURE__ */ new Set([
1539
1528
  "title",
@@ -1577,8 +1566,7 @@ const SUBSCHEMA_ARRAY_KEYWORDS = /* @__PURE__ */ new Set([
1577
1566
  /**
1578
1567
  * Keywords that are pure reference infrastructure: dead weight once every
1579
1568
  * local $ref has been inlined, removed from the canonical form so that a
1580
- * $defs rename or an unused definition never shifts a content key
1581
- * (docs/03, section "schemaHash and toolsetHash derivation").
1569
+ * $defs rename or an unused definition never shifts a content key.
1582
1570
  */
1583
1571
  const REF_INFRASTRUCTURE_KEYWORDS = /* @__PURE__ */ new Set([
1584
1572
  "$defs",
@@ -1652,8 +1640,7 @@ function canonicalizeNode(node, root, refStack) {
1652
1640
  return out;
1653
1641
  }
1654
1642
  /**
1655
- * Canonical schema derivation (docs/03, section "schemaHash and
1656
- * toolsetHash derivation"): local fragment-only $ref inlined (recursion is
1643
+ * Canonical schema derivation: local fragment-only $ref inlined (recursion is
1657
1644
  * a ConfigError), remote and dynamic references forbidden, annotation
1658
1645
  * keywords stripped (format retained), reference infrastructure ($defs,
1659
1646
  * definitions, $anchor) removed once inlined. The result feeds JCS
@@ -1667,8 +1654,7 @@ function sha256Hex$3(text) {
1667
1654
  }
1668
1655
  /**
1669
1656
  * The schemaHash used when no structured-output schema is declared: the
1670
- * hash of the canonical `true` schema (docs/03, section "schemaHash and
1671
- * toolsetHash derivation").
1657
+ * hash of the canonical `true` schema.
1672
1658
  */
1673
1659
  const EMPTY_SCHEMA_HASH = sha256Hex$3("true");
1674
1660
  /** The toolsetHash of an empty toolset: the hash of the canonical empty contract array. */
@@ -1691,8 +1677,7 @@ function schemaHashOfSpec(spec) {
1691
1677
  * contract tuples (name, description, canonical parameters, version)
1692
1678
  * sorted by name. Tool description IS part of the contract; schema
1693
1679
  * annotations inside parameters are not. An absent version participates as
1694
- * absent (docs/03, section "schemaHash and toolsetHash derivation";
1695
- * docs/08, section "toolsetHash contract").
1680
+ * absent.
1696
1681
  */
1697
1682
  function toolsetHash(contracts) {
1698
1683
  return sha256Hex$3(jcsSerialize([...contracts].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0).map((contract) => {
@@ -1714,7 +1699,7 @@ function pointerToPath(instanceLocation) {
1714
1699
  });
1715
1700
  }
1716
1701
  /**
1717
- * Runtime validation per form (docs/08, section "Runtime validation"):
1702
+ * Runtime validation per form:
1718
1703
  * form 1 via the Standard Schema's own validate, form 2 via the pair's
1719
1704
  * type guard, form 3 via the vendored draft 2020-12 validator. The same
1720
1705
  * machinery backs the structured-output tiers of the Agent Runtime.
@@ -1767,8 +1752,7 @@ const CURRENT_HASH_VERSION = 2;
1767
1752
  /**
1768
1753
  * Round-1 normalization: hashVersion is taken from `hashVersion`, else
1769
1754
  * from the legacy `v` field, else 1. Stores are never rewritten;
1770
- * normalization happens at read (docs/03, section "The single versioning
1771
- * mechanism").
1755
+ * normalization happens at read.
1772
1756
  */
1773
1757
  function normalizeEntry(raw) {
1774
1758
  const record = raw;
@@ -1783,15 +1767,15 @@ function normalizeEntry(raw) {
1783
1767
  //#endregion
1784
1768
  //#region src/knowledge/decay.ts
1785
1769
  /**
1786
- * Grounding and decay (M11-T03; docs/05, section "Grounding and
1787
- * decay"). The decay owner: the asymmetric TTL table, the expiry
1770
+ * Grounding and decay (M11-T03). The decay owner: the asymmetric
1771
+ * TTL table, the expiry
1788
1772
  * filter the read path applies at every pin AND repin (M10-T03), the
1789
1773
  * re-measurement queue (a STATUS FILTER, not infrastructure), and the
1790
1774
  * archive-never-delete maintenance helpers (historical runs keep their
1791
1775
  * audit trail).
1792
1776
  */
1793
1777
  /**
1794
- * The asymmetric TTL table (docs/05, section "Grounding and decay"):
1778
+ * The asymmetric TTL table:
1795
1779
  * a false negative is costlier through lock-in, so weaknesses expire
1796
1780
  * sooner than strengths.
1797
1781
  */
@@ -1807,14 +1791,14 @@ const CLAIM_TTL_DAYS = {
1807
1791
  };
1808
1792
  /** Inbox proposals expire after 14 days (reserved for M12 phase 3). */
1809
1793
  const INBOX_PROPOSAL_TTL_DAYS = 14;
1810
- /** The docs/05 TTL applied to an observedAt ISO date. */
1794
+ /** The asymmetric TTL applied to an observedAt ISO date. */
1811
1795
  function claimExpiry(claimClass, polarity, observedAt) {
1812
1796
  const base = Date.parse(observedAt);
1813
1797
  if (Number.isNaN(base)) throw new ConfigError(`claimExpiry: observedAt is not a date: '${observedAt}'`);
1814
1798
  const days = CLAIM_TTL_DAYS[claimClass][polarity];
1815
1799
  return new Date(base + days * 864e5).toISOString();
1816
1800
  }
1817
- /** True when the claim steers nothing at `at` (docs/05, read-path filters). */
1801
+ /** True when the claim steers nothing at `at` (the read-path filter). */
1818
1802
  function claimExpired(claim, at) {
1819
1803
  const expiry = Date.parse(claim.expiresAt);
1820
1804
  const now = Date.parse(at);
@@ -1824,7 +1808,7 @@ function ttlState(claim, at) {
1824
1808
  return claimExpired(claim, at) ? "expired" : "holds";
1825
1809
  }
1826
1810
  /**
1827
- * The re-measurement queue (docs/05, section "Grounding and decay"):
1811
+ * The re-measurement queue:
1828
1812
  * expired eval-measured claims that are still ACTIVE. Just a status
1829
1813
  * filter: the next sweep re-measures these subjects; nothing archives
1830
1814
  * them (archiving would empty the queue and hide the decay).
@@ -1833,9 +1817,9 @@ function remeasureQueue(claims, at) {
1833
1817
  return claims.filter((claim) => claim.status === "active" && claim.class === "eval-measured" && claimExpired(claim, at));
1834
1818
  }
1835
1819
  /**
1836
- * Deprecation maintenance (docs/05: "deprecations, which archive
1837
- * claims, never delete them, so historical runs keep their audit
1838
- * trail"): archive ops for every non-terminal claim of the deprecated
1820
+ * Deprecation maintenance (deprecations archive claims, never delete
1821
+ * them, so historical runs keep their audit trail): archive ops for
1822
+ * every non-terminal claim of the deprecated
1839
1823
  * models. The caller commits them under its own gate-free archive ops.
1840
1824
  */
1841
1825
  function archiveDeprecatedModelOps(claims, deprecated) {
@@ -1849,8 +1833,7 @@ function archiveDeprecatedModelOps(claims, deprecated) {
1849
1833
  //#endregion
1850
1834
  //#region src/knowledge/claims.ts
1851
1835
  /**
1852
- * Claim validators, the editorial path (M10-T02; docs/05, sections
1853
- * "Data model", "The human gate", "Grounding and decay"). The types
1836
+ * Claim validators, the editorial path (M10-T02). The types
1854
1837
  * live with the SPI (l0/spi/knowledge.ts); this module owns the
1855
1838
  * RUNTIME enforcement that the types promise:
1856
1839
  *
@@ -1864,9 +1847,19 @@ function archiveDeprecatedModelOps(claims, deprecated) {
1864
1847
  * - statements stay bounded, evidence stays mandatory, TTL fields stay
1865
1848
  * coherent.
1866
1849
  */
1867
- /** docs/06, Appendix A: KB active-claims cap, default 8 per (model, taskClass). */
1850
+ /**
1851
+ * The typed statement template for a proposal-born claim (phase 3):
1852
+ * assembled over the closed enum vocabulary ONLY, so tool-output text
1853
+ * is unquotable into persistence, and model-free, because a claim
1854
+ * statement renders into the knowledge card's notes layer, which never
1855
+ * leaks model names to the orchestrator.
1856
+ */
1857
+ function proposalStatement(proposal) {
1858
+ return `orchestrator-observed ${proposal.polarity} on ${proposal.taskClass}: trigger ${proposal.trigger}`;
1859
+ }
1860
+ /** Appendix A: KB active-claims cap, default 8 per (model, taskClass). */
1868
1861
  const KB_ACTIVE_CLAIMS_CAP = 8;
1869
- /** docs/05, section "Data model": statement <= 200 chars. */
1862
+ /** The committed data model bound: statement <= 200 chars. */
1870
1863
  const CLAIM_STATEMENT_MAX_CHARS = 200;
1871
1864
  const RULED_OUT_VOCABULARY = /* @__PURE__ */ new Set([
1872
1865
  "prompt",
@@ -1913,8 +1906,8 @@ function claimIssues(claim, path, options) {
1913
1906
  return issues;
1914
1907
  }
1915
1908
  /**
1916
- * The coherence square of the committer identity (docs/05, 5.4;
1917
- * M11-T01): an eval-committer-gated claim MUST be eval-measured,
1909
+ * The coherence square of the committer identity (M11-T01): an
1910
+ * eval-committer-gated claim MUST be eval-measured,
1918
1911
  * authored by the eval pipeline, and carry metrics; anything else is
1919
1912
  * an identity mismatch, schema-enforced.
1920
1913
  */
@@ -1941,7 +1934,7 @@ function claimOpIssues(op, index) {
1941
1934
  return issues;
1942
1935
  }
1943
1936
  /**
1944
- * The commit-time cap (docs/06, Appendix A): active claims per
1937
+ * The commit-time cap (Appendix A): active claims per
1945
1938
  * (model, taskClass) after the batch applies. Supersede chains keep
1946
1939
  * only the head active by construction (applyClaimOps flips the prior
1947
1940
  * to 'superseded'), so a supersede never grows the count.
@@ -1971,8 +1964,7 @@ function validateEditorialCommit(ops, claimsAfter, options) {
1971
1964
  //#endregion
1972
1965
  //#region src/knowledge/epoch.ts
1973
1966
  /**
1974
- * modelEpoch capture (M11-T04; docs/05, section "Grounding and
1975
- * decay"). An HONESTLY COARSE signal: the registry version, the
1967
+ * modelEpoch capture (M11-T04). An HONESTLY COARSE signal: the registry version, the
1976
1968
  * price-table version, and the caps hash catch overt model swaps and
1977
1969
  * deprecations; silent alias re-pointing is a documented uncaught case
1978
1970
  * absent probes (the canary fingerprint in @rulvar/evals compensates,
@@ -1999,8 +1991,7 @@ function modelEpochOf(inputs) {
1999
1991
  * FileModelKnowledgeStore (M10-T01): the default ModelKnowledgeStore, a
2000
1992
  * single JSON file in the project (`./rulvar.models.json`),
2001
1993
  * git-diffable, serverless, embeddable. The git review of that file IS
2002
- * the human gate's medium (docs/05, sections "Data model" and "Format
2003
- * decision rationale"); the store itself only enforces the mechanics:
1994
+ * the human gate's medium; the store itself only enforces the mechanics:
2004
1995
  * CAS by monotonic version (mirroring the lease fencing discipline),
2005
1996
  * append-only claim evolution (supersede and archive flip status, never
2006
1997
  * delete), and atomic replace on write.
@@ -2130,7 +2121,7 @@ var FileModelKnowledgeStore = class {
2130
2121
  *
2131
2122
  * Named strong default models live ONLY in the umbrella `rulvar`
2132
2123
  * package config, never here: the core ships the floor mechanism, the
2133
- * umbrella ships opinions (docs/04, section "Role quality floors").
2124
+ * umbrella ships opinions.
2134
2125
  */
2135
2126
  function violates(ref, constraint) {
2136
2127
  if (constraint === void 0) return;
@@ -2154,11 +2145,11 @@ function checkFloors(options) {
2154
2145
  }
2155
2146
  //#endregion
2156
2147
  //#region src/knowledge/card.ts
2157
- /** docs/06, Appendix A: the KB card render budget (characters). */
2148
+ /** The KB card render budget (characters). */
2158
2149
  const KB_CARD_RENDER_BUDGET_CHARS = 4096;
2159
2150
  /**
2160
2151
  * The ladders a run declares: every advertised profile whose model
2161
- * spec is a ladder (docs/04, section 12). The card is tier-relative to
2152
+ * spec is a ladder. The card is tier-relative to
2162
2153
  * exactly these.
2163
2154
  */
2164
2155
  function collectDeclaredLadders(profiles) {
@@ -2193,7 +2184,7 @@ function floored(model, taskClass, floors) {
2193
2184
  }
2194
2185
  }
2195
2186
  /**
2196
- * The admission filter (docs/05, 4.1): status active, unexpired at
2187
+ * The admission filter: status active, unexpired at
2197
2188
  * `now`, and the subject reachable through the run's declared ladders
2198
2189
  * after the role-floor filter.
2199
2190
  */
@@ -2211,8 +2202,7 @@ function tiersOf(claim, ladders) {
2211
2202
  return coordinates;
2212
2203
  }
2213
2204
  /**
2214
- * The verified-layer compiler (M11-T06; docs/05, sections "Read path"
2215
- * and "Composition with the model layer"): start-tier recommendations
2205
+ * The verified-layer compiler (M11-T06): start-tier recommendations
2216
2206
  * per (ladder, taskClass) compiled EXCLUSIVELY from eval-measured
2217
2207
  * claims. A strength on a rung below the default votes down (start
2218
2208
  * cheaper); a weakness on the default rung or below votes up. The net
@@ -2257,9 +2247,9 @@ function compileVerifiedLayer(claims, ladders) {
2257
2247
  return rows;
2258
2248
  }
2259
2249
  /**
2260
- * The deterministic card render (docs/05, 4.3). Pure: same filtered
2250
+ * The deterministic card render. Pure: same filtered
2261
2251
  * claims and ladders give byte-identical text. The render budget is
2262
- * docs/06 Appendix A (4096 chars); over it, the OLDEST-observed notes
2252
+ * 4096 chars; over it, the OLDEST-observed notes
2263
2253
  * withhold first behind an explicit marker.
2264
2254
  */
2265
2255
  function modelKnowledgeCard(claims, ladders, options) {
@@ -2271,6 +2261,30 @@ function modelKnowledgeCard(claims, ladders, options) {
2271
2261
  lines.push("Verified layer (start-tier recommendations, clamped one rung from the default):");
2272
2262
  for (const row of verified) lines.push(`- ladder '${row.ladder}', taskClass '${row.taskClass}': start tier ${String(row.recommendedTier)} (default ${String(row.defaultTier)}, eval evidence, ${String(row.votes)} claim${row.votes === 1 ? "" : "s"})`);
2273
2263
  }
2264
+ const profileLines = [];
2265
+ for (const [name, profile] of Object.entries(options?.profiles ?? {}).sort(([left], [right]) => left < right ? -1 : 1)) {
2266
+ const model = profile.model;
2267
+ if (typeof model !== "string") continue;
2268
+ const matched = claims.filter((claim) => claim.class === "eval-measured" && claim.subject.model === model && (profile.effort === void 0 || claim.subject.effort === profile.effort));
2269
+ if (matched.length === 0) continue;
2270
+ const byClass = /* @__PURE__ */ new Map();
2271
+ for (const claim of [...matched].sort((left, right) => left.id < right.id ? -1 : 1)) {
2272
+ const verdict = claim.polarity === "strength" ? "strong" : "weak";
2273
+ const prior = byClass.get(claim.taskClass);
2274
+ byClass.set(claim.taskClass, prior === "weak" ? "weak" : verdict);
2275
+ }
2276
+ const strong = [...byClass.entries()].filter(([, verdict]) => verdict === "strong").map(([taskClass]) => taskClass).sort();
2277
+ const weak = [...byClass.entries()].filter(([, verdict]) => verdict === "weak").map(([taskClass]) => taskClass).sort();
2278
+ const parts = [];
2279
+ if (strong.length > 0) parts.push(`strong ${strong.join(", ")}`);
2280
+ if (weak.length > 0) parts.push(`weak ${weak.join(", ")}`);
2281
+ profileLines.push(`- ${name}: ${parts.join("; ")}`);
2282
+ }
2283
+ if (profileLines.length > 0) {
2284
+ lines.push("Profile evidence (eval-measured, folded over each profile model):");
2285
+ lines.push(...profileLines);
2286
+ lines.push("Spawn guidance: prefer the cheapest profile marked strong for the task at hand; avoid profiles marked weak at it.");
2287
+ }
2274
2288
  const noteLines = claims.filter((claim) => claim.class === "human-editorial").sort((left, right) => left.observedAt === right.observedAt ? left.id < right.id ? -1 : 1 : left.observedAt < right.observedAt ? 1 : -1).map((claim) => {
2275
2289
  return `- [${tiersOf(claim, ladders).join(", ")}] ${claim.taskClass} ${claim.polarity} (confidence ${claim.confidence}, observed ${claim.observedAt}, expires ${claim.expiresAt}): ${claim.statement}`;
2276
2290
  });
@@ -2318,7 +2332,7 @@ function compilePermissionPreset(preset) {
2318
2332
  //#endregion
2319
2333
  //#region src/tools/shell-matcher.ts
2320
2334
  /**
2321
- * Lexes a command into segments per the docs/08 5.2 algorithm. Quotes
2335
+ * Lexes a command into segments per the matching algorithm above. Quotes
2322
2336
  * and escapes are honored; nothing is expanded; `$(`, backticks, `<(`,
2323
2337
  * `>(`, and `<<` (outside single quotes) poison their segment.
2324
2338
  */
@@ -2498,16 +2512,15 @@ function matchShellCommand(command, rules) {
2498
2512
  * execute body never invalidates a journal; changing semantics is
2499
2513
  * signaled by bumping version.
2500
2514
  *
2501
- * Owning spec: docs/08-tools-permissions-spec.md, sections "Tool
2502
- * definition and toolsetHash" and "SchemaSpec".
2515
+ * Public docs: https://docs.rulvar.com/guide/tools
2503
2516
  */
2504
- /** First-party provider tool-name constraint intersection (docs/08, section 1.1). */
2517
+ /** First-party provider tool-name constraint intersection. */
2505
2518
  const TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]{1,64}$/;
2506
2519
  /**
2507
2520
  * Defines a tool. Definition-time failures are typed ConfigErrors, never
2508
2521
  * first-call surprises: an illegal name, a Standard Schema without the
2509
2522
  * JSON Schema projection, a recursive local $ref, or a remote/dynamic
2510
- * reference all fail here (docs/08, sections 1.1 and 2.3).
2523
+ * reference all fail here.
2511
2524
  */
2512
2525
  function tool(init) {
2513
2526
  if (!TOOL_NAME_PATTERN.test(init.name)) throw new ConfigError(`tool name '${init.name}' must match ^[a-zA-Z0-9_-]{1,64}$ (docs/08, section "tool() definition and ToolDef")`);
@@ -2526,8 +2539,7 @@ function tool(init) {
2526
2539
  }
2527
2540
  /**
2528
2541
  * The identity projection: the contract tuple that enters toolsetHash.
2529
- * parameters is the canonicalized derived JSON Schema (docs/03, section
2530
- * "schemaHash and toolsetHash derivation").
2542
+ * parameters is the canonicalized derived JSON Schema.
2531
2543
  */
2532
2544
  function toolContract(def) {
2533
2545
  const parameters = canonicalizeSchema(projectToJsonSchema(def.parameters));
@@ -2549,8 +2561,7 @@ function toolContract(def) {
2549
2561
  * for the agent's lifetime; provider-side drift of a source's tools
2550
2562
  * changes the content key of NEW spawns only.
2551
2563
  *
2552
- * Owning spec: docs/08-tools-permissions-spec.md, sections "toolsetHash
2553
- * contract", "ToolSource seam", and "Filtering and prefixing".
2564
+ * Docs: https://docs.rulvar.com/guide/tools.
2554
2565
  */
2555
2566
  /** The empty toolset (no tools declared anywhere). */
2556
2567
  function emptyToolset() {
@@ -2565,8 +2576,8 @@ function isToolDef(spec) {
2565
2576
  }
2566
2577
  /**
2567
2578
  * Expands sources, validates every tool name and duplicate names across
2568
- * the whole toolset (ConfigError at spawn time; docs/08 sections 1.1 and
2569
- * 6.4), and computes the toolsetHash over contracts sorted by name.
2579
+ * the whole toolset (ConfigError at spawn time), and computes the
2580
+ * toolsetHash over contracts sorted by name.
2570
2581
  */
2571
2582
  async function resolveToolset(specs, session) {
2572
2583
  if (specs === void 0 || specs.length === 0) return emptyToolset();
@@ -2622,7 +2633,7 @@ function buildToolContext(seed) {
2622
2633
  * contract. Pinned SDK line: @modelcontextprotocol/sdk ^1.29 (the v2
2623
2634
  * migration is the explicit post-M3 task M5-T10; risk R1).
2624
2635
  *
2625
- * Owning spec: docs/08-tools-permissions-spec.md, section "MCP bus".
2636
+ * Docs: https://docs.rulvar.com/guide/mcp.
2626
2637
  */
2627
2638
  function validateConfig(cfg) {
2628
2639
  const forbid = (key) => {
@@ -2674,7 +2685,7 @@ function errorText(result) {
2674
2685
  * first tools() call; tools/list is fetched with cursor pagination until
2675
2686
  * exhaustion and cached per session; a listChanged notification
2676
2687
  * invalidates the cache, affecting subsequently spawned agents only (a
2677
- * spawn's toolset snapshot is immutable by construction; docs/08 6.3).
2688
+ * spawn's toolset snapshot is immutable by construction).
2678
2689
  */
2679
2690
  function mcp(cfg) {
2680
2691
  validateConfig(cfg);
@@ -2773,13 +2784,12 @@ function mcp(cfg) {
2773
2784
  * retain failed trees under the shared pin cap.
2774
2785
  *
2775
2786
  * The sandbox is a determinism and blast-radius boundary, NOT a security
2776
- * boundary (docs/08, sections 7.2 and 8; docs/01 NFR security posture).
2787
+ * boundary.
2777
2788
  *
2778
- * Owning spec: docs/08-tools-permissions-spec.md, section "Isolation and
2779
- * worktree lifecycle".
2789
+ * Full contract: https://docs.rulvar.com/guide/tools
2780
2790
  */
2781
2791
  const execFileAsync = promisify(execFile);
2782
- /** docs/06 Appendix A: the shared pin cap (park/unpark and retainWorktree). */
2792
+ /** Appendix A: the shared pin cap (park/unpark and retainWorktree). */
2783
2793
  const DEFAULT_MAX_PINNED_WORKTREES = 4;
2784
2794
  async function git(cwd, args) {
2785
2795
  const { stdout } = await execFileAsync("git", [
@@ -2791,7 +2801,7 @@ async function git(cwd, args) {
2791
2801
  }
2792
2802
  /**
2793
2803
  * The shipped git worktree lifecycle. A non-git host is a typed
2794
- * ConfigError at acquire (docs/08, section 8.3, rule 1).
2804
+ * ConfigError at acquire.
2795
2805
  */
2796
2806
  var GitWorktreeProvider = class {
2797
2807
  repoRoot;
@@ -2881,7 +2891,7 @@ var GitWorktreeProvider = class {
2881
2891
  * spawn kind and content-key derivation, sha256 over RFC 8785 JCS
2882
2892
  * canonical JSON. Frozen as part of the hashVersion 2 profile in M2.
2883
2893
  *
2884
- * Owning spec: docs/03-journal-spec.md, section "Identity model" (DEF-6
2894
+ * Identity model contract: https://docs.rulvar.com/guide/journal (DEF-6
2885
2895
  * framing). Excluded from every content key: cosmetics (label, phase),
2886
2896
  * handling policy (onError, retry, replay), policy fields
2887
2897
  * (memoizeOutcome), lineage blocks, and spanId.
@@ -2889,8 +2899,8 @@ var GitWorktreeProvider = class {
2889
2899
  /**
2890
2900
  * The identity projection of a CanonicalModelSpec. For the plain-model
2891
2901
  * kind the projection is `{ model, effort? }` WITHOUT the kind
2892
- * discriminant, exactly as fixed by the docs/03 section 1.5 worked
2893
- * example; `effort` is omitted when unresolved. The ladder embedding lands
2902
+ * discriminant, exactly as frozen by the hashVersion 2 profile;
2903
+ * `effort` is omitted when unresolved. The ladder embedding lands
2894
2904
  * with ladder execution (M7).
2895
2905
  */
2896
2906
  function modelSpecIdentity(spec) {
@@ -2924,7 +2934,7 @@ function identityJcs(input) {
2924
2934
  return jcsSerialize(projectIdentity(input));
2925
2935
  }
2926
2936
  /**
2927
- * key = sha256(JCS(IdentityInput)) (docs/03, section "Content key").
2937
+ * key = sha256(JCS(IdentityInput)).
2928
2938
  */
2929
2939
  function deriveContentKey(input) {
2930
2940
  return createHash("sha256").update(identityJcs(input), "utf8").digest("hex");
@@ -2936,7 +2946,7 @@ function deriveContentKey(input) {
2936
2946
  * of wall-clock (invariant I3: structure comes from call-and-return only).
2937
2947
  * The grammar is part of the hashVersion 2 profile.
2938
2948
  *
2939
- * Owning spec: docs/03-journal-spec.md, section "Scope-path grammar".
2949
+ * Full contract: https://docs.rulvar.com/guide/journal.
2940
2950
  *
2941
2951
  * Segment rules: a sequential body is ONE scope (sequential calls add no
2942
2952
  * segment; they are distinguished by key and ordinal only). ctx.phase is
@@ -3071,12 +3081,12 @@ var ParallelSiteCounter = class {
3071
3081
  * per-engine deriver registry, the support-window compatibility scan, and
3072
3082
  * the versioned KeyRing for matching. A profile is immutable after
3073
3083
  * release and versions the ENTIRE identity and replay pipeline as one
3074
- * unit (docs/03, section "hashVersion").
3084
+ * unit. Full contract: https://docs.rulvar.com/guide/journal-compatibility.
3075
3085
  */
3076
3086
  function sha256Hex$2(text) {
3077
3087
  return createHash("sha256").update(text, "utf8").digest("hex");
3078
3088
  }
3079
- /** The full v2 table; the three kernel amendments live in these rules (docs/03, section 6.3). */
3089
+ /** The full v2 table; the three kernel amendments live in these rules. */
3080
3090
  const V2_TABLE = {
3081
3091
  ok: "replay",
3082
3092
  escalated: "replay",
@@ -3111,7 +3121,7 @@ const deriverV2 = {
3111
3121
  budgetAccount: "root"
3112
3122
  }
3113
3123
  };
3114
- /** Kinds that did not exist in round 1: incomparable under v1 (docs/03, section 4.3). */
3124
+ /** Kinds that did not exist in round 1: incomparable under v1. */
3115
3125
  const V1_INEXPRESSIBLE_KINDS = /* @__PURE__ */ new Set([
3116
3126
  "decision",
3117
3127
  "plan.revision",
@@ -3159,8 +3169,8 @@ function isKeyDeriver(value) {
3159
3169
  }
3160
3170
  /**
3161
3171
  * Builds the per-engine deriver registry: the shipped v1/v2 profiles plus
3162
- * EngineOptions.extraDerivers, the ONLY window extender (docs/03, section
3163
- * 4.5). A malformed extra deriver is a ConfigError before any run effect.
3172
+ * EngineOptions.extraDerivers, the ONLY window extender. A malformed
3173
+ * extra deriver is a ConfigError before any run effect.
3164
3174
  */
3165
3175
  function buildDeriverRegistry(extraDerivers) {
3166
3176
  const registry = /* @__PURE__ */ new Map([[deriverV1.hashVersion, deriverV1], [deriverV2.hashVersion, deriverV2]]);
@@ -3173,7 +3183,7 @@ function buildDeriverRegistry(extraDerivers) {
3173
3183
  /**
3174
3184
  * The one compatibility scan: immediately after load, strictly BEFORE any
3175
3185
  * live call, any append, and any admission reserve; repeated at lease
3176
- * acquire in queue mode (docs/03, section 4.5). Side-effect free.
3186
+ * acquire in queue mode. Side-effect free.
3177
3187
  */
3178
3188
  function scanJournalCompatibility(runId, entries, registry) {
3179
3189
  const versions = [...registry.keys()];
@@ -3197,8 +3207,7 @@ function scanJournalCompatibility(runId, entries, registry) {
3197
3207
  }
3198
3208
  /**
3199
3209
  * KeyRing over the registry: the live call is projected DOWN into the
3200
- * profile of the stored entry; there is no upward canonization (docs/03,
3201
- * section 4.7).
3210
+ * profile of the stored entry; there is no upward canonization.
3202
3211
  */
3203
3212
  function registryKeyRing(registry) {
3204
3213
  return { keyFor(identity, hashVersion) {
@@ -3219,11 +3228,11 @@ function registryKeyRing(registry) {
3219
3228
  * addressable); step 2 applies the per-status table of the ENTRY'S OWN
3220
3229
  * hashVersion profile, carrying the three kernel amendments:
3221
3230
  * memoizeOutcome on task-class failures, abandon-derived skipped, and
3222
- * escalated-replays-as-ok (docs/03, section "Replay predicate (DEF-1)").
3231
+ * escalated-replays-as-ok (https://docs.rulvar.com/guide/journal).
3223
3232
  */
3224
3233
  /**
3225
3234
  * task-class: schema-mismatch, terminal, non-retryable tool. transport,
3226
- * rate-limit, and budget are never memoized (docs/03, section 6.4).
3235
+ * rate-limit, and budget are never memoized.
3227
3236
  */
3228
3237
  function classifyAgentError(e) {
3229
3238
  if (e.kind === "schema-mismatch" || e.kind === "terminal") return "task";
@@ -3232,7 +3241,7 @@ function classifyAgentError(e) {
3232
3241
  }
3233
3242
  /**
3234
3243
  * The child scope-prefix an abandon over `target` covers transitively.
3235
- * Agent spawns nest under agent:<seq> (docs/03, section 2.2); a child
3244
+ * Agent spawns nest under agent:<seq>; a child
3236
3245
  * workflow's subtree runs under the wf:<name>:<ordinal> scope recorded in
3237
3246
  * its dispatch payload (M6-T06). A child entry without the payload
3238
3247
  * (foreign journals) degrades to the agent:<seq> convention, which covers
@@ -3249,7 +3258,7 @@ function childCoveragePrefix(target) {
3249
3258
  * Builds the AbandonFold in ONE pass at load, in append order, pinned for
3250
3259
  * the entire resume (DEF-1 ordering rule 4). Coverage is the target seq
3251
3260
  * itself plus, transitively, every entry under the target's child
3252
- * scope-prefix (docs/03, sections 6.2 and 8.4). Repeated abandons over an
3261
+ * scope-prefix. Repeated abandons over an
3253
3262
  * already-covered target fold to noop.
3254
3263
  */
3255
3264
  function buildAbandonFold(entries) {
@@ -3335,8 +3344,8 @@ function dispositionHook(fold, registry, invalidated) {
3335
3344
  * Lineage: LogicalTaskId, approach signatures, and the counter folds
3336
3345
  * (M7-T02, DEF-3).
3337
3346
  *
3338
- * Owning spec: docs/03-journal-spec.md, section "Lineage (DEF-3)";
3339
- * docs/07-adaptive-orchestration-spec.md, section "Lineage (DEF-3)".
3347
+ * Public contract: https://docs.rulvar.com/guide/journal and
3348
+ * https://docs.rulvar.com/guide/adaptive-orchestration.
3340
3349
  *
3341
3350
  * The LTID answers "is this the same logical task across rebirths".
3342
3351
  * NodeId remains plan-node identity; the content key remains the identity
@@ -3349,9 +3358,9 @@ function dispositionHook(fold, registry, invalidated) {
3349
3358
  * in decision entries are READ on replay, never recomputed; a fold
3350
3359
  * recomputation over the same prefix serves only as an integrity assert.
3351
3360
  */
3352
- /** approachSig/approachSigCoarse derivation version (docs/03, 10.7). */
3361
+ /** approachSig/approachSigCoarse derivation version. */
3353
3362
  const LINEAGE_SIG_VERSION = 1;
3354
- /** Deterministic LTIDs canonized onto legacy journals (docs/03, 10.7). */
3363
+ /** Deterministic LTIDs canonized onto legacy journals. */
3355
3364
  const LEGACY_LTID_PREFIX = "legacy:";
3356
3365
  const DEFAULT_ESCALATION_LIMITS = {
3357
3366
  maxEscalationsPerLogicalTask: 2,
@@ -3377,7 +3386,7 @@ function sha256Hex$1(text) {
3377
3386
  return createHash("sha256").update(text, "utf8").digest("hex");
3378
3387
  }
3379
3388
  /**
3380
- * Approach-tag normalization (docs/03, 10.2): NFC, lowercase, runs of
3389
+ * Approach-tag normalization: NFC, lowercase, runs of
3381
3390
  * non-alphanumerics collapse into a hyphen, truncate to 32 characters; an
3382
3391
  * empty value canonicalizes to 'default'. Prompt prose never enters any
3383
3392
  * signature: rephrasings collide by construction, not by heuristic.
@@ -3386,7 +3395,7 @@ function normalizeApproachTag(raw) {
3386
3395
  const collapsed = (raw ?? "").normalize("NFC").toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 32);
3387
3396
  return collapsed === "" ? "default" : collapsed;
3388
3397
  }
3389
- /** The isolation string entering approachSigCoarse (docs/03, 10.3). */
3398
+ /** The isolation string entering approachSigCoarse. */
3390
3399
  function canonicalIsolationTag(spec) {
3391
3400
  if (spec === void 0) return "none";
3392
3401
  return typeof spec === "string" ? spec : spec.kind;
@@ -3394,7 +3403,7 @@ function canonicalIsolationTag(spec) {
3394
3403
  /**
3395
3404
  * approachSigCoarse = sha256(JCS({ sigVersion, agentType, toolsetHash,
3396
3405
  * schemaHash, isolation })). Feeds the stall detector and the oscillation
3397
- * guard, which keys ACROSS LTID boundaries (docs/07, 3.8).
3406
+ * guard, which keys ACROSS LTID boundaries.
3398
3407
  */
3399
3408
  function approachSigCoarse(inputs) {
3400
3409
  return sha256Hex$1(jcsSerialize({
@@ -3417,7 +3426,7 @@ function approachSigOf(coarse, tag) {
3417
3426
  * The deterministic signature inputs assigned to legacy spawns (journals
3418
3427
  * written before lineage existed) and to attempts whose producers did not
3419
3428
  * record signature inputs: stable constants, never wall-clock, so replay
3420
- * canonizes identically on every engine (docs/03, 10.7).
3429
+ * canonizes identically on every engine.
3421
3430
  */
3422
3431
  const LEGACY_SIGNATURE_INPUTS = {
3423
3432
  agentType: "legacy",
@@ -3441,7 +3450,7 @@ function classifyAttemptOutcome(terminal) {
3441
3450
  default: return "task-error";
3442
3451
  }
3443
3452
  }
3444
- /** Outcome classes that lengthen the stall streak (docs/03, 10.4). */
3453
+ /** Outcome classes that lengthen the stall streak. */
3445
3454
  const STALLING_OUTCOMES = /* @__PURE__ */ new Set([
3446
3455
  "task-error",
3447
3456
  "no-progress",
@@ -3459,7 +3468,7 @@ function asRecord$2(value) {
3459
3468
  * Reads the computed SpawnLineage block of a decision payload, tolerating
3460
3469
  * pre-DEF-3 producers (M6 journals): a verdict lineage block without
3461
3470
  * signatures canonizes onto the deterministic legacy signature constants,
3462
- * so folds over old journals stay byte-stable (docs/03, 10.7).
3471
+ * so folds over old journals stay byte-stable.
3463
3472
  */
3464
3473
  function readSpawnLineage(decision) {
3465
3474
  if (decision === void 0) return;
@@ -3484,8 +3493,7 @@ function readSpawnLineage(decision) {
3484
3493
  * The incremental lineage fold: attempts, escalation debits, stall
3485
3494
  * streaks, single-live-attempt, and legacy canonization, computed from
3486
3495
  * journal entries only. `absorb` is idempotent by seq cursor; every read
3487
- * accepts an optional `uptoSeq` pin so renders stay snapshot-stable
3488
- * (docs/03, 10.4; docs/07, 8.3).
3496
+ * accepts an optional `uptoSeq` pin so renders stay snapshot-stable.
3489
3497
  */
3490
3498
  var LineageIndex = class {
3491
3499
  attemptsByLtid = /* @__PURE__ */ new Map();
@@ -3671,7 +3679,7 @@ var LineageIndex = class {
3671
3679
  * attempt whose bound key matches (an at-least-once redispatch of the
3672
3680
  * same slot after cancelled/error/limit); else a legacy attempt is
3673
3681
  * canonized with the deterministic 'legacy:' + contentHash LTID
3674
- * (docs/03, 10.7: random ULIDs on replay are forbidden).
3682
+ * (random ULIDs on replay are forbidden).
3675
3683
  */
3676
3684
  bindRoot(slotScope, entry) {
3677
3685
  const queue = this.queueByScope.get(slotScope) ?? [];
@@ -3721,13 +3729,13 @@ var LineageIndex = class {
3721
3729
  * True while the LTID has an unsettled attempt (admitted, dispatched, or
3722
3730
  * redispatched without a terminal), including admits whose decision
3723
3731
  * entries have not landed yet. Backs the single-live-attempt invariant:
3724
- * a competing admit gets `lineage_busy` (docs/03, 10.5).
3732
+ * a competing admit gets `lineage_busy`.
3725
3733
  */
3726
3734
  hasLiveAttempt(logicalTaskId) {
3727
3735
  if ((this.pendingAdmits.get(logicalTaskId) ?? 0) > 0) return true;
3728
3736
  return (this.attemptsByLtid.get(logicalTaskId) ?? []).some((attempt) => attempt.outcome === void 0);
3729
3737
  }
3730
- /** The stall streak per docs/03, 10.4 (pinnable to a snapshot seq). */
3738
+ /** The stall streak (pinnable to a snapshot seq). */
3731
3739
  stallStreak(logicalTaskId, uptoSeq = Number.POSITIVE_INFINITY) {
3732
3740
  let streak = 0;
3733
3741
  for (const attempt of this.attemptsOf(logicalTaskId, uptoSeq)) {
@@ -3741,7 +3749,7 @@ var LineageIndex = class {
3741
3749
  }
3742
3750
  return streak;
3743
3751
  }
3744
- /** The pinned LineageStats render (docs/03, 10.3). */
3752
+ /** The pinned LineageStats render. */
3745
3753
  statsOf(logicalTaskId, uptoSeq = Number.POSITIVE_INFINITY) {
3746
3754
  const attempts = this.attemptsOf(logicalTaskId, uptoSeq);
3747
3755
  const groups = /* @__PURE__ */ new Map();
@@ -3781,8 +3789,8 @@ var LineageIndex = class {
3781
3789
  /**
3782
3790
  * TerminationAccount and the termination lemma (M7-T03, DEF-2).
3783
3791
  *
3784
- * Owning spec: docs/07-adaptive-orchestration-spec.md, section 11;
3785
- * docs/06-execution-spec.md, Appendix A defaults; XF-07/XF-09 cap fields.
3792
+ * Public contract: https://docs.rulvar.com/guide/budgets;
3793
+ * committed defaults declared below; XF-07/XF-09 cap fields.
3786
3794
  *
3787
3795
  * One construction is committed: a single per-run account with an
3788
3796
  * exclusively DEBIT-ONLY API and a limits vector frozen at start in the
@@ -3808,7 +3816,7 @@ function sha256Hex(text) {
3808
3816
  /**
3809
3817
  * Reads the declared ladder length of one agent profile. Ladders are
3810
3818
  * declared through the profile's ModelSpec (`model: { ladder }`, or the
3811
- * loop-role routing entry; docs/04, section 12). The reader is defensive
3819
+ * loop-role routing entry). The reader is defensive
3812
3820
  * so the snapshot is total over every registry shape (an undeclared
3813
3821
  * ladder has length 1: the single implicit rung).
3814
3822
  */
@@ -3829,7 +3837,7 @@ function kMaxOf(profiles) {
3829
3837
  /**
3830
3838
  * The deterministic profile-registry snapshot hash frozen inside
3831
3839
  * termination.init: profile names mapped to their declared ladder
3832
- * lengths, canonical JSON, sha256 (docs/07, 11.6).
3840
+ * lengths, canonical JSON, sha256.
3833
3841
  */
3834
3842
  function profileRegistrySnapshotHash(profiles) {
3835
3843
  const projection = {};
@@ -3871,11 +3879,11 @@ function validateTerminationLimits(raw) {
3871
3879
  function lineageWeightOf(limits) {
3872
3880
  return limits.maxEscalationsPerLogicalTask + limits.kMax;
3873
3881
  }
3874
- /** Phi0 = V0 + C * S0, finite and fixed in termination.init (docs/07, 11.4). */
3882
+ /** Phi0 = V0 + C * S0, finite and fixed in termination.init. */
3875
3883
  function phiInitialOf(limits) {
3876
3884
  return limits.maxRevisionsPerRun + lineageWeightOf(limits) * limits.maxTotalSpawns;
3877
3885
  }
3878
- /** Builds the termination.init value payload (docs/07, 11.6). */
3886
+ /** Builds the termination.init value payload. */
3879
3887
  function buildTerminationInitValue(limits, registrySnapshotHash) {
3880
3888
  return {
3881
3889
  limits,
@@ -3891,7 +3899,7 @@ function readTerminationInit(entry) {
3891
3899
  return value;
3892
3900
  }
3893
3901
  /**
3894
- * Config-drift detection at resume (docs/07, 11.2): the journaled vector
3902
+ * Config-drift detection at resume: the journaled vector
3895
3903
  * always wins; every differing field is reported for the
3896
3904
  * `termination:config-drift` event. Dynamic budget top-up via restart is
3897
3905
  * excluded by construction.
@@ -3909,9 +3917,9 @@ function terminationConfigDrift(frozen, live) {
3909
3917
  return drift;
3910
3918
  }
3911
3919
  /**
3912
- * The single per-run TerminationAccount (docs/07, 11.5): debit ONLY. No
3920
+ * The single per-run TerminationAccount: debit ONLY. No
3913
3921
  * credit operation exists by construction; reclaim never replenishes
3914
- * anything (DEF-5 interaction, docs/07 7.3). Live: the engine debits the
3922
+ * anything (DEF-5 interaction). Live: the engine debits the
3915
3923
  * in-memory account, writes the carrying entry with the balance-after,
3916
3924
  * then applies effects. Resume state is rebuilt by TerminationFold from
3917
3925
  * the journal, never from live config.
@@ -3950,7 +3958,7 @@ var TerminationAccount = class {
3950
3958
  phi: this.phi()
3951
3959
  };
3952
3960
  }
3953
- /** Phi = V + C * S + sum over live lineages (E + R) (docs/07, 11.4). */
3961
+ /** Phi = V + C * S + sum over live lineages (E + R). */
3954
3962
  phi() {
3955
3963
  let phi = this.revisionUnits + lineageWeightOf(this.limits) * this.spawnUnits;
3956
3964
  for (const state of this.lineages.values()) phi += state.escalationUnitsRemaining + state.rungsRemaining;
@@ -3968,7 +3976,7 @@ var TerminationAccount = class {
3968
3976
  return this.revisionUnits;
3969
3977
  }
3970
3978
  /**
3971
- * The spawn-admission debit (docs/07, 11.3b): minus one spawnUnit for
3979
+ * The spawn-admission debit: minus one spawnUnit for
3972
3980
  * an admitted spawn of ANY origin; a NEW lineage receives E0 escalation
3973
3981
  * units and (K_l - 1) rung transitions in the same atomic step, so the
3974
3982
  * lemma's per-spawn decrease is C - (E0 + K_l - 1) = kMax - K_l + 1,
@@ -3996,7 +4004,7 @@ var TerminationAccount = class {
3996
4004
  };
3997
4005
  }
3998
4006
  /**
3999
- * The plan_revise debit (docs/07, 11.3a and 11.7): minus one
4007
+ * The plan_revise debit: minus one
4000
4008
  * revisionUnit on EVERY journaled plan.revision, regardless of the op
4001
4009
  * count, guard verdicts, or the auto-rebase outcome; conflict spam is
4002
4010
  * never a free retry.
@@ -4013,7 +4021,7 @@ var TerminationAccount = class {
4013
4021
  };
4014
4022
  }
4015
4023
  /**
4016
- * The escalation debit (docs/07, 11.3d): minus one escalationUnit of
4024
+ * The escalation debit: minus one escalationUnit of
4017
4025
  * the affected lineage, including EACH lineage of a class-level
4018
4026
  * decision and timeout defaultDecisions. Conditioned on the
4019
4027
  * countsAgainstLimit flag embedded in the decision entry by the caller.
@@ -4031,7 +4039,7 @@ var TerminationAccount = class {
4031
4039
  };
4032
4040
  }
4033
4041
  /**
4034
- * The ladder-raise debit (docs/07, 11.3c): minus one rung of the
4042
+ * The ladder-raise debit: minus one rung of the
4035
4043
  * lineage; rungIndex is strictly monotone, there are no demotions and
4036
4044
  * no runtime startTier promotion in v1.
4037
4045
  */
@@ -4050,7 +4058,7 @@ var TerminationAccount = class {
4050
4058
  };
4051
4059
  }
4052
4060
  /**
4053
- * The docs/07 11.5 debit surface: attempts the named resource and, on
4061
+ * The unified debit surface: attempts the named resource and, on
4054
4062
  * underflow, writes `termination.denied` strictly BEFORE resolving with
4055
4063
  * the typed failure (the caller surfaces the error only after this
4056
4064
  * settles). Requires a deniedWriter; pure-fold contexts use the
@@ -4136,7 +4144,7 @@ var TerminationAccount = class {
4136
4144
  return lineage;
4137
4145
  }
4138
4146
  };
4139
- /** The typed error code surfaced after a denied debit (docs/07, 11.3). */
4147
+ /** The typed error code surfaced after a denied debit. */
4140
4148
  function exhaustionCodeOf(resource) {
4141
4149
  switch (resource) {
4142
4150
  case "revisionUnits": return "revision_budget_exhausted";
@@ -4150,7 +4158,7 @@ function asRecord$1(value) {
4150
4158
  return typeof value === "object" && value !== null ? value : void 0;
4151
4159
  }
4152
4160
  /**
4153
- * The replay fold (docs/07, 11.6): rebuilds the account from
4161
+ * The replay fold: rebuilds the account from
4154
4162
  * termination.init and the debiting decision entries, asserting every
4155
4163
  * embedded balance-after against the recomputation. A divergence raises
4156
4164
  * the typed journal-integrity error at exactly the diverging entry;
@@ -4283,7 +4291,8 @@ function applySpawnDebit(account, entry, admission, assertBalance) {
4283
4291
  * Reuse-by-reference: SpawnKey dedup, donor rules, node.link, and the
4284
4292
  * abandoned-spend ledger (M7-T07, DEF-5).
4285
4293
  *
4286
- * Owning spec: docs/03-journal-spec.md, section 9; docs/07, section 7.3.
4294
+ * Full contract: https://docs.rulvar.com/guide/journal and
4295
+ * https://docs.rulvar.com/guide/adaptive-orchestration.
4287
4296
  * Oscillation (cancel followed by a byte-identical re-add) no longer
4288
4297
  * means full repayment: completed work under an abandoned scope comes
4289
4298
  * back by reference, partially completed work grafts through a
@@ -4299,7 +4308,7 @@ function applySpawnDebit(account, entry, admission, assertBalance) {
4299
4308
  */
4300
4309
  const DEFAULT_MAX_OSCILLATIONS_PER_KEY = 2;
4301
4310
  /**
4302
- * node.link identity (docs/03, 9.5): sha256 of {kind, spawnKey,
4311
+ * node.link identity: sha256 of {kind, spawnKey,
4303
4312
  * donorScope, targetNodeId}; targetNodeId is deterministic on replay
4304
4313
  * because NodeIds are assigned inside plan.revision.
4305
4314
  */
@@ -4433,7 +4442,7 @@ var DedupIndex = class DedupIndex {
4433
4442
  allDonorsOf(spawnKey) {
4434
4443
  return this.donors.get(spawnKey) ?? [];
4435
4444
  }
4436
- /** Link count per key: the oscillation counter (docs/03, 9.7). */
4445
+ /** Link count per key: the oscillation counter. */
4437
4446
  oscillationCountOf(spawnKey) {
4438
4447
  return this.links.get(spawnKey) ?? 0;
4439
4448
  }
@@ -4446,7 +4455,7 @@ var DedupIndex = class DedupIndex {
4446
4455
  };
4447
4456
  }
4448
4457
  };
4449
- /** A plan-node scope (docs/03, 2.1): its entries belong to one node. */
4458
+ /** A plan-node scope: its entries belong to one node. */
4450
4459
  function isPlanNodeScope(scope) {
4451
4460
  return /(^|\/)plan\/[0-9A-Z]{26}$/.test(scope);
4452
4461
  }
@@ -4457,8 +4466,8 @@ function readIsolation(entry) {
4457
4466
  return "none";
4458
4467
  }
4459
4468
  /**
4460
- * The four-outcome verdict evaluation on a SpawnKey match (docs/03,
4461
- * 9.4), computed once live at the fold head and embedded into the
4469
+ * The four-outcome verdict evaluation on a SpawnKey match, computed
4470
+ * once live at the fold head and embedded into the
4462
4471
  * deciding entry; replay never re-evaluates.
4463
4472
  */
4464
4473
  function evaluateReuse(index, spawnKey, config) {
@@ -4587,7 +4596,7 @@ function decodeCheckpoint(blob) {
4587
4596
  * The journal append JSON-serializability check (M1-T04): every journaled
4588
4597
  * value MUST be JSON-serializable; a violation raises a typed
4589
4598
  * NonSerializableValueError at the calling site without journaling
4590
- * anything (docs/03, section "Serialization requirements").
4599
+ * anything.
4591
4600
  */
4592
4601
  function check(value, path) {
4593
4602
  if (value === null) return;
@@ -4644,7 +4653,7 @@ const KNOWN_KINDS = /* @__PURE__ */ new Set([
4644
4653
  "termination.init",
4645
4654
  "termination.denied"
4646
4655
  ]);
4647
- /** Legal stored statuses per kind (docs/03, section 5.3). */
4656
+ /** Legal stored statuses per kind. */
4648
4657
  const LEGAL_STATUSES = {
4649
4658
  agent: [
4650
4659
  "running",
@@ -4740,8 +4749,7 @@ function validateEntryShape(entry) {
4740
4749
  * resolution and abandon are appends of new entries plus a pure
4741
4750
  * deterministic fold; JournalStore stays exactly five methods.
4742
4751
  *
4743
- * Owning spec: docs/03-journal-spec.md, sections "Suspension and
4744
- * resolutions (DEF-4)" and "Abandon, derived skipped" (9.1).
4752
+ * Full contract: https://docs.rulvar.com/guide/durability
4745
4753
  */
4746
4754
  /**
4747
4755
  * The first-closing-wins fold over a loaded journal: one pass by seq,
@@ -4751,7 +4759,7 @@ function validateEntryShape(entry) {
4751
4759
  * schema-invalid offline resolution classifies invalid and does NOT close
4752
4760
  * the target. Abandon coverage is the target seq plus the transitive
4753
4761
  * child scope-prefix; the AbandonFold consumed by the replay predicate is
4754
- * a projection of THIS fold (docs/03, section 6.2: not a separate pass).
4762
+ * a projection of THIS fold (not a separate pass).
4755
4763
  */
4756
4764
  var ResolutionFold = class {
4757
4765
  targets = /* @__PURE__ */ new Map();
@@ -4891,8 +4899,8 @@ var ResolutionFold = class {
4891
4899
  }
4892
4900
  };
4893
4901
  /**
4894
- * Per-run, per-target FIFO serializer of resolution/abandon attempts
4895
- * (docs/03, section 8.5): classification against the in-memory fold ->
4902
+ * Per-run, per-target FIFO serializer of resolution/abandon attempts:
4903
+ * classification against the in-memory fold ->
4896
4904
  * durable append -> settle exactly once; losing attempts are ALSO
4897
4905
  * appended and become journaled noops by fold classification. Winner
4898
4906
  * effects run strictly after the critical section (the caller's job).
@@ -4985,7 +4993,7 @@ var ResolutionArbiter = class {
4985
4993
  };
4986
4994
  //#endregion
4987
4995
  //#region src/journal/matching.ts
4988
- /** Kinds excluded from forward-matching cursors (docs/03, section 8.2). */
4996
+ /** Kinds excluded from forward-matching cursors. */
4989
4997
  const REF_ENTRY_KINDS = /* @__PURE__ */ new Set(["resolution", "abandon"]);
4990
4998
  function currentOnlyKeyRing() {
4991
4999
  return { keyFor(identity, hashVersion) {
@@ -5009,7 +5017,7 @@ var JournalMatcher = class {
5009
5017
  keyRing;
5010
5018
  disposition;
5011
5019
  aliasDisposition;
5012
- /** Scope-prefix aliases (DEF-5, docs/03 9.5): donor prefix -> target prefix. */
5020
+ /** Scope-prefix aliases (DEF-5): donor prefix -> target prefix. */
5013
5021
  aliases = [];
5014
5022
  keyCache = /* @__PURE__ */ new Map();
5015
5023
  hitsInternal = 0;
@@ -5040,8 +5048,8 @@ var JournalMatcher = class {
5040
5048
  this.disposition = disposition;
5041
5049
  }
5042
5050
  /**
5043
- * The disposition applied to alias-sourced candidates (DEF-5, docs/03
5044
- * 9.5): the skipped overlay from abandon is bypassed ONLY through the
5051
+ * The disposition applied to alias-sourced candidates (DEF-5): the
5052
+ * skipped overlay from abandon is bypassed ONLY through the
5045
5053
  * alias, so entries regain their pre-abandon terminal status for
5046
5054
  * matching in the NEW scope; the standalone old scope stays skipped.
5047
5055
  */
@@ -5097,7 +5105,7 @@ var JournalMatcher = class {
5097
5105
  * Forward-matches one live call. A miss does not advance any cursor and
5098
5106
  * does not extinguish future hits: the scan always starts at the scope
5099
5107
  * head and skips consumed operations, so insertion stability holds by
5100
- * construction (docs/03, section 7.1).
5108
+ * construction.
5101
5109
  */
5102
5110
  match(scope, identity, mode) {
5103
5111
  if (mode === "never") {
@@ -5208,19 +5216,17 @@ var JournalMatcher = class {
5208
5216
  * The journal kernel write path (M1-T04): two-phase entries, ordinal
5209
5217
  * assignment, the per-run serialized append queue with the JSON
5210
5218
  * serializability check, and the budget-ledger fold. Scoped
5211
- * forward-matching and the replay predicate land with resume in M2
5212
- * (docs/03, sections "Scoped forward-matching" and "Replay predicate");
5219
+ * forward-matching and the replay predicate land with resume in M2;
5213
5220
  * in M1 every lookup is live.
5214
5221
  *
5215
- * Owning spec: docs/03-journal-spec.md, sections "JournalEntry form",
5216
- * "Two-phase entries, dispatch, and the budget ledger"; component sketch
5217
- * in docs/02-architecture.md, section "Journal Kernel".
5222
+ * Full contract: https://docs.rulvar.com/guide/journal; architecture
5223
+ * overview: https://docs.rulvar.com/guide/architecture.
5218
5224
  */
5219
- /** docs/06 Appendix A: large-value soft warn threshold (committed for M2). */
5225
+ /** Large-value soft warn threshold (committed for M2). */
5220
5226
  const LARGE_VALUE_WARN_BYTES = 262144;
5221
5227
  /**
5222
5228
  * Per-run journal kernel front end. Everything is per instance: no module
5223
- * state anywhere (docs/02, section "Dependency rules").
5229
+ * state anywhere.
5224
5230
  */
5225
5231
  var Replayer = class {
5226
5232
  runId;
@@ -5266,8 +5272,8 @@ var Replayer = class {
5266
5272
  }
5267
5273
  }
5268
5274
  /**
5269
- * Forward-matches one live call against the prior journal (docs/03,
5270
- * section 7). Fresh runs always miss; the M2-T06 predicate is injected
5275
+ * Forward-matches one live call against the prior journal. Fresh
5276
+ * runs always miss; the M2-T06 predicate is injected
5271
5277
  * through setDisposition once folds are built.
5272
5278
  */
5273
5279
  match(scope, identity, mode) {
@@ -5283,7 +5289,7 @@ var Replayer = class {
5283
5289
  this.matcher.setDisposition(disposition);
5284
5290
  }
5285
5291
  /**
5286
- * The disposition for alias-sourced candidates (DEF-5, docs/03 9.5):
5292
+ * The disposition for alias-sourced candidates (DEF-5):
5287
5293
  * bypasses the abandon overlay so donor entries regain their
5288
5294
  * pre-abandon terminal status when matched through the alias.
5289
5295
  */
@@ -5291,7 +5297,7 @@ var Replayer = class {
5291
5297
  this.matcher.setAliasDisposition(disposition);
5292
5298
  }
5293
5299
  /**
5294
- * Registers a node.link scope-prefix rewrite (DEF-5, docs/03 9.5):
5300
+ * Registers a node.link scope-prefix rewrite (DEF-5):
5295
5301
  * donorPrefix forward-matches into targetPrefix at every nested level.
5296
5302
  * Idempotent; the alias map is rebuilt by fold on resume.
5297
5303
  */
@@ -5299,9 +5305,9 @@ var Replayer = class {
5299
5305
  this.matcher.registerAlias(donorPrefix, targetPrefix);
5300
5306
  }
5301
5307
  /**
5302
- * invalidate/retry (docs/03, section 6.5): explicit unpinning of a
5308
+ * invalidate/retry: explicit unpinning of a
5303
5309
  * memoized failure; the invalidated entry reruns on this resume. The
5304
- * safety boundary is an open question (docs/14).
5310
+ * safety boundary is an open question.
5305
5311
  */
5306
5312
  invalidate(seq) {
5307
5313
  this.invalidated.add(seq);
@@ -5348,8 +5354,8 @@ var Replayer = class {
5348
5354
  });
5349
5355
  }
5350
5356
  /**
5351
- * Submits a resolution attempt through the per-target FIFO arbiter
5352
- * (docs/03, section 8.7). Losing attempts are journaled noops.
5357
+ * Submits a resolution attempt through the per-target FIFO arbiter.
5358
+ * Losing attempts are journaled noops.
5353
5359
  */
5354
5360
  resolveSuspended(target, attempt) {
5355
5361
  const targetEntry = this.entries.find((entry) => entry.seq === target);
@@ -5361,12 +5367,12 @@ var Replayer = class {
5361
5367
  if (targetEntry === void 0) throw new ConfigError(`abandonBranch: seq ${attempt.target} does not exist`);
5362
5368
  return this.arbiter.submitAbandon(targetEntry.scope, targetEntry.spanId, attempt);
5363
5369
  }
5364
- /** Pure fold view, snapshot-pinned (docs/03, section 8.7). */
5370
+ /** Pure fold view, snapshot-pinned. */
5365
5371
  suspensionState(target) {
5366
5372
  return this.foldInternal.suspensionState(target);
5367
5373
  }
5368
5374
  /**
5369
- * Value size policy (docs/03, section "Normative payload schemas"):
5375
+ * Value size policy:
5370
5376
  * there is NO automatic offload in v1; oversized values warn and
5371
5377
  * proceed. Large artifacts belong in TranscriptStore by reference.
5372
5378
  */
@@ -5393,7 +5399,7 @@ var Replayer = class {
5393
5399
  * Two-phase dispatch: the running entry (kinds agent, step, child).
5394
5400
  * `value` is legal on child dispatches only: the child payload
5395
5401
  * `{ workflow, childScope }` lets the abandon fold compute the child's
5396
- * transitive scope coverage (docs/03, section 8.4; M6-T06). Values
5402
+ * transitive scope coverage (M6-T06). Values
5397
5403
  * never enter identity.
5398
5404
  */
5399
5405
  appendRunning(input) {
@@ -5457,8 +5463,7 @@ var Replayer = class {
5457
5463
  });
5458
5464
  }
5459
5465
  /**
5460
- * The budget ledger fold (docs/03, section "Budget ledger fold on
5461
- * resume"): usage sums over terminal entries exactly once; agentsSpawned
5466
+ * The budget ledger fold: usage sums over terminal entries exactly once; agentsSpawned
5462
5467
  * counts agent dispatches.
5463
5468
  */
5464
5469
  ledger() {
@@ -5545,7 +5550,7 @@ var Replayer = class {
5545
5550
  * resolveExternal validates against the pinned schema BEFORE append on
5546
5551
  * the live path and settles the waiting promise in place without replay.
5547
5552
  *
5548
- * Owning specs: docs/06, section 2.7; docs/03, section 8.
5553
+ * Full contract: https://docs.rulvar.com/guide/durability
5549
5554
  */
5550
5555
  /**
5551
5556
  * Normalizes a resolution value into an ApprovalDecision. Anything that
@@ -5562,7 +5567,7 @@ function toApprovalDecision(value) {
5562
5567
  * Per-run registry of open external suspensions plus the run's activity
5563
5568
  * counter: when every in-flight branch is blocked on suspensions
5564
5569
  * (activity zero, waiters open), the run quiesces into outcome
5565
- * 'suspended' (docs/06, section 2.7).
5570
+ * 'suspended'.
5566
5571
  */
5567
5572
  var ExternalRegistry = class ExternalRegistry {
5568
5573
  replayer;
@@ -5677,7 +5682,7 @@ var ExternalRegistry = class ExternalRegistry {
5677
5682
  });
5678
5683
  }
5679
5684
  /**
5680
- * Tool-approval suspension (M3-T03; docs/08, section 3.6): journals (or
5685
+ * Tool-approval suspension (M3-T03): journals (or
5681
5686
  * re-matches) the suspended approval entry keyed by (toolName, input)
5682
5687
  * in the agent's child scope and parks until a resolution closes it.
5683
5688
  * The ask verdict is journaled together with the turn checkpoint; on
@@ -5735,7 +5740,7 @@ var ExternalRegistry = class ExternalRegistry {
5735
5740
  });
5736
5741
  }
5737
5742
  /**
5738
- * Flavor B escalation suspension (M3-T07; docs/07, section 6.2): the
5743
+ * Flavor B escalation suspension (M3-T07): the
5739
5744
  * escalate tool suspends the agent on the SAME machinery as approvals
5740
5745
  * (kind 'approval', toolName 'escalate') with a journaled deadlineAt so
5741
5746
  * deadlines survive resume; the resolution VALUE is the raw
@@ -5812,7 +5817,7 @@ var ExternalRegistry = class ExternalRegistry {
5812
5817
  /**
5813
5818
  * RunHandle.resolveExternal: the live path validates BEFORE append and
5814
5819
  * throws InvalidResolutionError without journaling; a winning attempt
5815
- * settles the waiting promise in place (docs/03, section 8.7).
5820
+ * settles the waiting promise in place.
5816
5821
  */
5817
5822
  async resolveExternal(key, value) {
5818
5823
  const waiter = [...this.waiters.values()].find((candidate) => candidate.key === key);
@@ -5917,7 +5922,7 @@ var InMemoryTranscriptStore = class {
5917
5922
  * beside the journal and are replaced atomically, so listRuns never
5918
5923
  * parses payloads.
5919
5924
  *
5920
- * Contract (docs/03, section "Storage SPI", DEF-4 tightening):
5925
+ * Contract (DEF-4 tightening):
5921
5926
  * - A1 atomicity: a torn trailing line (crash mid-append) is never
5922
5927
  * visible in load; it is dropped and overwritten by the next append.
5923
5928
  * - A2 total per-run order: load returns append order, stable across
@@ -5928,7 +5933,7 @@ var InMemoryTranscriptStore = class {
5928
5933
  *
5929
5934
  * Leasing is NOT implemented here: LeasableStore ships with
5930
5935
  * @rulvar/store-sqlite (M5); JsonlFileStore is single-writer by
5931
- * convention (docs/03, section "Shipped stores").
5936
+ * convention.
5932
5937
  */
5933
5938
  const JOURNAL_SUFFIX = ".jsonl";
5934
5939
  const META_SUFFIX = ".meta.json";
@@ -6012,7 +6017,7 @@ const TRANSCRIPT_SUFFIX = ".bin";
6012
6017
  /**
6013
6018
  * File-backed TranscriptStore (M6-T02): blobs (transcripts, checkpoints,
6014
6019
  * persisted CompiledWorkflow sources) as one file per ref under `dir`,
6015
- * so compiled runs resume across processes (docs/06, 10.2). Refs follow
6020
+ * so compiled runs resume across processes. Refs follow
6016
6021
  * the `<runId>/<name>` convention; each path segment is checked
6017
6022
  * filesystem-safe and nested segments become directories.
6018
6023
  */
@@ -6073,7 +6078,7 @@ var FileTranscriptStore = class {
6073
6078
  //#endregion
6074
6079
  //#region src/engine/cost-report.ts
6075
6080
  /**
6076
- * CostReport builders (M5-T03; docs/09, section "CostReport"). Two
6081
+ * CostReport builders (M5-T03). Two
6077
6082
  * sources, one shape:
6078
6083
  *
6079
6084
  * - `buildCostReport` folds the LIVE per-run attribution buckets (ctx
@@ -6087,8 +6092,7 @@ var FileTranscriptStore = class {
6087
6092
  * facts that entries do not carry, so those buckets are empty here;
6088
6093
  * byRole and the orchestrator block complete in M7 (DEF-7).
6089
6094
  *
6090
- * Unpriced models surface in `unpriced`, never as a silent zero
6091
- * (docs/04, section "Pricing").
6095
+ * Unpriced models surface in `unpriced`, never as a silent zero.
6092
6096
  */
6093
6097
  const ROLES = [
6094
6098
  "orchestrate",
@@ -6172,8 +6176,8 @@ function costReportFromJournal(entries, priceUsd) {
6172
6176
  //#endregion
6173
6177
  //#region src/engine/run-profiles.ts
6174
6178
  /**
6175
- * The shipped presets (docs/06, section 11: fast / standard / deep /
6176
- * ultra "and similar"). Data only; a review-time assertion checks the
6179
+ * The shipped presets (fast / standard / deep / ultra "and similar").
6180
+ * Data only; a review-time assertion checks the
6177
6181
  * engine has zero behavioral branches keyed on these names.
6178
6182
  */
6179
6183
  const RUN_PROFILES = {
@@ -6240,7 +6244,7 @@ const TIER_ORDER = {
6240
6244
  /**
6241
6245
  * Strict-schema compatibility as both first-class providers define it:
6242
6246
  * every object node declares `additionalProperties: false` and lists every
6243
- * property in `required` (docs/04, section 5.2). Boolean schemas and
6247
+ * property in `required`. Boolean schemas and
6244
6248
  * non-object shapes are trivially compatible.
6245
6249
  */
6246
6250
  function isStrictCompatibleSchema(schema) {
@@ -6280,10 +6284,10 @@ function isStrictCompatibleSchema(schema) {
6280
6284
  return true;
6281
6285
  }
6282
6286
  /**
6283
- * Tier selection (docs/04, section 8.4): the model's declared ceiling
6287
+ * Tier selection: the model's declared ceiling
6284
6288
  * bounds the tier; the native tier additionally requires a
6285
- * strict-compatible canonical schema (docs/04, section 5.2: relying on
6286
- * silent server-side fallback is forbidden), degrading to forced-tool.
6289
+ * strict-compatible canonical schema (relying on silent server-side
6290
+ * fallback is forbidden), degrading to forced-tool.
6287
6291
  * Prefill is not a tier.
6288
6292
  */
6289
6293
  function selectStructuredOutputTier(caps, canonicalSchema) {
@@ -6301,10 +6305,10 @@ function tierWithinCaps(tier, caps) {
6301
6305
  * Scheduler and concurrency (M1-T08): the per-run semaphore with a FIFO
6302
6306
  * queue (default 12 concurrent model calls). The engine lifetime spawn cap
6303
6307
  * is enforced by the budget layer at admission; parallel/pipeline
6304
- * composition semantics live with ctx (docs/06, section "Scheduler").
6308
+ * composition semantics live with ctx.
6305
6309
  * Per-provider concurrency keys land with M4.
6306
6310
  */
6307
- /** FIFO semaphore; default per-run width is 12 (docs/06, Appendix A). */
6311
+ /** FIFO semaphore; default per-run width is 12. */
6308
6312
  const DEFAULT_PER_RUN_CONCURRENCY = 12;
6309
6313
  var Semaphore = class {
6310
6314
  limit;
@@ -6350,7 +6354,7 @@ var Semaphore = class {
6350
6354
  //#region src/model/concurrency.ts
6351
6355
  /**
6352
6356
  * Per-provider concurrency keys (M4-T07): a keyed limiter beside the
6353
- * router, ENGINE-scoped (docs/06, section 4: keys constrain calls
6357
+ * router, ENGINE-scoped (keys constrain calls
6354
6358
  * across a single engine per adapter). The Appendix A default is
6355
6359
  * unlimited: an embeddable library must not surprise-throttle hosts, so
6356
6360
  * the per-run semaphore stays the only default bound and provider 429s
@@ -6359,7 +6363,7 @@ var Semaphore = class {
6359
6363
  *
6360
6364
  * There is deliberately NO distributed cross-process limiter: two
6361
6365
  * processes sharing one API key coordinate nothing here (a
6362
- * process-global limiter is an open question, docs/14).
6366
+ * process-global limiter is an open question).
6363
6367
  */
6364
6368
  var KeyedLimiter = class {
6365
6369
  semaphores = /* @__PURE__ */ new Map();
@@ -6382,7 +6386,7 @@ var KeyedLimiter = class {
6382
6386
  };
6383
6387
  //#endregion
6384
6388
  //#region src/model/failover.ts
6385
- /** Normalizes the author-facing ModelChoice.fallbacks list (docs/04, 8.1). */
6389
+ /** Normalizes the author-facing ModelChoice.fallbacks list. */
6386
6390
  function normalizeFallbacks(refs) {
6387
6391
  return (refs ?? []).map((model) => ({ model }));
6388
6392
  }
@@ -6407,8 +6411,8 @@ function nextFailover(targets, trigger, from) {
6407
6411
  }
6408
6412
  }
6409
6413
  /**
6410
- * Classifies a terminal agent outcome for the degenerate fallback
6411
- * (docs/04, 11.3 as amended): schema-mismatch errors are
6414
+ * Classifies a terminal agent outcome for the degenerate fallback:
6415
+ * schema-mismatch errors are
6412
6416
  * 'schema-exhausted'; any other error is 'error'; limit terminals (the
6413
6417
  * no-progress abort included) are 'limit'; cancelled, escalated, and
6414
6418
  * skipped never trigger.
@@ -6428,11 +6432,11 @@ function resolvePricing(ref, table, capsPricing) {
6428
6432
  return table?.models[ref] ?? capsPricing;
6429
6433
  }
6430
6434
  /**
6431
- * Dollars from normalized usage against one pricing row (docs/04,
6432
- * section 1.6: the adapter normalized the usage; inputTokens is the
6435
+ * Dollars from normalized usage against one pricing row (the adapter
6436
+ * normalized the usage; inputTokens is the
6433
6437
  * full prompt). Cache writes price at the 5m premium rate; the 1h rate
6434
6438
  * applies where a provider distinguishes it in usage, which the
6435
- * canonical Usage does not yet carry (docs/04, section 10).
6439
+ * canonical Usage does not yet carry.
6436
6440
  */
6437
6441
  function priceUsdOf(pricing, usage) {
6438
6442
  return usage.inputTokens / 1e6 * pricing.inputUsdPerMTok + usage.outputTokens / 1e6 * pricing.outputUsdPerMTok + usage.cacheReadTokens / 1e6 * (pricing.cacheReadUsdPerMTok ?? 0) + usage.cacheWriteTokens / 1e6 * (pricing.cacheWriteUsdPerMTok ?? 0);
@@ -6494,7 +6498,7 @@ function projectHistory(messages, targetProvider) {
6494
6498
  }
6495
6499
  /**
6496
6500
  * Lifts the adapter-shipped retention payload of one finished turn into
6497
- * provider-raw parts (docs/04, section 2.3 retention transport). Reads
6501
+ * provider-raw parts (the retention transport). Reads
6498
6502
  * providerMetadata[<adapter id>].retainedParts and tags each block with
6499
6503
  * the adapter's provider family. Returns [] when the adapter shipped
6500
6504
  * nothing.
@@ -6532,9 +6536,8 @@ const DEFAULT_RETRY_POLICY = {
6532
6536
  /**
6533
6537
  * Classifies a WireError for the retry engine. Task-class failures are
6534
6538
  * never retryable by construction: adapters mark them retryable: false
6535
- * and this returns undefined. The kind travels in WireError.data.kind
6536
- * (docs/04, section 4.9); anything retryable without a specific kind is
6537
- * transport.
6539
+ * and this returns undefined. The kind travels in WireError.data.kind;
6540
+ * anything retryable without a specific kind is transport.
6538
6541
  */
6539
6542
  function retryClassOf(error) {
6540
6543
  if (!error.retryable) return;
@@ -6575,7 +6578,7 @@ function canRideLoopTurn(tier, toolsAvailable) {
6575
6578
  * to a different model OR the loop model's caps cannot serve the required
6576
6579
  * tier OR finalize is routed, in which case the schema never rides a loop
6577
6580
  * or synthesis turn). Otherwise the schema rides the last loop turn with
6578
- * no extra call (docs/04, sections 8.3 and 8.4 as amended in M4-T01).
6581
+ * no extra call (as amended in M4-T01).
6579
6582
  */
6580
6583
  function needsSeparateExtract(input) {
6581
6584
  if (!input.schemaSet) return false;
@@ -6586,7 +6589,7 @@ function needsSeparateExtract(input) {
6586
6589
  * map. This is the finalize TRIGGER: firing is decided by the presence of
6587
6590
  * a routing entry at any layer; the model it fires ON still resolves
6588
6591
  * through the full chain (a higher layer's all-roles `model` may override
6589
- * the routed choice per docs/04, section 8.2).
6592
+ * the routed choice).
6590
6593
  */
6591
6594
  function roleConfiguredInRouting(role, layers) {
6592
6595
  return layers.some((layer) => layer?.routing?.[role] !== void 0);
@@ -6594,8 +6597,8 @@ function roleConfiguredInRouting(role, layers) {
6594
6597
  /**
6595
6598
  * The finalize firing rule: only if configured in routing, and only after
6596
6599
  * tools stop, which presupposes a non-empty toolset. A no-tools agent's
6597
- * single loop turn is already its synthesis (docs/04, section 8.4 as
6598
- * amended in M4-T01). The caller additionally gates on the loop having
6600
+ * single loop turn is already its synthesis (as amended in M4-T01). The
6601
+ * caller additionally gates on the loop having
6599
6602
  * ended without an abort: a limit/error/cancelled/escalated loop never
6600
6603
  * reaches synthesis.
6601
6604
  */
@@ -6604,7 +6607,7 @@ function finalizeFires(options) {
6604
6607
  }
6605
6608
  /**
6606
6609
  * The summarize trigger: the compaction threshold on the context window
6607
- * (docs/06, Appendix A: default 0.8). Pure predicate; the compaction
6610
+ * (default 0.8). Pure predicate; the compaction
6608
6611
  * pipeline that acts on it is M4-T03.
6609
6612
  */
6610
6613
  function atCompactionThreshold(usedTokens, contextWindow, threshold) {
@@ -6613,12 +6616,12 @@ function atCompactionThreshold(usedTokens, contextWindow, threshold) {
6613
6616
  }
6614
6617
  //#endregion
6615
6618
  //#region src/runtime/compaction.ts
6616
- /** Appendix A: compaction threshold default, 0.8 of contextWindow. */
6619
+ /** Compaction threshold default, 0.8 of contextWindow. */
6617
6620
  const DEFAULT_COMPACTION_THRESHOLD = .8;
6618
6621
  /** Deterministic marker opening every compaction summary message. */
6619
6622
  const COMPACTION_SUMMARY_PREFIX = "Summary of the conversation so far:";
6620
6623
  /**
6621
- * The threshold check (docs/06, M4-T03 committed semantics): the context
6624
+ * The threshold check (M4-T03 committed semantics): the context
6622
6625
  * estimate is the last loop turn's inputTokens + outputTokens; the Usage
6623
6626
  * invariant makes inputTokens the full prompt, and the turn's output
6624
6627
  * joins the next prompt.
@@ -6664,14 +6667,11 @@ function compactMessages(messages, summaryText) {
6664
6667
  * parsing, the per-invocation resolution chain, canonicalization into
6665
6668
  * CanonicalModelSpec, and caps scrubbing with visible scrub notes.
6666
6669
  *
6667
- * Owning spec: docs/04-model-layer-spec.md, sections "Router and
6668
- * resolution chain", "Canonical effort", and "Caps scrubbing and
6669
- * structured-output tier selection".
6670
+ * Public contract: https://docs.rulvar.com/guide/model-routing.
6670
6671
  */
6671
6672
  /**
6672
6673
  * Per-engine adapter registry: strictly per engine, no global mutable
6673
- * registry exists. A duplicate adapterId is a typed ConfigError
6674
- * (docs/04, section "Registry and ModelRef").
6674
+ * registry exists. A duplicate adapterId is a typed ConfigError.
6675
6675
  */
6676
6676
  function buildAdapterRegistry(adapters) {
6677
6677
  const registry = /* @__PURE__ */ new Map();
@@ -6695,12 +6695,10 @@ function parseModelRef(ref) {
6695
6695
  };
6696
6696
  }
6697
6697
  /**
6698
- * Role effort defaults (docs/04, section "Invocation roles and firing
6699
- * protocol"): orchestrate and plan default to high; summarize and extract
6698
+ * Role effort defaults: orchestrate and plan default to high; summarize and extract
6700
6699
  * default to low. loop and finalize have NO role default: when the chain
6701
6700
  * resolves nothing, the wire omits effort and identity records the spec
6702
- * with the effort member absent (docs/04, section "Router and resolution
6703
- * chain", as amended).
6701
+ * with the effort member absent.
6704
6702
  */
6705
6703
  const ROLE_EFFORT_DEFAULTS = {
6706
6704
  orchestrate: "high",
@@ -6755,7 +6753,7 @@ const SAMPLING_KEYS = [
6755
6753
  * Resolution runs on every model invocation, not once per agent: a layered
6756
6754
  * merge of { model, effort, providerOptions, fallbacks } in the order call
6757
6755
  * override > agent profile > workflow defaults > engine defaults, with the
6758
- * invocation role attached as a tag (docs/04, section "Resolution chain").
6756
+ * invocation role attached as a tag.
6759
6757
  * After resolution the router reads ModelCaps and scrubs illegal
6760
6758
  * parameters visibly: unsupported effort is removed from the wire but
6761
6759
  * kept in identity; sampling params rejected by the model are removed
@@ -6839,7 +6837,7 @@ function resolveModelInvocation(options) {
6839
6837
  if (merged.fallbacks !== void 0) resolved.fallbacks = merged.fallbacks;
6840
6838
  return resolved;
6841
6839
  }
6842
- /** The closed trigger vocabulary guard (docs/04, section 12). */
6840
+ /** The closed trigger vocabulary guard. */
6843
6841
  const TRIGGER_CLASSES = [
6844
6842
  "error",
6845
6843
  "limit",
@@ -6863,7 +6861,7 @@ function validateGate(gate, rungCount, index) {
6863
6861
  if (!(gate.fraction > 0 && gate.fraction <= 1)) throw new ConfigError(`ladder acceptance gate ${String(index)}: a spot-check fraction lies in (0, 1], got ${String(gate.fraction)}`);
6864
6862
  }
6865
6863
  /**
6866
- * Canonicalizes a declared LadderSpec (docs/04, section 12): validates the
6864
+ * Canonicalizes a declared LadderSpec: validates the
6867
6865
  * shape once (FR-119 judge declaration included) and resolves every rung's
6868
6866
  * effort to an explicit value. `chainEffort` is the effort the resolution
6869
6867
  * chain would contribute at the declaring layer; a rung that resolves no
@@ -6901,7 +6899,7 @@ function canonicalizeLadder(spec, options) {
6901
6899
  /**
6902
6900
  * The concrete ModelChoice of one rung attempt: each attempt is an
6903
6901
  * ordinary agent scope whose CanonicalModelSpec is that rung's
6904
- * `{ kind: 'model' }` form (docs/04, section 8.2).
6902
+ * `{ kind: 'model' }` form.
6905
6903
  */
6906
6904
  function ladderRungChoice(ladder, index) {
6907
6905
  const rung = ladder.rungs[index];
@@ -6917,7 +6915,7 @@ const DEFAULT_MAX_TURNS = 32;
6917
6915
  const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 12e4;
6918
6916
  /**
6919
6917
  * Limits merge per spawn: AgentOpts.limits over profile limits over engine
6920
- * defaults.limits (docs/06, section "UsageLimits").
6918
+ * defaults.limits.
6921
6919
  */
6922
6920
  function mergeUsageLimits(call, profile, engine) {
6923
6921
  const pick = (key) => call?.[key] ?? profile?.[key] ?? engine?.[key];
@@ -6945,13 +6943,13 @@ var ModelRetry = class extends Error {
6945
6943
  if (opts?.data !== void 0) this.data = opts.data;
6946
6944
  }
6947
6945
  };
6948
- /** Bounded semantic retries per tool call chain (docs/06, Appendix A). */
6946
+ /** Bounded semantic retries per tool call chain. */
6949
6947
  const DEFAULT_MODEL_RETRY_ATTEMPTS = 2;
6950
6948
  //#endregion
6951
6949
  //#region src/runtime/escalation.ts
6952
6950
  const ESCALATE_TOOL_NAME = "escalate";
6953
6951
  /**
6954
- * The exact tool schema of docs/07, section 4.9. costToDate and salvage
6952
+ * The escalate tool's exact request schema. costToDate and salvage
6955
6953
  * MUST NOT appear here: additionalProperties false rejects model-authored
6956
6954
  * values for them at argument validation.
6957
6955
  */
@@ -6995,7 +6993,7 @@ const ESCALATION_REQUEST_SCHEMA = {
6995
6993
  }
6996
6994
  }
6997
6995
  };
6998
- /** The full-report schema applied BEFORE append (docs/03, section 5.4). */
6996
+ /** The full-report schema applied BEFORE append. */
6999
6997
  const ESCALATION_REPORT_SCHEMA = {
7000
6998
  type: "object",
7001
6999
  additionalProperties: false,
@@ -7066,7 +7064,7 @@ const ESCALATION_REPORT_SCHEMA = {
7066
7064
  }
7067
7065
  };
7068
7066
  /**
7069
- * The engine opt-in tool (docs/08, section 6.6): registered through the
7067
+ * The engine opt-in tool: registered through the
7070
7068
  * same path as any tool under escalation opt-in of EITHER flavor (the
7071
7069
  * worker's only authoring channel for a report), never available without
7072
7070
  * opt-in, and dispatched through the same permission chain. The loop
@@ -7088,7 +7086,7 @@ async function validateEscalationReport(report) {
7088
7086
  return validation.valid ? [] : validation.issues;
7089
7087
  }
7090
7088
  /**
7091
- * countsAgainstLimit derivation (docs/07, section 6.3, XF-06): true iff
7089
+ * countsAgainstLimit derivation (XF-06): true iff
7092
7090
  * scope_bigger; scope_different and blocked_with_evidence are exempt and
7093
7091
  * never debit the escalation counter.
7094
7092
  */
@@ -7102,11 +7100,11 @@ function countsAgainstLimit(kind) {
7102
7100
  * journaled as a first-class terminal abort distinct from user
7103
7101
  * cancellation (a cancelled entry always reruns; a no-progress abort
7104
7102
  * must replay, or every resume would re-pay the stuck turns). The
7105
- * interim heuristic is committed in docs/06 Appendix A: N consecutive
7103
+ * interim heuristic is committed: N consecutive
7106
7104
  * turns without tool calls or artifact deltas, N = 3; the broader
7107
- * heuristic stays OQ-15 (docs/14), revisited on dogfood traces.
7105
+ * heuristic stays OQ-15, revisited on dogfood traces.
7108
7106
  *
7109
- * Encoding (docs/03, sections 6.3 and 6.6): the abort is the agent's
7107
+ * Encoding: the abort is the agent's
7110
7108
  * terminal entry with status 'limit', an error payload carrying
7111
7109
  * abortClass 'no-progress', and memoizeOutcome stamped by the ENGINE on
7112
7110
  * the terminal entry, so the frozen memoize-limit rule replays it on
@@ -7114,7 +7112,7 @@ function countsAgainstLimit(kind) {
7114
7112
  * per-turn artifact channel, so the tool-call test subsumes artifact
7115
7113
  * deltas; per-turn artifact producers arrive with M4 compaction.
7116
7114
  */
7117
- /** docs/06 Appendix A: the committed no-progress detector N. */
7115
+ /** The committed no-progress detector N. */
7118
7116
  const DEFAULT_NO_PROGRESS_TURNS = 3;
7119
7117
  /**
7120
7118
  * Counts consecutive progress-free turns. A turn with at least one tool
@@ -7154,14 +7152,14 @@ var NoProgressDetector = class {
7154
7152
  * allow: allow is only ever falling through to canUseTool or the
7155
7153
  * terminal default.
7156
7154
  *
7157
- * Owning spec: docs/08-tools-permissions-spec.md, section "Permission
7158
- * chain". Risk presets, the argv shell matcher, domain rules, and the
7155
+ * Full contract: https://docs.rulvar.com/guide/tools.
7156
+ * Risk presets, the argv shell matcher, domain rules, and the
7159
7157
  * audit/dry-run surface land in M5.
7160
7158
  */
7161
7159
  /**
7162
7160
  * Merges the engine-wide config and the profile config into one chain.
7163
7161
  * Layers concatenate engine-first; since rules only deny or ask, ordering
7164
- * within a layer cannot change the verdict (docs/08, section 4.2). The
7162
+ * within a layer cannot change the verdict. The
7165
7163
  * profile's canUseTool wins over the engine's (a single slot by
7166
7164
  * construction). A declared preset compiles INTO the same layers, after
7167
7165
  * the host-authored rules, never as a fifth layer (M5-T05).
@@ -7189,7 +7187,7 @@ function compilePermissionChain(engine, profile) {
7189
7187
  ...canUseTool === void 0 ? {} : { canUseTool }
7190
7188
  };
7191
7189
  }
7192
- /** The command text an argv rule matches against (docs/08, section 5). */
7190
+ /** The command text an argv rule matches against. */
7193
7191
  function commandOf(input) {
7194
7192
  if (typeof input === "string") return input;
7195
7193
  if (typeof input === "object" && input !== null) {
@@ -7214,7 +7212,7 @@ function ruleMatches(rule, toolName, risk, input) {
7214
7212
  return true;
7215
7213
  }
7216
7214
  /**
7217
- * Advisory domain-rule matches for the audit payload (docs/08, 4.4):
7215
+ * Advisory domain-rule matches for the audit payload:
7218
7216
  * reported, never enforced outside first-party fetch.
7219
7217
  */
7220
7218
  function advisoryMatches(chain, toolName) {
@@ -7222,7 +7220,7 @@ function advisoryMatches(chain, toolName) {
7222
7220
  }
7223
7221
  /**
7224
7222
  * Unmatchable segments (command/process substitution, here-docs) yield
7225
- * ask, ALWAYS, for any tool that has argv rules (docs/08, 5.2 step 3).
7223
+ * ask, ALWAYS, for any tool that has argv rules.
7226
7224
  */
7227
7225
  function argvUnmatchableAsk(chain, toolName, input) {
7228
7226
  if (![...chain.deny, ...chain.ask].some((rule) => "argv" in rule && (Array.isArray(rule.tool) ? rule.tool : [rule.tool]).includes(toolName))) return false;
@@ -7230,7 +7228,7 @@ function argvUnmatchableAsk(chain, toolName, input) {
7230
7228
  if (command === void 0) return true;
7231
7229
  return lexShellCommand(command).some((segment) => segment.unmatchable);
7232
7230
  }
7233
- /** A stub ToolContext for offline (dry-run) evaluations (docs/08, 4.5). */
7231
+ /** A stub ToolContext for offline (dry-run) evaluations. */
7234
7232
  function offlineContext(toolName) {
7235
7233
  return {
7236
7234
  runId: "dry-run",
@@ -7244,14 +7242,14 @@ function offlineContext(toolName) {
7244
7242
  }
7245
7243
  /**
7246
7244
  * Evaluates the chain for one dispatch, or OFFLINE against a
7247
- * hypothetical call by tool name (the dry-run API of docs/08, section
7248
- * 4.5: nothing executes; shells and tests read the verdict, the
7245
+ * hypothetical call by tool name (the dry-run API: nothing executes;
7246
+ * shells and tests read the verdict, the
7249
7247
  * deciding layer, and the matched rule). Hooks run in deterministic
7250
7248
  * registration order; { modifiedInput } substitutes the input and
7251
7249
  * continues; the first decisive verdict wins. The returned input is what
7252
- * execute receives and what the approval identity hashes (docs/03,
7253
- * section 1.2: post hook modification). Advisory domain-rule matches
7254
- * ride every verdict for the audit payload (docs/08, 4.4).
7250
+ * execute receives and what the approval identity hashes (post hook
7251
+ * modification). Advisory domain-rule matches
7252
+ * ride every verdict for the audit payload.
7255
7253
  */
7256
7254
  async function evaluatePermission(chain, tool, input, ctx) {
7257
7255
  const def = typeof tool === "string" ? {
@@ -7439,8 +7437,8 @@ function formatRePrompt(issues, attempt, maxAttempts) {
7439
7437
  * with M3/M4; the escalated status arrives in M3 as the flagged breaking
7440
7438
  * change.
7441
7439
  *
7442
- * Owning specs: docs/06-execution-spec.md, section "Agent runtime
7443
- * binding"; docs/04-model-layer-spec.md (roles, tiers, refusal).
7440
+ * Docs: https://docs.rulvar.com/guide/agents (agent runtime binding);
7441
+ * https://docs.rulvar.com/guide/model-routing (roles, tiers, refusal).
7444
7442
  */
7445
7443
  function isEscalated(r) {
7446
7444
  return r.status === "escalated";
@@ -7466,8 +7464,7 @@ function addUsage(total, turn) {
7466
7464
  }
7467
7465
  /**
7468
7466
  * The Usage invariant is verified at the adapter boundary: inputTokens is
7469
- * the FULL prompt including cache reads and writes (docs/04, section
7470
- * "Usage invariant").
7467
+ * the FULL prompt including cache reads and writes.
7471
7468
  */
7472
7469
  function assertUsageInvariant(usage, adapterId) {
7473
7470
  if (usage.inputTokens < usage.cacheReadTokens + usage.cacheWriteTokens) throw new Error(`adapter '${adapterId}' violated the Usage invariant: inputTokens (${usage.inputTokens}) < cacheReadTokens + cacheWriteTokens (${usage.cacheReadTokens} + ${usage.cacheWriteTokens})`);
@@ -7612,7 +7609,7 @@ function buildRequest(resolved, messages, limits, tools) {
7612
7609
  * parts go at the HEAD: on both first-class providers the retained
7613
7610
  * blocks (thinking blocks, reasoning items) precede the turn's text and
7614
7611
  * tool calls, and head placement reproduces that order on re-projection
7615
- * (docs/04, section 2.3, M4-T02).
7612
+ * (M4-T02).
7616
7613
  */
7617
7614
  function assistantMsg(turn, retained = []) {
7618
7615
  const parts = [...retained];
@@ -7636,8 +7633,7 @@ function assistantMsg(turn, retained = []) {
7636
7633
  * surfaced to the model as error tool results and never thrown past
7637
7634
  * policy: unknown names, argument-validation issues, ModelRetry (bounded
7638
7635
  * per tool call chain), NonSerializableValueError, and arbitrary execute
7639
- * throws all land as { isError: true } results (docs/08, sections 1.1 and
7640
- * 2.4; docs/06, section "ModelRetry").
7636
+ * throws all land as { isError: true } results.
7641
7637
  */
7642
7638
  async function executeToolCall(options) {
7643
7639
  const { call, runtime } = options;
@@ -8581,7 +8577,7 @@ async function runAgent(options) {
8581
8577
  * ceiling severing live streams, with partial usage written usageApprox.
8582
8578
  * B0 is immutable after start: no API tops it up.
8583
8579
  *
8584
- * The account tree (docs/06, section 5.4): the run root plus one
8580
+ * The account tree: the run root plus one
8585
8581
  * sub-account per admitted child workflow (and, from M7, the orchestrator
8586
8582
  * account and plan/NodeId accounts). A child's spend propagates to ALL
8587
8583
  * ancestors up to the run root; the root ceiling remains the true
@@ -8590,11 +8586,11 @@ async function runAgent(options) {
8590
8586
  * reserves are recovered from spawn-admission decision entries); the
8591
8587
  * per-account historical fold completes with DEF-7 in M7.
8592
8588
  *
8593
- * Owning spec: docs/06-execution-spec.md, section "Three-layer budget".
8589
+ * Full contract: https://docs.rulvar.com/guide/budgets
8594
8590
  */
8595
- /** Last resort of the admission reserve formula (docs/06, Appendix A). */
8591
+ /** Last resort of the admission reserve formula. */
8596
8592
  const DEFAULT_FLAT_RESERVE_USD = .5;
8597
- /** The run-root account scope (docs/06, section 5.4 scope vocabulary). */
8593
+ /** The run-root account scope. */
8598
8594
  const ROOT_ACCOUNT = "run";
8599
8595
  const ZERO_USAGE = {
8600
8596
  inputTokens: 0,
@@ -8603,8 +8599,7 @@ const ZERO_USAGE = {
8603
8599
  cacheWriteTokens: 0
8604
8600
  };
8605
8601
  /**
8606
- * The admission reserve for a spawn (docs/06, section "Layer 1: admission
8607
- * before spawn"): opts.estCost, else profile.estCost, else
8602
+ * The admission reserve for a spawn: opts.estCost, else profile.estCost, else
8608
8603
  * price(countTokens(input) + caps.maxOutputTokens), else the engine flat
8609
8604
  * default.
8610
8605
  */
@@ -8670,7 +8665,7 @@ var RunBudget = class {
8670
8665
  return chain;
8671
8666
  }
8672
8667
  /**
8673
- * Opens a child sub-account under `parentScope` (docs/06, section 5.4).
8668
+ * Opens a child sub-account under `parentScope`.
8674
8669
  * Re-opening an existing scope is the resume roll-forward path: the
8675
8670
  * recorded ceiling wins once and the accumulated state is kept.
8676
8671
  */
@@ -8727,7 +8722,7 @@ var RunBudget = class {
8727
8722
  /**
8728
8723
  * Marks the run exhausted without a ceiling event: the orchestrator
8729
8724
  * finalize fallback maps to outcome 'exhausted' with the synthesized
8730
- * partial value (DEF-7, docs/07 12.4; exhaustion is never null).
8725
+ * partial value (DEF-7; exhaustion is never null).
8731
8726
  */
8732
8727
  markExhausted() {
8733
8728
  this.exhaustedInternal = true;
@@ -8744,7 +8739,7 @@ var RunBudget = class {
8744
8739
  * Layer 1: admission before spawn. Blocks when spent + committedReserve
8745
8740
  * has reached the ceiling on ANY account in the ancestor chain of
8746
8741
  * `accountScope`, otherwise commits the reserve along the whole chain.
8747
- * Also enforces the engine lifetime spawn cap (docs/06, "Scheduler").
8742
+ * Also enforces the engine lifetime spawn cap.
8748
8743
  */
8749
8744
  admitSpawn(reserveUsd, accountScope = "run") {
8750
8745
  if (this.agentsSpawnedInternal >= this.lifetimeSpawnCap) {
@@ -8768,7 +8763,7 @@ var RunBudget = class {
8768
8763
  /**
8769
8764
  * Resume roll-forward: commits a reserve recovered from a journaled
8770
8765
  * spawn-admission decision entry without re-evaluating admission
8771
- * (docs/06, 5.1: reserves are recovered, never re-estimated).
8766
+ * (reserves are recovered, never re-estimated).
8772
8767
  */
8773
8768
  admitRecovered(reserveUsd, accountScope = "run") {
8774
8769
  this.agentsSpawnedInternal += 1;
@@ -8776,7 +8771,7 @@ var RunBudget = class {
8776
8771
  this.emitUpdate();
8777
8772
  }
8778
8773
  /**
8779
- * Registers the orchestrator finalize reserve (DEF-7, docs/07 12.2):
8774
+ * Registers the orchestrator finalize reserve (DEF-7):
8780
8775
  * absolute dollars set on the named account AND the run root, so
8781
8776
  * admission never lets any spawn eat the finalization money even
8782
8777
  * against whole-run exhaustion. Kept SEPARATE from committedReserveUsd
@@ -8852,7 +8847,7 @@ var RunBudget = class {
8852
8847
  agentsSpawned: this.agentsSpawnedInternal
8853
8848
  };
8854
8849
  }
8855
- /** Null when the run has no USD ceiling (docs/06, section "Canonical Ctx interface"). */
8850
+ /** Null when the run has no USD ceiling. */
8856
8851
  remaining() {
8857
8852
  const root = this.root;
8858
8853
  if (root.ceilingUsd === void 0) return null;
@@ -8877,8 +8872,8 @@ var RunBudget = class {
8877
8872
  /**
8878
8873
  * AdmissionController v1 (M6-T06; DEF-2, DEF-3, DEF-5 substrate).
8879
8874
  *
8880
- * Owning spec: docs/07-adaptive-orchestration-spec.md, section
8881
- * "AdmissionController". The single admission point for ALL spawns of any
8875
+ * Public contract: https://docs.rulvar.com/guide/adaptive-orchestration.
8876
+ * The single admission point for ALL spawns of any
8882
8877
  * origin: ctx.workflow, the orchestrator spawn tools (M6-T07), escalation
8883
8878
  * decomposition and rung respawns (M7). `admit(spec)` is called BEFORE
8884
8879
  * the carrying spawn-admission decision entry is journaled; the verdict
@@ -8941,8 +8936,8 @@ var AdmissionController = class {
8941
8936
  return this.lineageLimits;
8942
8937
  }
8943
8938
  /**
8944
- * Binds the run's TerminationAccount (DEF-2; PlanRunner runs only,
8945
- * docs/07 section 1): from bind time on, every admitted spawn of any
8939
+ * Binds the run's TerminationAccount (DEF-2; PlanRunner runs only):
8940
+ * from bind time on, every admitted spawn of any
8946
8941
  * origin debits one spawnUnit atomically with its decision entry, and
8947
8942
  * a declared ladder longer than the frozen kMax rejects with
8948
8943
  * ladder_exceeds_frozen. Non-PlanRunner runs never bind an account and
@@ -8957,7 +8952,7 @@ var AdmissionController = class {
8957
8952
  return this.terminationAccount;
8958
8953
  }
8959
8954
  /**
8960
- * The lineage half of admission (DEF-3, docs/03 section 10.5): folds are
8955
+ * The lineage half of admission (DEF-3): folds are
8961
8956
  * computed live STRICTLY BEFORE the carrying decision entry is appended;
8962
8957
  * the caller embeds the returned block in the entry and replay reads it
8963
8958
  * back byte-exact. Enforces the single-live-attempt invariant
@@ -9170,7 +9165,7 @@ var AdmissionController = class {
9170
9165
  * Resume roll-forward for a child that already SETTLED before the
9171
9166
  * resume: re-registers the counters (maxChildrenPerNode, the lifetime
9172
9167
  * cap, statsBefore fidelity) without committing any reserve; the spend
9173
- * itself sits in the root ledger seed (docs/03, 13.3).
9168
+ * itself sits in the root ledger seed.
9174
9169
  */
9175
9170
  recoverSettled(parentAccountScope) {
9176
9171
  this.budget.admitRecovered(0, parentAccountScope);
@@ -9180,8 +9175,8 @@ var AdmissionController = class {
9180
9175
  /**
9181
9176
  * Resume roll-forward for an admission whose decision entry exists but
9182
9177
  * whose child has NOT settled: re-applies the recorded reserve and
9183
- * counters without re-evaluating any limit (docs/07, 7.1: replay never
9184
- * re-evaluates admission; docs/06, 5.1: reserves are recovered, never
9178
+ * counters without re-evaluating any limit (replay never
9179
+ * re-evaluates admission; reserves are recovered, never
9185
9180
  * re-estimated).
9186
9181
  */
9187
9182
  recoverInFlight(parentAccountScope, verdict) {
@@ -9195,7 +9190,7 @@ var AdmissionController = class {
9195
9190
  //#endregion
9196
9191
  //#region src/orchestrator/handles.ts
9197
9192
  /**
9198
- * The committed WakeDigest render budget (docs/06, Appendix A: 400
9193
+ * The committed WakeDigest render budget (Appendix A: 400
9199
9194
  * chars per outputSummary row, the character measure; committed at M10
9200
9195
  * entry by adopting the implemented distillation cap unchanged, the
9201
9196
  * value frozen into every cassette since M6). One value serves both
@@ -9205,8 +9200,8 @@ var AdmissionController = class {
9205
9200
  const WAKE_SUMMARY_RENDER_BUDGET_CHARS = 400;
9206
9201
  /**
9207
9202
  * The M6 outputSummary: a deterministic truncation of the child's
9208
- * output (or error message), identical live and on replay (docs/07
9209
- * section 2, clause 3: distillation lives with the child, ordered by
9203
+ * output (or error message), identical live and on replay (distillation
9204
+ * lives with the child, ordered by
9210
9205
  * spawn ordinal; the LLM distillation upgrade is M7 territory).
9211
9206
  */
9212
9207
  function summarizeOutput(result) {
@@ -9226,7 +9221,7 @@ function digestOf(record, result) {
9226
9221
  }
9227
9222
  //#endregion
9228
9223
  //#region src/orchestrator/wake.ts
9229
- /** docs/07 4.8: the wait_for_events parameter schema (normative). */
9224
+ /** The wait_for_events parameter schema (normative). */
9230
9225
  const WAIT_FOR_EVENTS_SCHEMA = {
9231
9226
  type: "object",
9232
9227
  additionalProperties: false,
@@ -9303,7 +9298,7 @@ function emptyDigestBlocks() {
9303
9298
  }
9304
9299
  //#endregion
9305
9300
  //#region src/orchestrator/spawn-tools.ts
9306
- /** docs/07 4.2: the spawn_agent parameter schema (normative). */
9301
+ /** The spawn_agent parameter schema (normative). */
9307
9302
  const SPAWN_AGENT_SCHEMA = {
9308
9303
  type: "object",
9309
9304
  additionalProperties: false,
@@ -9354,7 +9349,7 @@ const SPAWN_AGENT_SCHEMA = {
9354
9349
  taskClass: { type: "string" }
9355
9350
  }
9356
9351
  };
9357
- /** docs/07 4.3: parallel_agents wraps the spawn_agent params. */
9352
+ /** parallel_agents wraps the spawn_agent params. */
9358
9353
  const PARALLEL_AGENTS_SCHEMA = {
9359
9354
  type: "object",
9360
9355
  additionalProperties: false,
@@ -9366,7 +9361,7 @@ const PARALLEL_AGENTS_SCHEMA = {
9366
9361
  } },
9367
9362
  $defs: { spawnAgentParams: SPAWN_AGENT_SCHEMA }
9368
9363
  };
9369
- /** docs/07 4.4: await_any and await_all share one parameter shape. */
9364
+ /** await_any and await_all share one parameter shape. */
9370
9365
  const AWAIT_SCHEMA = {
9371
9366
  type: "object",
9372
9367
  additionalProperties: false,
@@ -9380,7 +9375,7 @@ const AWAIT_SCHEMA = {
9380
9375
  }
9381
9376
  } }
9382
9377
  };
9383
- /** docs/07 4.5: cancel_agent. */
9378
+ /** The cancel_agent parameter schema. */
9384
9379
  const CANCEL_AGENT_SCHEMA = {
9385
9380
  type: "object",
9386
9381
  additionalProperties: false,
@@ -9393,7 +9388,7 @@ const CANCEL_AGENT_SCHEMA = {
9393
9388
  reason: { type: "string" }
9394
9389
  }
9395
9390
  };
9396
- /** docs/07 4.11: finish; result validates against the declared output schema. */
9391
+ /** finish; result validates against the declared output schema. */
9397
9392
  const FINISH_SCHEMA = {
9398
9393
  type: "object",
9399
9394
  additionalProperties: false,
@@ -9407,7 +9402,7 @@ const FINISH_TOOL_NAME = "finish";
9407
9402
  /**
9408
9403
  * Builds the mode (c) toolset over the per-call runtime. profileCardText
9409
9404
  * rides the spawn tools' descriptions so both modes speak one agent
9410
- * vocabulary (docs/06 9.3; M6-T04).
9405
+ * vocabulary (M6-T04).
9411
9406
  */
9412
9407
  function buildOrchestratorTools(runtime, profileCardText) {
9413
9408
  return [
@@ -9508,15 +9503,13 @@ function runtimeOf(ctx) {
9508
9503
  * log, budget, and the deterministic shims; workflow/orchestrate/
9509
9504
  * awaitExternal/brief land with their milestones (M2/M6).
9510
9505
  *
9511
- * Owning spec: docs/06-execution-spec.md, sections "Canonical Ctx
9512
- * interface", "Error policy and dropped results", "Scheduler".
9506
+ * Public contract: https://docs.rulvar.com/guide/workflows.
9513
9507
  */
9514
9508
  /**
9515
9509
  * The rejection carrier of ctx.agent value-form calls: a real Error that
9516
- * structurally satisfies the typed AgentError (docs/06, section "ctx.agent
9517
- * and AgentOpts") and carries the full AgentResult for Settled mapping.
9518
- * Deliberately not a RulvarError: AgentError is not in the closed code
9519
- * registry (docs/02, section "Error taxonomy").
9510
+ * structurally satisfies the typed AgentError and carries the full
9511
+ * AgentResult for Settled mapping. Deliberately not a RulvarError:
9512
+ * AgentError is not in the closed code registry.
9520
9513
  */
9521
9514
  var AgentCallError = class extends Error {
9522
9515
  kind;
@@ -9560,9 +9553,9 @@ function bump(map, key, usd) {
9560
9553
  }
9561
9554
  /**
9562
9555
  * Completes a model-authored escalation request into the full report:
9563
- * costToDate and salvage are runtime-filled, never model-filled (docs/07,
9564
- * section 6.3). The worktree patch ref lands after collect(); the
9565
- * pre-dispose preview for flavor B decision-makers omits it.
9556
+ * costToDate and salvage are runtime-filled, never model-filled. The
9557
+ * worktree patch ref lands after collect(); the pre-dispose preview for
9558
+ * flavor B decision-makers omits it.
9566
9559
  */
9567
9560
  function buildEscalationReport(request, result, worktreePatchRef) {
9568
9561
  return {
@@ -10528,7 +10521,7 @@ function createCtx(internals) {
10528
10521
  }
10529
10522
  /**
10530
10523
  * Per-(scope, name) invocation ordinals of ctx.workflow, in execution
10531
- * order (docs/03, section 2.2: nested workflow scopes).
10524
+ * order (nested workflow scopes).
10532
10525
  */
10533
10526
  const workflowOrdinals = /* @__PURE__ */ new Map();
10534
10527
  const nextWorkflowOrdinal = (scope, name) => {
@@ -10546,7 +10539,7 @@ function createCtx(internals) {
10546
10539
  rebuilt.name = wire.code;
10547
10540
  return rebuilt;
10548
10541
  };
10549
- /** Maps an embedded admission rejection onto its typed error (docs/07, 7.3). */
10542
+ /** Maps an embedded admission rejection onto its typed error. */
10550
10543
  const rejectionError = (reason, name) => {
10551
10544
  if (reason.code === "budget" || reason.code === "lifetime") return new BudgetExhaustedError(`admission rejected child workflow '${name}' (${reason.code})`, { data: { reason } });
10552
10545
  return new AdmissionRejectedError(`admission rejected child workflow '${name}' (${reason.code}; maxDepth/maxChildrenPerNode are set via createEngine budgetDefaults)`, { data: { reason } });
@@ -10850,8 +10843,7 @@ async function executeWorkflow(internals, wf, args) {
10850
10843
  /**
10851
10844
  * The mode (c) dynamic orchestrator (M6-T07/T08).
10852
10845
  *
10853
- * Owning spec: docs/06-execution-spec.md section 9.3 and
10854
- * docs/07-adaptive-orchestration-spec.md sections 1 and 4. An ordinary
10846
+ * Full contract: https://docs.rulvar.com/guide/adaptive-orchestration. An ordinary
10855
10847
  * workflow whose agent (role 'orchestrate') holds the typed spawn tools;
10856
10848
  * both surfaces (top-level orchestrate() and ctx.orchestrate) share this
10857
10849
  * one implementation, the nested surface riding ctx.workflow so the
@@ -10862,7 +10854,7 @@ async function executeWorkflow(internals, wf, args) {
10862
10854
  * ordinary kind 'agent' entry; a crashed orchestrate() restores its
10863
10855
  * history from the checkpoint and finds child results by content keys,
10864
10856
  * WITHOUT regenerating spawn decisions and without re-paying children.
10865
- * Non-PlanRunner applicability (docs/07 section 1): only the lifetime
10857
+ * Non-PlanRunner applicability: only the lifetime
10866
10858
  * cap, maxDepth, and the budget layers apply; no termination.init is
10867
10859
  * written; escalated children simply settle into their digests.
10868
10860
  */
@@ -10881,7 +10873,7 @@ function orchestratorPrompt(goal, maxSpawns, extensionLines) {
10881
10873
  }
10882
10874
  /**
10883
10875
  * Resolves per-spawn dispatch options against the engine registries
10884
- * (docs/08: registered SchemaSpec and tool profile names; M7-T05). An
10876
+ * (registered SchemaSpec and tool profile names; M7-T05). An
10885
10877
  * unknown ref is a typed ConfigError, surfaced as a tool error to the
10886
10878
  * orchestrator and never a run failure.
10887
10879
  */
@@ -11164,7 +11156,7 @@ function makeOrchestratorWorkflow(goal, opts) {
11164
11156
  const forcedFinishController = new AbortController();
11165
11157
  let capInFlight = false;
11166
11158
  /**
11167
- * The at-cap freeze (docs/07, 12.4): EXACTLY one decision entry
11159
+ * The at-cap freeze: EXACTLY one decision entry
11168
11160
  * strictly before any effects; then the plan freezes for adaptation,
11169
11161
  * wake triggers except quiescence disarm, and the orchestrator is
11170
11162
  * driven to the reserved final wake. Crash between the entry and the
@@ -11211,7 +11203,7 @@ function makeOrchestratorWorkflow(goal, opts) {
11211
11203
  }, callingState.spanId);
11212
11204
  forcedFinishController.abort("rulvar:forced-finish");
11213
11205
  };
11214
- /** Layer-1 soft boundary before delivering each wake (docs/07, 12.3). */
11206
+ /** Layer-1 soft boundary before delivering each wake. */
11215
11207
  const overSoftBoundary = () => {
11216
11208
  if (capState === void 0 || orchestratorAccount === void 0 || extension === void 0) return false;
11217
11209
  return (internals.budget.accountView(orchestratorAccount)?.spentUsd ?? 0) + capState.turnEstimateUsd > capState.effectiveCapUsd - capState.finalizeReserveUsd;
@@ -11463,7 +11455,7 @@ function makeOrchestratorWorkflow(goal, opts) {
11463
11455
  ladders,
11464
11456
  ...internals.floors === void 0 ? {} : { floors: internals.floors },
11465
11457
  now: new Date(internals.now()).toISOString()
11466
- }), ladders);
11458
+ }), ladders, { profiles: advertisedProfiles });
11467
11459
  await internals.replayer.appendSinglePhase({
11468
11460
  scope: callingState.scope,
11469
11461
  key,
@@ -11520,6 +11512,7 @@ function makeOrchestratorWorkflow(goal, opts) {
11520
11512
  role: "orchestrate",
11521
11513
  result: "full",
11522
11514
  tools: [...buildOrchestratorTools(orchestratorRuntime, fullCardText), ...extension?.tools(io) ?? []],
11515
+ ...capState === void 0 ? {} : { estCost: capState.effectiveCapUsd },
11523
11516
  ...opts?.model === void 0 ? {} : { model: opts.model },
11524
11517
  ...opts?.limits === void 0 ? {} : { limits: opts.limits },
11525
11518
  [kOnRunning]: (seq) => {
@@ -11533,7 +11526,7 @@ function makeOrchestratorWorkflow(goal, opts) {
11533
11526
  if (orchestratorAccount !== void 0) orchestratorState.budgetScope = orchestratorAccount;
11534
11527
  orchestratorState.signal = callingState.signal === void 0 ? forcedFinishController.signal : AbortSignal.any([callingState.signal, forcedFinishController.signal]);
11535
11528
  /**
11536
- * The reserved final wake (docs/07, 12.4 d): a FRESH agent entry on
11529
+ * The reserved final wake: a FRESH agent entry on
11537
11530
  * the restricted single-tool toolset (a different toolsetHash), a
11538
11531
  * prompt deterministically derived from the journaled cap decision
11539
11532
  * and the pinned digest, and a finalizeTurns limit, paid from the
@@ -11551,6 +11544,7 @@ function makeOrchestratorWorkflow(goal, opts) {
11551
11544
  result: "full",
11552
11545
  tools: finishOnly,
11553
11546
  limits: { maxTurns: capState?.finalizeTurns ?? 2 },
11547
+ ...capState === void 0 ? {} : { estCost: capState.finalizeReserveUsd },
11554
11548
  ...opts?.model === void 0 ? {} : { model: opts.model },
11555
11549
  [kTerminalTool]: { name: FINISH_TOOL_NAME }
11556
11550
  };
@@ -11603,7 +11597,7 @@ function makeOrchestratorWorkflow(goal, opts) {
11603
11597
  return result.output;
11604
11598
  });
11605
11599
  }
11606
- /** Top-level surface: creates a run (docs/06 9.3). */
11600
+ /** Top-level surface: creates a run. */
11607
11601
  function orchestrate(engine, goal, opts) {
11608
11602
  return engine.run(makeOrchestratorWorkflow(goal, opts), void 0);
11609
11603
  }
@@ -11613,16 +11607,13 @@ function orchestrate(engine, goal, opts) {
11613
11607
  * Per-run event machinery (M1-T10): the span registry (run > phase >
11614
11608
  * agent > tool > child hierarchy) and the event bus that stamps the
11615
11609
  * WorkflowEvent envelope, feeds RunHandle.events / on(), and fans out to
11616
- * subscribers. EventSink is deliberately not an SPI (docs/02, section
11617
- * "SPI seams and the 1.0 freeze").
11610
+ * subscribers. EventSink is deliberately not an SPI.
11618
11611
  *
11619
- * Owning spec: docs/09-observability-testing-spec.md, section "Event
11620
- * stream".
11612
+ * Full contract: https://docs.rulvar.com/guide/observability.
11621
11613
  */
11622
11614
  /**
11623
11615
  * Spans form a tree per run; spanId values are engine-minted opaque
11624
- * strings, unique per run, pure telemetry, never identity (docs/09,
11625
- * section "Span hierarchy").
11616
+ * strings, unique per run, pure telemetry, never identity.
11626
11617
  */
11627
11618
  var SpanRegistry = class {
11628
11619
  parents = /* @__PURE__ */ new Map();
@@ -11787,15 +11778,14 @@ var InProcessRunner = class {
11787
11778
  * Engine entry points (M1-T11): createEngine and engine.run over the
11788
11779
  * InProcessRunner. Every registry hangs off the engine instance; nothing
11789
11780
  * is module-global, so two engines in one process are fully isolated and
11790
- * ctx is created per run (docs/02, section "Engine anatomy"; docs/06,
11791
- * section "Engine and ops API"). engine.resume lands with the journal
11781
+ * ctx is created per run. engine.resume lands with the journal
11792
11782
  * kernel in M2.
11793
11783
  */
11794
- /** Content hash of an in-process workflow body (run-to-definition binding, docs/06 10.2). */
11784
+ /** Content hash of an in-process workflow body (run-to-definition binding). */
11795
11785
  function hashWorkflowBody(wf) {
11796
11786
  return createHash("sha256").update(wf.body.toString(), "utf8").digest("hex");
11797
11787
  }
11798
- /** Content hash of a compiled workflow source (run-to-definition binding, docs/06 10.2). */
11788
+ /** Content hash of a compiled workflow source (run-to-definition binding). */
11799
11789
  function hashWorkflowSource(source) {
11800
11790
  return createHash("sha256").update(source, "utf8").digest("hex");
11801
11791
  }
@@ -12212,11 +12202,11 @@ function createEngine(options) {
12212
12202
  /**
12213
12203
  * The host half of the worker sandbox contract (M6-T02).
12214
12204
  *
12215
- * Owning spec: docs/06-execution-spec.md, section 8.2. WorkerSandboxRunner
12205
+ * Full contract: https://docs.rulvar.com/guide/planner. WorkerSandboxRunner
12216
12206
  * (@rulvar/planner) owns the worker lifecycle and the MessagePort; this
12217
12207
  * core-owned bridge serves every sandbox primitive against the canonical
12218
- * ctx of the run, so the runner builds exclusively from the public API
12219
- * (docs/02, dependency rules). The boundary is journal-compatible JSON
12208
+ * ctx of the run, so the runner builds exclusively from the public API.
12209
+ * The boundary is journal-compatible JSON
12220
12210
  * validated on both sides; raw structured clone is NOT the contract.
12221
12211
  *
12222
12212
  * Responsibilities:
@@ -12488,4 +12478,4 @@ function createSandboxBridge(ctx, options) {
12488
12478
  };
12489
12479
  }
12490
12480
  //#endregion
12491
- export { AWAIT_SCHEMA, AdmissionController, AdmissionRejectedError, AgentCallError, BUDGET_ABORT_REASON, BudgetExhaustedError, CANCEL_AGENT_SCHEMA, CHECKPOINT_FORMAT_V1, CLAIM_STATEMENT_MAX_CHARS, CLAIM_TTL_DAYS, COMPACTION_SUMMARY_PREFIX, CURRENT_HASH_VERSION, ConfigError, DEFAULT_CHILD_BUDGET_FRACTION, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_FLAT_RESERVE_USD, DEFAULT_MAX_CHILDREN_PER_NODE, DEFAULT_MAX_DEPTH, DEFAULT_MAX_OSCILLATIONS_PER_KEY, DEFAULT_MAX_PINNED_WORKTREES, DEFAULT_MAX_REVISIONS_PER_RUN, DEFAULT_MAX_TOTAL_SPAWNS, DEFAULT_MAX_TURNS, DEFAULT_MODEL_RETRY_ATTEMPTS, DEFAULT_NO_PROGRESS_TURNS, DEFAULT_PER_RUN_CONCURRENCY, DEFAULT_RETRY_POLICY, DEFAULT_STREAM_IDLE_TIMEOUT_MS, DedupIndex, EMIT_RESULT_TOOL, EMPTY_SCHEMA_HASH, EMPTY_TOOLSET_HASH, ESCALATE_TOOL_NAME, ESCALATION_REPORT_SCHEMA, ESCALATION_REQUEST_SCHEMA, EventBus, ExternalRegistry, FINISH_SCHEMA, FINISH_TOOL_NAME, FileModelKnowledgeStore, FileTranscriptStore, GitWorktreeProvider, INBOX_PROPOSAL_TTL_DAYS, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, InvalidResolutionError, JournalCompatibilityError, JournalMatcher, JournalMissError, JournalOrderViolation, JsonlFileStore, KB_ACTIVE_CLAIMS_CAP, KB_CARD_RENDER_BUDGET_CHARS, KeyedLimiter, KnowledgeCasError, LARGE_VALUE_WARN_BYTES, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LINEAGE_SIG_VERSION, LeaseHeldError, LineageIndex, MASKED_SECRET, MAX_DEPTH_CEILING, ModelRetry, NoProgressDetector, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OrchestratorCapConfigError, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, PlanInvariantError, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, ReplayPlanHashMismatch, Replayer, ResolutionArbiter, ResolutionFold, RulvarError, RunBudget, SPAWN_AGENT_SCHEMA, SandboxError, ScriptRejected, Semaphore, SpanRegistry, TOOL_NAME_PATTERN, TerminationAccount, WAIT_FOR_EVENTS_SCHEMA, WAIT_FOR_EVENTS_TOOL_NAME, WAKE_SUMMARY_RENDER_BUDGET_CHARS, admissionReserveUsd, agentErrorFromWire, agentErrorToWire, agentScope, applyClaimOps, applyStructuredOutputTier, approachSigCoarse, approachSigOf, archiveDeprecatedModelOps, atCompactionThreshold, buildAbandonFold, buildAdapterRegistry, buildCostReport, buildDeriverRegistry, buildOrchestratorTools, buildTerminationInitValue, buildToolContext, canRideLoopTurn, canonicalIsolationTag, canonicalizeLadder, canonicalizeSchema, capIssues, capsHashOf, checkFloors, checkpointRefFor, childCoveragePrefix, claimExpired, claimExpiry, claimIssues, claimOpIssues, classifyAgentError, classifyAttemptOutcome, collectDeclaredLadders, compactMessages, compilePermissionChain, compilePermissionPreset, compileVerifiedLayer, costReportFromJournal, countsAgainstLimit, createCanonicalIdMinter, createCtx, createEngine, createSandboxBridge, currentOnlyKeyRing, decodeCheckpoint, defineWorkflow, deriveContentKey, deriverV1, deriverV2, digestOf, dispositionHook, emptyDigestBlocks, emptyToolset, encodeCheckpoint, escalateTool, evaluatePermission, evaluateReuse, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, priceUsdOf, profileCard, profileRegistrySnapshotHash, projectHistory, projectIdentity, projectToJsonSchema, providerOf, readTerminationInit, registryKeyRing, remeasureQueue, replayDisposition, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, validateEditorialCommit, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateSchemaSpec, validateTerminationLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
12481
+ export { AWAIT_SCHEMA, AdmissionController, AdmissionRejectedError, AgentCallError, BUDGET_ABORT_REASON, BudgetExhaustedError, CANCEL_AGENT_SCHEMA, CHECKPOINT_FORMAT_V1, CLAIM_STATEMENT_MAX_CHARS, CLAIM_TTL_DAYS, COMPACTION_SUMMARY_PREFIX, CURRENT_HASH_VERSION, ConfigError, DEFAULT_CHILD_BUDGET_FRACTION, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_FLAT_RESERVE_USD, DEFAULT_MAX_CHILDREN_PER_NODE, DEFAULT_MAX_DEPTH, DEFAULT_MAX_OSCILLATIONS_PER_KEY, DEFAULT_MAX_PINNED_WORKTREES, DEFAULT_MAX_REVISIONS_PER_RUN, DEFAULT_MAX_TOTAL_SPAWNS, DEFAULT_MAX_TURNS, DEFAULT_MODEL_RETRY_ATTEMPTS, DEFAULT_NO_PROGRESS_TURNS, DEFAULT_PER_RUN_CONCURRENCY, DEFAULT_RETRY_POLICY, DEFAULT_STREAM_IDLE_TIMEOUT_MS, DedupIndex, EMIT_RESULT_TOOL, EMPTY_SCHEMA_HASH, EMPTY_TOOLSET_HASH, ESCALATE_TOOL_NAME, ESCALATION_REPORT_SCHEMA, ESCALATION_REQUEST_SCHEMA, EventBus, ExternalRegistry, FINISH_SCHEMA, FINISH_TOOL_NAME, FileModelKnowledgeStore, FileTranscriptStore, GitWorktreeProvider, INBOX_PROPOSAL_TTL_DAYS, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, InvalidResolutionError, JournalCompatibilityError, JournalMatcher, JournalMissError, JournalOrderViolation, JsonlFileStore, KB_ACTIVE_CLAIMS_CAP, KB_CARD_RENDER_BUDGET_CHARS, KeyedLimiter, KnowledgeCasError, LARGE_VALUE_WARN_BYTES, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LINEAGE_SIG_VERSION, LeaseHeldError, LineageIndex, MASKED_SECRET, MAX_DEPTH_CEILING, ModelRetry, NoProgressDetector, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OrchestratorCapConfigError, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, PlanInvariantError, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, ReplayPlanHashMismatch, Replayer, ResolutionArbiter, ResolutionFold, RulvarError, RunBudget, SPAWN_AGENT_SCHEMA, SandboxError, ScriptRejected, Semaphore, SpanRegistry, TOOL_NAME_PATTERN, TerminationAccount, WAIT_FOR_EVENTS_SCHEMA, WAIT_FOR_EVENTS_TOOL_NAME, WAKE_SUMMARY_RENDER_BUDGET_CHARS, admissionReserveUsd, agentErrorFromWire, agentErrorToWire, agentScope, applyClaimOps, applyStructuredOutputTier, approachSigCoarse, approachSigOf, archiveDeprecatedModelOps, atCompactionThreshold, buildAbandonFold, buildAdapterRegistry, buildCostReport, buildDeriverRegistry, buildOrchestratorTools, buildTerminationInitValue, buildToolContext, canRideLoopTurn, canonicalIsolationTag, canonicalizeLadder, canonicalizeSchema, capIssues, capsHashOf, checkFloors, checkpointRefFor, childCoveragePrefix, claimExpired, claimExpiry, claimIssues, claimOpIssues, classifyAgentError, classifyAttemptOutcome, collectDeclaredLadders, compactMessages, compilePermissionChain, compilePermissionPreset, compileVerifiedLayer, costReportFromJournal, countsAgainstLimit, createCanonicalIdMinter, createCtx, createEngine, createSandboxBridge, currentOnlyKeyRing, decodeCheckpoint, defineWorkflow, deriveContentKey, deriverV1, deriverV2, digestOf, dispositionHook, emptyDigestBlocks, emptyToolset, encodeCheckpoint, escalateTool, evaluatePermission, evaluateReuse, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, priceUsdOf, profileCard, profileRegistrySnapshotHash, projectHistory, projectIdentity, projectToJsonSchema, proposalStatement, providerOf, readTerminationInit, registryKeyRing, remeasureQueue, replayDisposition, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, validateEditorialCommit, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateSchemaSpec, validateTerminationLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };