@rulvar/core 1.35.0 → 1.37.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 +135 -16
  2. package/dist/index.js +381 -118
  3. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -28,7 +28,7 @@ type WireError = {
28
28
  * 'agent' is carried by the AgentError value projection, not by a
29
29
  * RulvarError subclass.
30
30
  */
31
- type ErrorCode = "agent" | "config" | "non_serializable_value" | "script_rejected" | "journal_compat" | "invalid_resolution" | "journal_order_violation" | "plan_invariant" | "replay_plan_hash_mismatch" | "orchestrator_cap_config" | "journal_miss" | "budget_exhausted" | "admission_rejected" | "sandbox_limit" | "lease_held" | "knowledge_cas";
31
+ type ErrorCode = "agent" | "config" | "non_serializable_value" | "script_rejected" | "journal_compat" | "invalid_resolution" | "journal_order_violation" | "plan_invariant" | "replay_plan_hash_mismatch" | "orchestrator_cap_config" | "journal_miss" | "budget_exhausted" | "fail_run" | "admission_rejected" | "sandbox_limit" | "lease_held" | "knowledge_cas";
32
32
  /** An alias for the registry type; both names are public. */
33
33
  type RulvarErrorCode = ErrorCode;
34
34
  /**
@@ -191,6 +191,23 @@ declare class BudgetExhaustedError extends RulvarError {
191
191
  });
192
192
  }
193
193
  /**
194
+ * A declared fail-run policy engaged and closed the run as a failure
195
+ * (v1.35.0 review P2-1): `budget.atCap: 'fail-run'` after the journaled
196
+ * orchestrator cap decision, or `guards.fallback: 'fail-run'` after the
197
+ * journaled guard verdict. The run outcome is 'error' with this code;
198
+ * `data.source` names the policy ('orchestrator_budget_cap' or
199
+ * 'plan_guards') and `data` carries the decision entry reference, so the
200
+ * outcome is a pure roll forward of the journal on resume: no second
201
+ * decision, no model call, no spend.
202
+ */
203
+ declare class FailRunError extends RulvarError {
204
+ readonly code = "fail_run";
205
+ constructor(message: string, opts?: {
206
+ data?: Json;
207
+ cause?: unknown;
208
+ });
209
+ }
210
+ /**
194
211
  * A structural admission rejection (maxDepth, maxChildrenPerNode,
195
212
  * maxTotalSpawns) from the AdmissionController (M6-T06). The rejection verdict is embedded in
196
213
  * the carrying spawn-admission decision entry and replays identically;
@@ -893,6 +910,14 @@ interface LeasableStore extends JournalStore {
893
910
  acquire(runId: string, owner: string): Promise<Lease>;
894
911
  renew(l: Lease): Promise<void>;
895
912
  release(l: Lease): Promise<void>;
913
+ /**
914
+ * Optional TTL introspection (v1.35.0 review P2-4): the configured
915
+ * lease ttl in milliseconds. A store exposing it lets createWorker
916
+ * VERIFY at construction that the worker's renew cadence matches the
917
+ * store's expiry instead of trusting two config sources to agree;
918
+ * stores without it are accepted with the worker's own ttl.
919
+ */
920
+ readonly leaseTtlMs?: number;
896
921
  }
897
922
  //#endregion
898
923
  //#region src/l0/spi/transcript.d.ts
@@ -1667,7 +1692,13 @@ declare function applyClaimOps(claims: readonly ModelClaim[], ops: readonly Clai
1667
1692
  interface FileModelKnowledgeStoreOptions {
1668
1693
  /** Default './rulvar.models.json'. */
1669
1694
  path?: string;
1670
- /** Active claims per (model, taskClass); default 8. */
1695
+ /**
1696
+ * Active claims per (model, taskClass); default 8. A nonnegative
1697
+ * integer (zero refuses every active claim), validated at
1698
+ * construction: the enforcement compares `count > cap`, and every
1699
+ * comparison with NaN is false, so an unvalidated NaN or Infinity
1700
+ * silently disabled the cap (v1.35.0 review P2-5).
1701
+ */
1671
1702
  activeClaimsCap?: number;
1672
1703
  }
1673
1704
  declare class FileModelKnowledgeStore implements ModelKnowledgeStore {
@@ -2792,7 +2823,11 @@ interface EscalationOptions {
2792
2823
  deadlineMs?: number;
2793
2824
  /** Applied by the timeout resolution (by: 'timeout'); default accept. */
2794
2825
  defaultDecision?: EscalationDecision;
2795
- /** In-run minimum spend before scope_bigger; default 0 (M3-T09). */
2826
+ /**
2827
+ * In-run minimum spend before scope_bigger; default 0 (M3-T09). A
2828
+ * finite number >= 0, validated before any LLM call: the gate
2829
+ * compares spend against it, and a NaN would silently disable it.
2830
+ */
2796
2831
  minSpendUsd?: number;
2797
2832
  }
2798
2833
  /** The model-facing request: the report minus the runtime-filled fields. */
@@ -5244,6 +5279,18 @@ interface OrchestratorExtensionIO {
5244
5279
  */
5245
5280
  replayed?: boolean;
5246
5281
  }): void;
5282
+ /**
5283
+ * A deterministic run failure declared by the extension (v1.35.0 review P2-1):
5284
+ * the first call stores the error and aborts the orchestrator loop;
5285
+ * the orchestrate settle boundary rethrows it, so the run fails with
5286
+ * the given typed error instead of asking the model to finish. Later
5287
+ * calls do nothing. The intended producer is a journaled
5288
+ * policy verdict (the PlanRunner guards fallback 'fail-run'): boot
5289
+ * terminates again from the journal on resume, so the failure rolls
5290
+ * forward without another decision or model call. Optional so
5291
+ * IO implementations built before v1.36 keep compiling.
5292
+ */
5293
+ terminate?(error: Error): void;
5247
5294
  }
5248
5295
  /**
5249
5296
  * The extension contract. PlanRunner implements it in @rulvar/plan; the
@@ -5290,17 +5337,43 @@ interface OrchestratorExtension {
5290
5337
  */
5291
5338
  interface OrchestratorBudgetSpec {
5292
5339
  /**
5293
- * Absolute bound in USD. It never REPLACES the fraction bound:
5340
+ * Absolute bound in USD: a finite number >= 0, validated before any
5341
+ * journal entry or dispatch (a malformed value is a ConfigError). It
5342
+ * never REPLACES the fraction bound:
5294
5343
  * effectiveCap = min(capUsd, (capFraction ?? 0.2) * ceiling), so an
5295
5344
  * explicit capUsd larger than the default fraction of the run ceiling
5296
5345
  * is still cut to that fraction (and a warn log says so). Pass
5297
5346
  * capFraction: 1.0 to make capUsd the sole bound.
5298
5347
  */
5299
5348
  capUsd?: number;
5300
- /** default 0.2; effectiveCap = min of the given bounds */
5349
+ /**
5350
+ * A fraction in (0, 1], default 0.2; effectiveCap = min of the given
5351
+ * bounds. Zero does not lift the cap (it would make every turn
5352
+ * unpayable): anything outside (0, 1] is a ConfigError before any
5353
+ * journal entry or dispatch.
5354
+ */
5301
5355
  capFraction?: number;
5356
+ /**
5357
+ * A finite number >= 0, validated before any journal entry or
5358
+ * dispatch. The reserve is SUBTRACTED from the soft boundary, so a
5359
+ * negative value would widen the cap instead of reserving.
5360
+ */
5302
5361
  finalizeReserveUsd?: number;
5362
+ /**
5363
+ * A positive integer, validated before any journal entry or dispatch:
5364
+ * the turn limit of the reserved final wake.
5365
+ */
5303
5366
  finalizeTurns?: number;
5367
+ /**
5368
+ * The policy at the cap, validated as exactly one of the two literals
5369
+ * even at a plain JS/JSON boundary. 'finish-with-partial' (default)
5370
+ * runs the reserved finalizer and returns its partial result with run
5371
+ * outcome 'ok'. 'fail-run' skips the finalizer entirely: the run
5372
+ * fails with outcome 'error' carrying FailRunError (code 'fail_run',
5373
+ * data.source 'orchestrator_budget_cap', data.capDecisionRef); resume
5374
+ * rolls the same failure forward from the journaled cap decision
5375
+ * without another model call.
5376
+ */
5304
5377
  atCap?: "finish-with-partial" | "fail-run";
5305
5378
  }
5306
5379
  /** Options for orchestrate(engine, goal, o?). */
@@ -5308,13 +5381,19 @@ interface OrchestrateOptions {
5308
5381
  model?: ModelSpec;
5309
5382
  /** Registered profile names to advertise; default: every profile. */
5310
5383
  profiles?: string[];
5311
- /** Per-orchestrate spawn cap; the engine lifetime cap applies regardless. */
5384
+ /**
5385
+ * Per-orchestrate spawn cap: a nonnegative integer (zero admits no
5386
+ * spawns), validated before any journal entry or dispatch. The engine
5387
+ * lifetime cap applies regardless.
5388
+ */
5312
5389
  maxSpawns?: number;
5313
5390
  /** The orchestrator's own budget sub-account (cap enforcement layers only in M6). */
5314
5391
  budget?: OrchestratorBudgetSpec;
5315
5392
  /**
5316
- * Deterministic digest render bound: each
5317
- * TaskDigest outputSummary is clamped to this many CHARACTERS (the
5393
+ * Deterministic digest render bound: a nonnegative integer, validated
5394
+ * before any journal entry or dispatch. Each TaskDigest outputSummary
5395
+ * is truncated to AT MOST this many CHARACTERS, the truncation marker
5396
+ * included (a budget below 3 keeps the bound with a bare slice; the
5318
5397
  * model-independent measure; OQ-04 closed at M10 entry). Default
5319
5398
  * WAKE_SUMMARY_RENDER_BUDGET_CHARS.
5320
5399
  */
@@ -5384,6 +5463,20 @@ declare class Semaphore {
5384
5463
  }
5385
5464
  //#endregion
5386
5465
  //#region src/engine/external.d.ts
5466
+ /**
5467
+ * The rejection carrier of an aborted flavor B decision wait (v1.35.0
5468
+ * review P1): the parked `awaitDecision` observes the branch/run
5469
+ * AbortSignal, releases its held activity, removes its waiter, and
5470
+ * rejects with this class so cancel, host abort, the run deadline, and
5471
+ * failed sibling aborts all settle the run in bounded time.
5472
+ * Deliberately not a RulvarError: the abort is cancellation intent, not
5473
+ * a registry failure class; the suspension entry stays OPEN, so a later
5474
+ * resume parks the decision again and the durable deadline still applies.
5475
+ */
5476
+ declare class EscalationDecisionAbortedError extends Error {
5477
+ readonly entryRef: number;
5478
+ constructor(message: string, entryRef: number);
5479
+ }
5387
5480
  /** The resolution value shape of a tool-approval suspension (M3-T03). */
5388
5481
  interface ApprovalDecision {
5389
5482
  decision: "allow" | "deny";
@@ -5484,6 +5577,13 @@ declare class ExternalRegistry {
5484
5577
  toolName: string;
5485
5578
  input: Json;
5486
5579
  deadlineAt: string;
5580
+ /**
5581
+ * The branch/run signal: an abort while parked releases the held
5582
+ * activity, removes the waiter, and rejects with
5583
+ * EscalationDecisionAbortedError (v1.35.0 review P1). The suspension
5584
+ * entry stays open for resume.
5585
+ */
5586
+ signal?: AbortSignal;
5487
5587
  onPending?: (entry: JournalEntry, replayed: boolean) => void;
5488
5588
  }): Promise<{
5489
5589
  value: Json;
@@ -5548,7 +5648,8 @@ interface AgentProfile {
5548
5648
  /**
5549
5649
  * Per-profile compaction threshold; default 0.8 of the loop model's
5550
5650
  * contextWindow (M4-T03). Compaction is ON by
5551
- * default; history-processor plumbing stays engine-internal.
5651
+ * default; history-processor plumbing stays engine-internal. The
5652
+ * threshold is a fraction in (0, 1], validated at createEngine.
5552
5653
  */
5553
5654
  compaction?: {
5554
5655
  threshold?: number;
@@ -5987,8 +6088,12 @@ declare function compileVerifiedLayer(claims: readonly ModelClaim[], ladders: re
5987
6088
  /**
5988
6089
  * The deterministic card render. Pure: same filtered
5989
6090
  * claims and ladders give byte-identical text. The render budget is
5990
- * 4096 chars; over it, the OLDEST-observed notes
5991
- * withhold first behind an explicit marker.
6091
+ * 4096 chars by default; over it, the OLDEST-observed notes withhold
6092
+ * first behind an explicit marker, and the budget is a HARD upper bound
6093
+ * of the returned string: a card whose mandatory sections alone exceed
6094
+ * it is truncated with the shared marker (v1.35.0 review P2-5: a budget
6095
+ * of 32 used to return the full 136-char header form). budgetChars is a
6096
+ * nonnegative integer, validated as a ConfigError.
5992
6097
  */
5993
6098
  declare function modelKnowledgeCard(claims: readonly ModelClaim[], ladders: readonly DeclaredLadder[], options?: {
5994
6099
  budgetChars?: number;
@@ -6166,7 +6271,14 @@ interface GitWorktreeProviderOptions {
6166
6271
  * requests keep on dispose. Default false.
6167
6272
  */
6168
6273
  keepOnError?: boolean;
6169
- /** Pin cap shared by park/unpark and retainWorktree (default 4). */
6274
+ /**
6275
+ * Pin cap shared by park/unpark and retainWorktree (default 4). A
6276
+ * nonnegative integer (zero retains nothing), validated at
6277
+ * construction: the retention compares `pinned.size < cap`, and every
6278
+ * comparison with NaN is false, so an unvalidated NaN performed the
6279
+ * acquire effects and then dropped every tree as "cap reached"
6280
+ * (v1.35.0 review P2-5).
6281
+ */
6170
6282
  maxPinnedWorktrees?: number;
6171
6283
  /** Warning sink (cap overflow); defaults to process.emitWarning. */
6172
6284
  onWarn?: (msg: string) => void;
@@ -6357,9 +6469,16 @@ declare class JsonlFileStore implements MetaLookupStore {
6357
6469
  /**
6358
6470
  * File-backed TranscriptStore (M6-T02): blobs (transcripts, checkpoints,
6359
6471
  * persisted CompiledWorkflow sources) as one file per ref under `dir`,
6360
- * so compiled runs resume across processes. Refs follow
6361
- * the `<runId>/<name>` convention; each path segment is checked
6362
- * filesystem-safe and nested segments become directories.
6472
+ * so compiled runs resume across processes. Refs follow the
6473
+ * `<runId>/<name>` convention; nested segments become directories.
6474
+ *
6475
+ * Every ref is contained under `dir` (v1.36.0 review SEC-P1): each
6476
+ * segment must match `[A-Za-z0-9._-]` and be neither empty, '.', nor
6477
+ * '..', and the resolved path must stay under the resolved root. A '..'
6478
+ * segment used to pass the per-segment alphabet (dots are in it) and, via
6479
+ * `join`, escape the root; a caller passing an untrusted ref (or an
6480
+ * untrusted runId, which prefixes checkpoint and workflow-source refs)
6481
+ * could read, write, or delete `.bin` files outside `dir`.
6363
6482
  */
6364
6483
  declare class FileTranscriptStore implements TranscriptStore {
6365
6484
  private readonly dir;
@@ -6779,4 +6898,4 @@ interface SandboxBridge {
6779
6898
  declare const SANDBOX_AGENT_OPT_KEYS: readonly string[];
6780
6899
  declare function createSandboxBridge(ctx: Ctx<never>, options: SandboxBridgeOptions): SandboxBridge;
6781
6900
  //#endregion
6782
- export { AWAIT_SCHEMA, AbandonAttempt, AbandonFold, AbandonPayload, AbandonedSpendView, AbortClass, type AdaptiveEvents, AdmissionController, AdmissionDecision, AdmissionRejectedError, AdmissionStatsBefore, AdmitLineage, AdmitRejectReason, AdmitSpec, AdmitVerdict, AgentCallError, AgentError, type AgentEvents, AgentIdentityInput, AgentOpts, AgentProfile, AgentProfilePermissions, AgentResult, AgentResultMeta, AgentStatus, ApproachSignatureInputs, ApprovalDecision, ApprovalIdentityInput, Artifact, AttemptOutcomeClass, BUDGET_ABORT_REASON, BaseAppend, BriefOpts, BudgetAccountView, BudgetDefaults, BudgetExhaustedError, BudgetExhaustionDiagnostics, BudgetHooks, BudgetReserve, type Bytes, CANCEL_AGENT_SCHEMA, CHECKPOINT_FORMAT_V1, CLAIM_STATEMENT_MAX_CHARS, CLAIM_TTL_DAYS, COMPACTION_SUMMARY_PREFIX, CURRENT_HASH_VERSION, CacheHint, CacheTtl, CanUseTool, CanonicalId, CanonicalIdentity, CanonicalLadderSpec, CanonicalModelSpec, ChatEvent, ChatRequest, CheckpointState, ChildIdentityInput, type ClaimClass, type ClaimOp, type ClaimStatus, ClaimValidationOptions, CollectOpts, CollectedTurn, CompactionConfig, CompiledPermissionChain, CompiledWorkflow, ConfigError, type CoreEvents, CostAttribution, CostAttributionFacts, CostReport, CreateEngineOptions, Ctx, 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, DebitResult, DeclaredLadder, DedupIndex, DedupNote, DerivedKey, DeriverRegistry, DispositionRule, DispositionTable, DonorCandidate, DonorRef, DroppedItem, EMIT_RESULT_TOOL, EMPTY_SCHEMA_HASH, EMPTY_TOOLSET_HASH, ESCALATE_TOOL_NAME, ESCALATION_REPORT_SCHEMA, ESCALATION_REQUEST_SCHEMA, EVENT_SEGMENT_STRIDE, EffectiveUsageLimits, Effort, Engine, EngineDefaults, EntryKind, EntryRef, EntryStatus, ErrorClass, ErrorCode, ErrorPolicy, EscalatedResult, EscalationDecision, EscalationDigest, EscalationKind, EscalationLimits, EscalationOptions, EscalationReport, EscalationRequest, EventBus, type EvidenceRef, ExtensionAppendInput, ExtensionDispatchSpec, ExternalIdentityInput, ExternalRegistry, ExtractNecessityInput, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FailoverTarget, FailoverTrigger, FallbackField, FallbackTrigger, FileModelKnowledgeStore, FileModelKnowledgeStoreOptions, FileTranscriptStore, FinishInfo, Gate, GateAudit, type GateRecord, GitWorktreeProvider, GitWorktreeProviderOptions, GraftBoot, HashVersion, HookVerdict, INBOX_PROPOSAL_TTL_DAYS, IdentityInput, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, InvalidResolutionError, InvocationRole, type IsolationProvider, type IsolationSpec, Issue$1 as Issue, JournalCompatSubCode, JournalCompatibilityError, JournalEntry, JournalMatcher, JournalMissError, JournalOperation, JournalOrderViolation, JournalSerializationHook, type JournalStore, type Json, JsonSchema, JsonlFileStore, KB_ACTIVE_CLAIMS_CAP, KB_CARD_RENDER_BUDGET_CHARS, type KbProposal, type KbProposalTrigger, KeyDeriver, KeyRing, KeyedLimiter, KnowledgeCasError, type KnowledgeSnapshot, LARGE_VALUE_WARN_BYTES, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LINEAGE_SIG_VERSION, LadderSpec, type LeasableStore, type Lease, LeaseHeldError, Ledger, LineageCounters, LineageIndex, LineageRef, LineageRelation, LineageStats, LogicalTaskId, MASKED_SECRET, MAX_DEPTH_CEILING, MatchResult, McpConfig, McpToolSource, MechanicalGateProfile, MechanicalGateVerdict, type MetaLookupStore, type ModelCaps, ModelChoice, type ModelClaim, ModelEpochInputs, type ModelKnowledgeHandle, type ModelKnowledgeStore, ModelListConstraint, ModelRef, ModelRetry, ModelSpec, Msg, NoProgressDetector, NodeId, NodeLinkValue, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OnEscalation, OperationDisposition, OrchestrateOptions, OrchestratorBudgetSpec, OrchestratorCapConfigError, OrchestratorExtension, OrchestratorExtensionIO, OrchestratorRuntime, Out, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, Part, PendingExternal, PendingToolTurn, PermissionConfig, PermissionGate, PermissionHook, PermissionPreset, PermissionRule, PermissionVerdict, PhaseTarget, PipelineCollected, PipelineOpts, PlanInvariantError, PriceTable, PricedUsage, type Pricing, type PricingTier, type ProviderAdapter, QualityFloors, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RandIdentityInput, RandPayload, RefEntryAppender, RefEntryClassification, RefusalInfo, ReplayDisposition, ReplayMode, ReplayPlanHashMismatch, Replayer, ResolutionArbiter, ResolutionAttempt, ResolutionBy, ResolutionFold, ResolutionLayer, ResolutionOutcome, ResolutionPayload, ResolvedInvocation, ResolvedToolset, ResumeHandle, ResumeOptions, ResumePreview, ResumeReport, RetryClass, RetryPolicy, ReuseConfig, RiskRuleValue, Role, RulvarError, RulvarErrorCode, RunAgentOptions, RunBudget, RunEventSink, type RunFilter, RunHandle, RunInternals, type RunMeta, RunOptions, RunOutcome, RunProfile, RunStatus, RuntimeEventSink, SANDBOX_AGENT_OPT_KEYS, SPAWN_AGENT_SCHEMA, SandboxBridge, SandboxBridgeOptions, SandboxError, SandboxHostToWorker, SandboxMethod, SandboxWorkerToHost, SchemaPair, SchemaSpec, SchemaValidationResult, ScopeSegment, ScriptRejected, ScriptRunner, ScrubNote, Semaphore, SerializationHook, Settled, ShellPatternRules, ShellSegment, ShellVerdict, SinglePhaseAppend, SpanMinter, SpanRegistry, SpawnAdmissionValue, SpawnAgentParams, SpawnKey, SpawnLineage, SpawnLineageOpt, SpawnOrigin, SpawnRecord, Spend, Stage, type StandardJSONSchemaV1, type StandardSchemaV1, StepIdentityInput, StructuredOutputTier, SuspendedAppend, SuspensionState, TOOL_NAME_PATTERN, type TaskClass, TaskDigest, TaskSpec, TerminalPatch, TerminationAccount, TerminationAccountSnapshot, TerminationDeniedValue, TerminationDeniedWriter, TerminationInitValue, TerminationLimits, TerminationResource, ToolCallRequest, ToolChoice, type ToolContext, ToolContextSeed, ToolContract, type ToolDef, type ToolEvents, type ToolExecutor, ToolInit, type ToolRisk, ToolRuntime, type ToolSource, type ToolSourceSession, ToolsOption, TranscriptSerializationHook, type TranscriptStore, TriggerClass, TtlState, Usage, UsageLimits, UsageSlice, VerifiedRecommendation, WAIT_FOR_EVENTS_SCHEMA, WAIT_FOR_EVENTS_TOOL_NAME, WAKE_SUMMARY_RENDER_BUDGET_CHARS, WakeBudgetBlock, WakeDigest, WakeTrigger, WireError, Workflow, WorkflowCallOpts, type WorkflowEvent, type WorkflowEventBody, WorkflowRegistry, admissionReserveUsd, affordableOutputTokens, agentErrorFromWire, agentErrorToWire, agentResultWire, 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, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hasMetaLookup, hashRunArgs, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, metaMatchesFilter, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, priceEntryUsage, priceUsdOf, profileCard, profileRegistrySnapshotHash, projectHistory, projectIdentity, projectToJsonSchema, proposalStatement, providerOf, readRunMeta, readTerminationInit, registryKeyRing, remeasureQueue, replayDisposition, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, sanitizeTerminalText, sanitizeTokenCount, sanitizeUsage, sanitizeUsageDelta, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, snapshotUsage, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, usageViolations, validateEditorialCommit, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateRetryPolicy, validateSchemaSpec, validateTerminationLimits, validateUsageLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
6901
+ export { AWAIT_SCHEMA, AbandonAttempt, AbandonFold, AbandonPayload, AbandonedSpendView, AbortClass, type AdaptiveEvents, AdmissionController, AdmissionDecision, AdmissionRejectedError, AdmissionStatsBefore, AdmitLineage, AdmitRejectReason, AdmitSpec, AdmitVerdict, AgentCallError, AgentError, type AgentEvents, AgentIdentityInput, AgentOpts, AgentProfile, AgentProfilePermissions, AgentResult, AgentResultMeta, AgentStatus, ApproachSignatureInputs, ApprovalDecision, ApprovalIdentityInput, Artifact, AttemptOutcomeClass, BUDGET_ABORT_REASON, BaseAppend, BriefOpts, BudgetAccountView, BudgetDefaults, BudgetExhaustedError, BudgetExhaustionDiagnostics, BudgetHooks, BudgetReserve, type Bytes, CANCEL_AGENT_SCHEMA, CHECKPOINT_FORMAT_V1, CLAIM_STATEMENT_MAX_CHARS, CLAIM_TTL_DAYS, COMPACTION_SUMMARY_PREFIX, CURRENT_HASH_VERSION, CacheHint, CacheTtl, CanUseTool, CanonicalId, CanonicalIdentity, CanonicalLadderSpec, CanonicalModelSpec, ChatEvent, ChatRequest, CheckpointState, ChildIdentityInput, type ClaimClass, type ClaimOp, type ClaimStatus, ClaimValidationOptions, CollectOpts, CollectedTurn, CompactionConfig, CompiledPermissionChain, CompiledWorkflow, ConfigError, type CoreEvents, CostAttribution, CostAttributionFacts, CostReport, CreateEngineOptions, Ctx, 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, DebitResult, DeclaredLadder, DedupIndex, DedupNote, DerivedKey, DeriverRegistry, DispositionRule, DispositionTable, DonorCandidate, DonorRef, DroppedItem, EMIT_RESULT_TOOL, EMPTY_SCHEMA_HASH, EMPTY_TOOLSET_HASH, ESCALATE_TOOL_NAME, ESCALATION_REPORT_SCHEMA, ESCALATION_REQUEST_SCHEMA, EVENT_SEGMENT_STRIDE, EffectiveUsageLimits, Effort, Engine, EngineDefaults, EntryKind, EntryRef, EntryStatus, ErrorClass, ErrorCode, ErrorPolicy, EscalatedResult, EscalationDecision, EscalationDecisionAbortedError, EscalationDigest, EscalationKind, EscalationLimits, EscalationOptions, EscalationReport, EscalationRequest, EventBus, type EvidenceRef, ExtensionAppendInput, ExtensionDispatchSpec, ExternalIdentityInput, ExternalRegistry, ExtractNecessityInput, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FailRunError, FailoverTarget, FailoverTrigger, FallbackField, FallbackTrigger, FileModelKnowledgeStore, FileModelKnowledgeStoreOptions, FileTranscriptStore, FinishInfo, Gate, GateAudit, type GateRecord, GitWorktreeProvider, GitWorktreeProviderOptions, GraftBoot, HashVersion, HookVerdict, INBOX_PROPOSAL_TTL_DAYS, IdentityInput, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, InvalidResolutionError, InvocationRole, type IsolationProvider, type IsolationSpec, Issue$1 as Issue, JournalCompatSubCode, JournalCompatibilityError, JournalEntry, JournalMatcher, JournalMissError, JournalOperation, JournalOrderViolation, JournalSerializationHook, type JournalStore, type Json, JsonSchema, JsonlFileStore, KB_ACTIVE_CLAIMS_CAP, KB_CARD_RENDER_BUDGET_CHARS, type KbProposal, type KbProposalTrigger, KeyDeriver, KeyRing, KeyedLimiter, KnowledgeCasError, type KnowledgeSnapshot, LARGE_VALUE_WARN_BYTES, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LINEAGE_SIG_VERSION, LadderSpec, type LeasableStore, type Lease, LeaseHeldError, Ledger, LineageCounters, LineageIndex, LineageRef, LineageRelation, LineageStats, LogicalTaskId, MASKED_SECRET, MAX_DEPTH_CEILING, MatchResult, McpConfig, McpToolSource, MechanicalGateProfile, MechanicalGateVerdict, type MetaLookupStore, type ModelCaps, ModelChoice, type ModelClaim, ModelEpochInputs, type ModelKnowledgeHandle, type ModelKnowledgeStore, ModelListConstraint, ModelRef, ModelRetry, ModelSpec, Msg, NoProgressDetector, NodeId, NodeLinkValue, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OnEscalation, OperationDisposition, OrchestrateOptions, OrchestratorBudgetSpec, OrchestratorCapConfigError, OrchestratorExtension, OrchestratorExtensionIO, OrchestratorRuntime, Out, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, Part, PendingExternal, PendingToolTurn, PermissionConfig, PermissionGate, PermissionHook, PermissionPreset, PermissionRule, PermissionVerdict, PhaseTarget, PipelineCollected, PipelineOpts, PlanInvariantError, PriceTable, PricedUsage, type Pricing, type PricingTier, type ProviderAdapter, QualityFloors, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RandIdentityInput, RandPayload, RefEntryAppender, RefEntryClassification, RefusalInfo, ReplayDisposition, ReplayMode, ReplayPlanHashMismatch, Replayer, ResolutionArbiter, ResolutionAttempt, ResolutionBy, ResolutionFold, ResolutionLayer, ResolutionOutcome, ResolutionPayload, ResolvedInvocation, ResolvedToolset, ResumeHandle, ResumeOptions, ResumePreview, ResumeReport, RetryClass, RetryPolicy, ReuseConfig, RiskRuleValue, Role, RulvarError, RulvarErrorCode, RunAgentOptions, RunBudget, RunEventSink, type RunFilter, RunHandle, RunInternals, type RunMeta, RunOptions, RunOutcome, RunProfile, RunStatus, RuntimeEventSink, SANDBOX_AGENT_OPT_KEYS, SPAWN_AGENT_SCHEMA, SandboxBridge, SandboxBridgeOptions, SandboxError, SandboxHostToWorker, SandboxMethod, SandboxWorkerToHost, SchemaPair, SchemaSpec, SchemaValidationResult, ScopeSegment, ScriptRejected, ScriptRunner, ScrubNote, Semaphore, SerializationHook, Settled, ShellPatternRules, ShellSegment, ShellVerdict, SinglePhaseAppend, SpanMinter, SpanRegistry, SpawnAdmissionValue, SpawnAgentParams, SpawnKey, SpawnLineage, SpawnLineageOpt, SpawnOrigin, SpawnRecord, Spend, Stage, type StandardJSONSchemaV1, type StandardSchemaV1, StepIdentityInput, StructuredOutputTier, SuspendedAppend, SuspensionState, TOOL_NAME_PATTERN, type TaskClass, TaskDigest, TaskSpec, TerminalPatch, TerminationAccount, TerminationAccountSnapshot, TerminationDeniedValue, TerminationDeniedWriter, TerminationInitValue, TerminationLimits, TerminationResource, ToolCallRequest, ToolChoice, type ToolContext, ToolContextSeed, ToolContract, type ToolDef, type ToolEvents, type ToolExecutor, ToolInit, type ToolRisk, ToolRuntime, type ToolSource, type ToolSourceSession, ToolsOption, TranscriptSerializationHook, type TranscriptStore, TriggerClass, TtlState, Usage, UsageLimits, UsageSlice, VerifiedRecommendation, WAIT_FOR_EVENTS_SCHEMA, WAIT_FOR_EVENTS_TOOL_NAME, WAKE_SUMMARY_RENDER_BUDGET_CHARS, WakeBudgetBlock, WakeDigest, WakeTrigger, WireError, Workflow, WorkflowCallOpts, type WorkflowEvent, type WorkflowEventBody, WorkflowRegistry, admissionReserveUsd, affordableOutputTokens, agentErrorFromWire, agentErrorToWire, agentResultWire, 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, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hasMetaLookup, hashRunArgs, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, metaMatchesFilter, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, priceEntryUsage, priceUsdOf, profileCard, profileRegistrySnapshotHash, projectHistory, projectIdentity, projectToJsonSchema, proposalStatement, providerOf, readRunMeta, readTerminationInit, registryKeyRing, remeasureQueue, replayDisposition, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, sanitizeTerminalText, sanitizeTokenCount, sanitizeUsage, sanitizeUsageDelta, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, snapshotUsage, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, usageViolations, validateEditorialCommit, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateRetryPolicy, validateSchemaSpec, validateTerminationLimits, validateUsageLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createHash, getRandomValues, randomUUID } from "node:crypto";
2
2
  import { appendFileSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
3
- import { dirname, join, resolve } from "node:path";
3
+ import { dirname, join, resolve, sep } from "node:path";
4
4
  import { Client } from "@modelcontextprotocol/sdk/client";
5
5
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
6
6
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
@@ -206,6 +206,25 @@ var BudgetExhaustedError = class extends RulvarError {
206
206
  }
207
207
  };
208
208
  /**
209
+ * A declared fail-run policy engaged and closed the run as a failure
210
+ * (v1.35.0 review P2-1): `budget.atCap: 'fail-run'` after the journaled
211
+ * orchestrator cap decision, or `guards.fallback: 'fail-run'` after the
212
+ * journaled guard verdict. The run outcome is 'error' with this code;
213
+ * `data.source` names the policy ('orchestrator_budget_cap' or
214
+ * 'plan_guards') and `data` carries the decision entry reference, so the
215
+ * outcome is a pure roll forward of the journal on resume: no second
216
+ * decision, no model call, no spend.
217
+ */
218
+ var FailRunError = class extends RulvarError {
219
+ code = "fail_run";
220
+ constructor(message, opts) {
221
+ super(message, {
222
+ retryable: false,
223
+ ...opts
224
+ });
225
+ }
226
+ };
227
+ /**
209
228
  * A structural admission rejection (maxDepth, maxChildrenPerNode,
210
229
  * maxTotalSpawns) from the AdmissionController (M6-T06). The rejection verdict is embedded in
211
230
  * the carrying spawn-admission decision entry and replays identically;
@@ -2179,6 +2198,51 @@ function modelEpochOf(inputs) {
2179
2198
  return Object.keys(epoch).length === 0 ? void 0 : epoch;
2180
2199
  }
2181
2200
  //#endregion
2201
+ //#region src/l0/validate-numbers.ts
2202
+ /**
2203
+ * Shared numeric option validators (v1.34.0 review P2-3). Every public
2204
+ * numeric knob that shapes admission, limits, concurrency, or timers is
2205
+ * validated with these helpers at its intake boundary, so a malformed
2206
+ * value (NaN, Infinity, a negative, a fraction where an integer is
2207
+ * required) fails as a typed ConfigError before any journal entry,
2208
+ * worker, or provider dispatch. NaN needs dedicated handling because
2209
+ * every comparison with it is false: a hand-written range check in the
2210
+ * rejecting polarity (`value < min || value > max`) silently admits it.
2211
+ */
2212
+ /**
2213
+ * The Node timer ceiling: setTimeout clamps any longer delay to 1 ms, so
2214
+ * a naive far-future timer fires immediately (v1.34.0 review P2-2).
2215
+ * Relative timer options are validated against this bound; absolute
2216
+ * deadlines use the sliced timer in long-timer.ts instead.
2217
+ */
2218
+ const MAX_TIMER_DELAY_MS = 2147483647;
2219
+ function refuse(site, requirement, value) {
2220
+ throw new ConfigError(`${site} must be ${requirement}; got ${String(value)}`);
2221
+ }
2222
+ /** An integer >= 1 (counts, caps, and depths). */
2223
+ function requirePositiveInteger(value, site) {
2224
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1) refuse(site, "a positive integer", value);
2225
+ }
2226
+ /** An integer >= 0 (caps where zero means "none allowed"). */
2227
+ function requireNonNegativeInteger(value, site) {
2228
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) refuse(site, "a nonnegative integer", value);
2229
+ }
2230
+ /** A finite number >= 0 (USD amounts and reserves). */
2231
+ function requireNonNegativeNumber(value, site) {
2232
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) refuse(site, "a finite nonnegative number", value);
2233
+ }
2234
+ /** A finite fraction in (0, 1]. */
2235
+ function requireFraction(value, site) {
2236
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0 || value > 1) refuse(site, "a fraction in (0, 1]", value);
2237
+ }
2238
+ /**
2239
+ * A relative delay handed to setTimeout as-is: an integer within the
2240
+ * Node timer maximum, mirroring validateRetryPolicy's bound.
2241
+ */
2242
+ function requireTimerDelayMs(value, site) {
2243
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > 2147483647) refuse(site, "an integer between 1 and 2147483647 ms (the Node timer maximum)", value);
2244
+ }
2245
+ //#endregion
2182
2246
  //#region src/knowledge/file-store.ts
2183
2247
  /**
2184
2248
  * FileModelKnowledgeStore (M10-T01): the default ModelKnowledgeStore, a
@@ -2238,6 +2302,79 @@ function applyClaimOps(claims, ops) {
2238
2302
  }
2239
2303
  return next;
2240
2304
  }
2305
+ /** A lowercase sha256 digest: 64 hex characters. */
2306
+ const HASH_PATTERN = /^[0-9a-f]{64}$/;
2307
+ const CLAIM_STATUSES = /* @__PURE__ */ new Set([
2308
+ "active",
2309
+ "stale",
2310
+ "superseded",
2311
+ "archived"
2312
+ ]);
2313
+ /**
2314
+ * Structural issues of one PERSISTED claim (empty = sound). Distinct from
2315
+ * the editorial commit validator (claims.ts): a persisted snapshot
2316
+ * legitimately holds non-active statuses (stale, superseded, archived) and
2317
+ * carries no gate, so only shape and vocabulary are checked here. This is
2318
+ * the boundary that keeps a null or partial claim from reaching the card
2319
+ * render, where `claim.status` would throw an untyped TypeError (v1.36.0
2320
+ * review P2-6).
2321
+ */
2322
+ function persistedClaimIssues(value, path) {
2323
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return [`${path}: expected a claim object`];
2324
+ const claim = value;
2325
+ const issues = [];
2326
+ if (typeof claim.id !== "string" || claim.id.length === 0) issues.push(`${path}.id: expected a non-empty string`);
2327
+ const subject = claim.subject;
2328
+ if (subject === null || typeof subject !== "object") issues.push(`${path}.subject: expected an object`);
2329
+ else if (typeof subject.model !== "string" || !subject.model.includes(":")) issues.push(`${path}.subject.model: expected a 'provider:model' string`);
2330
+ if (typeof claim.taskClass !== "string" || claim.taskClass.length === 0) issues.push(`${path}.taskClass: expected a non-empty string`);
2331
+ if (claim.polarity !== "strength" && claim.polarity !== "weakness") issues.push(`${path}.polarity: expected 'strength' or 'weakness'`);
2332
+ if (typeof claim.statement !== "string" || claim.statement.length === 0) issues.push(`${path}.statement: expected a non-empty string`);
2333
+ if (claim.class !== "eval-measured" && claim.class !== "human-editorial") issues.push(`${path}.class: expected 'eval-measured' or 'human-editorial'`);
2334
+ if (typeof claim.status !== "string" || !CLAIM_STATUSES.has(claim.status)) issues.push(`${path}.status: expected active, stale, superseded, or archived`);
2335
+ if (!Array.isArray(claim.evidence) || claim.evidence.length === 0) issues.push(`${path}.evidence: expected a non-empty array`);
2336
+ if (claim.confidence !== "high" && claim.confidence !== "medium" && claim.confidence !== "low") issues.push(`${path}.confidence: expected 'high', 'medium', or 'low'`);
2337
+ if (typeof claim.observedAt !== "string" || Number.isNaN(Date.parse(claim.observedAt))) issues.push(`${path}.observedAt: expected an ISO date`);
2338
+ if (typeof claim.expiresAt !== "string" || Number.isNaN(Date.parse(claim.expiresAt))) issues.push(`${path}.expiresAt: expected an ISO date`);
2339
+ const author = claim.author;
2340
+ if (author === null || typeof author !== "object") issues.push(`${path}.author: expected an object`);
2341
+ else {
2342
+ if (author.kind !== "eval-pipeline" && author.kind !== "human") issues.push(`${path}.author.kind: expected 'eval-pipeline' or 'human'`);
2343
+ if (typeof author.id !== "string" || author.id.length === 0) issues.push(`${path}.author.id: expected a non-empty string`);
2344
+ }
2345
+ return issues;
2346
+ }
2347
+ /**
2348
+ * The single read boundary of the store (v1.36.0 review P2-6). A persisted
2349
+ * snapshot must hold a nonnegative integer version, a lowercase sha256
2350
+ * hash, structurally sound claims, and a hash that MATCHES its claims: the
2351
+ * KnowledgeSnapshot contract promises the hash is the deterministic
2352
+ * content hash of the claims, so a file edited without rehashing (a forged
2353
+ * version or hash, a torn write) is refused with a typed ConfigError
2354
+ * instead of flowing on to forge the audit trail or crash the render.
2355
+ */
2356
+ function validateKnowledgeSnapshot(parsed, path) {
2357
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new ConfigError(`knowledge store file does not hold a KnowledgeSnapshot: ${path}`);
2358
+ const snapshot = parsed;
2359
+ const issues = [];
2360
+ const version = snapshot.version;
2361
+ if (typeof version !== "number" || !Number.isInteger(version) || version < 0) issues.push(`version: expected a nonnegative integer; got ${String(version)}`);
2362
+ const hash = snapshot.hash;
2363
+ if (typeof hash !== "string" || !HASH_PATTERN.test(hash)) issues.push("hash: expected a lowercase sha256 digest of 64 hex characters");
2364
+ if (!Array.isArray(snapshot.claims)) issues.push("claims: expected an array");
2365
+ else snapshot.claims.forEach((claim, index) => {
2366
+ issues.push(...persistedClaimIssues(claim, `claims[${String(index)}]`));
2367
+ });
2368
+ if (issues.length > 0) throw new ConfigError(`knowledge store file is not a valid KnowledgeSnapshot (${path}):\n- ${issues.join("\n- ")}`);
2369
+ const claims = snapshot.claims;
2370
+ const recomputed = knowledgeHash(claims);
2371
+ if (hash !== recomputed) throw new ConfigError(`knowledge store hash does not match its claims (${path}): stored ${String(hash)}, computed ${recomputed}; the file was edited without rehashing`);
2372
+ return {
2373
+ version,
2374
+ hash,
2375
+ claims
2376
+ };
2377
+ }
2241
2378
  var FileModelKnowledgeStore = class {
2242
2379
  path;
2243
2380
  activeClaimsCap;
@@ -2245,6 +2382,7 @@ var FileModelKnowledgeStore = class {
2245
2382
  queue = Promise.resolve();
2246
2383
  constructor(options) {
2247
2384
  this.path = resolve(options?.path ?? "./rulvar.models.json");
2385
+ if (options?.activeClaimsCap !== void 0) requireNonNegativeInteger(options.activeClaimsCap, "FileModelKnowledgeStore activeClaimsCap");
2248
2386
  this.activeClaimsCap = options?.activeClaimsCap;
2249
2387
  }
2250
2388
  read() {
@@ -2265,13 +2403,7 @@ var FileModelKnowledgeStore = class {
2265
2403
  } catch (cause) {
2266
2404
  throw new ConfigError(`knowledge store file is not valid JSON: ${this.path}`, { cause });
2267
2405
  }
2268
- const snapshot = parsed;
2269
- if (snapshot === null || typeof snapshot.version !== "number" || typeof snapshot.hash !== "string" || !Array.isArray(snapshot.claims)) throw new ConfigError(`knowledge store file does not hold a KnowledgeSnapshot: ${this.path}`);
2270
- return {
2271
- version: snapshot.version,
2272
- hash: snapshot.hash,
2273
- claims: snapshot.claims
2274
- };
2406
+ return validateKnowledgeSnapshot(parsed, this.path);
2275
2407
  }
2276
2408
  async current() {
2277
2409
  return this.read();
@@ -2301,6 +2433,19 @@ var FileModelKnowledgeStore = class {
2301
2433
  return result;
2302
2434
  }
2303
2435
  };
2436
+ /**
2437
+ * Truncates `raw` to at most `budgetChars` characters. A string within
2438
+ * the budget returns unchanged; a longer one is cut to
2439
+ * `budgetChars - 3` characters plus the marker, and budgets below the
2440
+ * marker length fall back to a bare slice so the bound still holds.
2441
+ * The measure is deterministic characters (UTF-16 units): identical
2442
+ * live and on replay, no tokenizer dependence.
2443
+ */
2444
+ function truncateToBudget(raw, budgetChars) {
2445
+ if (raw.length <= budgetChars) return raw;
2446
+ if (budgetChars < 3) return raw.slice(0, Math.max(0, budgetChars));
2447
+ return `${raw.slice(0, budgetChars - 3)}...`;
2448
+ }
2304
2449
  //#endregion
2305
2450
  //#region src/model/floors.ts
2306
2451
  /**
@@ -2442,10 +2587,15 @@ function compileVerifiedLayer(claims, ladders) {
2442
2587
  /**
2443
2588
  * The deterministic card render. Pure: same filtered
2444
2589
  * claims and ladders give byte-identical text. The render budget is
2445
- * 4096 chars; over it, the OLDEST-observed notes
2446
- * withhold first behind an explicit marker.
2590
+ * 4096 chars by default; over it, the OLDEST-observed notes withhold
2591
+ * first behind an explicit marker, and the budget is a HARD upper bound
2592
+ * of the returned string: a card whose mandatory sections alone exceed
2593
+ * it is truncated with the shared marker (v1.35.0 review P2-5: a budget
2594
+ * of 32 used to return the full 136-char header form). budgetChars is a
2595
+ * nonnegative integer, validated as a ConfigError.
2447
2596
  */
2448
2597
  function modelKnowledgeCard(claims, ladders, options) {
2598
+ if (options?.budgetChars !== void 0) requireNonNegativeInteger(options.budgetChars, "modelKnowledgeCard budgetChars");
2449
2599
  const budget = options?.budgetChars ?? 4096;
2450
2600
  const lines = ["Model knowledge card (tier-relative; advisory within declared ladders and hard floors)."];
2451
2601
  const verified = compileVerifiedLayer(claims, ladders);
@@ -2494,7 +2644,7 @@ function modelKnowledgeCard(claims, ladders, options) {
2494
2644
  shown -= 1;
2495
2645
  text = render(shown);
2496
2646
  }
2497
- return text;
2647
+ return truncateToBudget(text, budget);
2498
2648
  }
2499
2649
  //#endregion
2500
2650
  //#region src/tools/presets.ts
@@ -3047,6 +3197,7 @@ var GitWorktreeProvider = class {
3047
3197
  constructor(options) {
3048
3198
  this.repoRoot = options?.repoRoot ?? process.cwd();
3049
3199
  this.keepOnError = options?.keepOnError ?? false;
3200
+ if (options?.maxPinnedWorktrees !== void 0) requireNonNegativeInteger(options.maxPinnedWorktrees, "GitWorktreeProvider maxPinnedWorktrees");
3050
3201
  this.maxPinned = options?.maxPinnedWorktrees ?? 4;
3051
3202
  this.onWarn = options?.onWarn ?? ((msg) => process.emitWarning(msg, {
3052
3203
  code: "RULVAR_WORKTREE",
@@ -5836,6 +5987,24 @@ var Replayer = class {
5836
5987
  * Full contract: https://docs.rulvar.com/guide/durability
5837
5988
  */
5838
5989
  /**
5990
+ * The rejection carrier of an aborted flavor B decision wait (v1.35.0
5991
+ * review P1): the parked `awaitDecision` observes the branch/run
5992
+ * AbortSignal, releases its held activity, removes its waiter, and
5993
+ * rejects with this class so cancel, host abort, the run deadline, and
5994
+ * failed sibling aborts all settle the run in bounded time.
5995
+ * Deliberately not a RulvarError: the abort is cancellation intent, not
5996
+ * a registry failure class; the suspension entry stays OPEN, so a later
5997
+ * resume parks the decision again and the durable deadline still applies.
5998
+ */
5999
+ var EscalationDecisionAbortedError = class extends Error {
6000
+ entryRef;
6001
+ constructor(message, entryRef) {
6002
+ super(message);
6003
+ this.name = "EscalationDecisionAbortedError";
6004
+ this.entryRef = entryRef;
6005
+ }
6006
+ };
6007
+ /**
5839
6008
  * Normalizes a resolution value into an ApprovalDecision. Anything that
5840
6009
  * is not an explicit allow is a deny: an approval never fails open.
5841
6010
  */
@@ -6112,8 +6281,33 @@ var ExternalRegistry = class ExternalRegistry {
6112
6281
  },
6113
6282
  deadlineAt: options.deadlineAt
6114
6283
  });
6115
- return new Promise((resolve) => {
6284
+ return new Promise((resolve, reject) => {
6285
+ const signal = options.signal;
6286
+ const abortError = () => {
6287
+ const reason = signal?.reason;
6288
+ const detail = reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "aborted";
6289
+ return new EscalationDecisionAbortedError(`flavor B escalation decision wait aborted (entry ${String(entry.seq)}): ${detail}`, entry.seq);
6290
+ };
6291
+ if (signal?.aborted === true) {
6292
+ reject(abortError());
6293
+ return;
6294
+ }
6116
6295
  const exitActivity = this.enter();
6296
+ let settled = false;
6297
+ let detachAbort;
6298
+ /** Exactly one terminal: activity exits once, the listener detaches once. */
6299
+ const settle = () => {
6300
+ if (settled) return false;
6301
+ settled = true;
6302
+ exitActivity();
6303
+ detachAbort?.();
6304
+ return true;
6305
+ };
6306
+ const onAbort = () => {
6307
+ if (!settle()) return;
6308
+ this.waiters.delete(entry.seq);
6309
+ if (!this.closedFlag) reject(abortError());
6310
+ };
6117
6311
  const waiter = {
6118
6312
  kind: "decision",
6119
6313
  key: ExternalRegistry.approvalKey(entry.seq),
@@ -6121,7 +6315,7 @@ var ExternalRegistry = class ExternalRegistry {
6121
6315
  entryRef: entry.seq,
6122
6316
  prompt: `decide escalation of '${options.toolName}'`,
6123
6317
  resolve: (value) => {
6124
- exitActivity();
6318
+ if (!settle()) return;
6125
6319
  resolve({
6126
6320
  value,
6127
6321
  entryRef: entry.seq
@@ -6129,6 +6323,12 @@ var ExternalRegistry = class ExternalRegistry {
6129
6323
  }
6130
6324
  };
6131
6325
  this.waiters.set(entry.seq, waiter);
6326
+ if (signal !== void 0) {
6327
+ signal.addEventListener("abort", onAbort, { once: true });
6328
+ detachAbort = () => {
6329
+ signal.removeEventListener("abort", onAbort);
6330
+ };
6331
+ }
6132
6332
  options.onPending?.(entry, replayed);
6133
6333
  });
6134
6334
  }
@@ -6445,9 +6645,16 @@ const TRANSCRIPT_SUFFIX = ".bin";
6445
6645
  /**
6446
6646
  * File-backed TranscriptStore (M6-T02): blobs (transcripts, checkpoints,
6447
6647
  * persisted CompiledWorkflow sources) as one file per ref under `dir`,
6448
- * so compiled runs resume across processes. Refs follow
6449
- * the `<runId>/<name>` convention; each path segment is checked
6450
- * filesystem-safe and nested segments become directories.
6648
+ * so compiled runs resume across processes. Refs follow the
6649
+ * `<runId>/<name>` convention; nested segments become directories.
6650
+ *
6651
+ * Every ref is contained under `dir` (v1.36.0 review SEC-P1): each
6652
+ * segment must match `[A-Za-z0-9._-]` and be neither empty, '.', nor
6653
+ * '..', and the resolved path must stay under the resolved root. A '..'
6654
+ * segment used to pass the per-segment alphabet (dots are in it) and, via
6655
+ * `join`, escape the root; a caller passing an untrusted ref (or an
6656
+ * untrusted runId, which prefixes checkpoint and workflow-source refs)
6657
+ * could read, write, or delete `.bin` files outside `dir`.
6451
6658
  */
6452
6659
  var FileTranscriptStore = class {
6453
6660
  dir;
@@ -6457,9 +6664,13 @@ var FileTranscriptStore = class {
6457
6664
  }
6458
6665
  blobPath(ref) {
6459
6666
  const segments = ref.split("/");
6460
- for (const segment of segments) if (!/^[A-Za-z0-9._-]+$/.test(segment)) throw new JournalOrderViolation(`FileTranscriptStore: ref segment '${segment}' is not filesystem-safe`);
6667
+ for (const segment of segments) if (segment === "" || segment === "." || segment === ".." || !/^[A-Za-z0-9._-]+$/.test(segment)) throw new JournalOrderViolation(`FileTranscriptStore: ref segment '${segment}' is not filesystem-safe`);
6461
6668
  const name = segments.pop() ?? "";
6462
- return join(this.dir, ...segments, `${name}${TRANSCRIPT_SUFFIX}`);
6669
+ const path = join(this.dir, ...segments, `${name}${TRANSCRIPT_SUFFIX}`);
6670
+ const root = resolve(this.dir);
6671
+ const resolved = resolve(path);
6672
+ if (resolved !== root && !resolved.startsWith(`${root}${sep}`)) throw new JournalOrderViolation(`FileTranscriptStore: ref '${ref}' resolves outside the configured root`);
6673
+ return path;
6463
6674
  }
6464
6675
  async put(ref, blob) {
6465
6676
  const path = this.blobPath(ref);
@@ -6477,6 +6688,7 @@ var FileTranscriptStore = class {
6477
6688
  }
6478
6689
  }
6479
6690
  async list(runId) {
6691
+ if (runId === "." || runId === "..") throw new JournalOrderViolation(`FileTranscriptStore: runId '${runId}' is not filesystem-safe`);
6480
6692
  const root = join(this.dir, safeName(runId));
6481
6693
  const refs = [];
6482
6694
  const walk = (dir, prefix) => {
@@ -6758,51 +6970,6 @@ function tierWithinCaps(tier, caps) {
6758
6970
  return TIER_ORDER[tier] <= TIER_ORDER[caps.structuredOutput];
6759
6971
  }
6760
6972
  //#endregion
6761
- //#region src/l0/validate-numbers.ts
6762
- /**
6763
- * Shared numeric option validators (v1.34.0 review P2-3). Every public
6764
- * numeric knob that shapes admission, limits, concurrency, or timers is
6765
- * validated with these helpers at its intake boundary, so a malformed
6766
- * value (NaN, Infinity, a negative, a fraction where an integer is
6767
- * required) fails as a typed ConfigError before any journal entry,
6768
- * worker, or provider dispatch. NaN needs dedicated handling because
6769
- * every comparison with it is false: a hand-written range check in the
6770
- * rejecting polarity (`value < min || value > max`) silently admits it.
6771
- */
6772
- /**
6773
- * The Node timer ceiling: setTimeout clamps any longer delay to 1 ms, so
6774
- * a naive far-future timer fires immediately (v1.34.0 review P2-2).
6775
- * Relative timer options are validated against this bound; absolute
6776
- * deadlines use the sliced timer in long-timer.ts instead.
6777
- */
6778
- const MAX_TIMER_DELAY_MS = 2147483647;
6779
- function refuse(site, requirement, value) {
6780
- throw new ConfigError(`${site} must be ${requirement}; got ${String(value)}`);
6781
- }
6782
- /** An integer >= 1 (counts, caps, and depths). */
6783
- function requirePositiveInteger(value, site) {
6784
- if (typeof value !== "number" || !Number.isInteger(value) || value < 1) refuse(site, "a positive integer", value);
6785
- }
6786
- /** An integer >= 0 (caps where zero means "none allowed"). */
6787
- function requireNonNegativeInteger(value, site) {
6788
- if (typeof value !== "number" || !Number.isInteger(value) || value < 0) refuse(site, "a nonnegative integer", value);
6789
- }
6790
- /** A finite number >= 0 (USD amounts and reserves). */
6791
- function requireNonNegativeNumber(value, site) {
6792
- if (typeof value !== "number" || !Number.isFinite(value) || value < 0) refuse(site, "a finite nonnegative number", value);
6793
- }
6794
- /** A finite fraction in (0, 1]. */
6795
- function requireFraction(value, site) {
6796
- if (typeof value !== "number" || !Number.isFinite(value) || value <= 0 || value > 1) refuse(site, "a fraction in (0, 1]", value);
6797
- }
6798
- /**
6799
- * A relative delay handed to setTimeout as-is: an integer within the
6800
- * Node timer maximum, mirroring validateRetryPolicy's bound.
6801
- */
6802
- function requireTimerDelayMs(value, site) {
6803
- if (typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > 2147483647) refuse(site, "an integer between 1 and 2147483647 ms (the Node timer maximum)", value);
6804
- }
6805
- //#endregion
6806
6973
  //#region src/engine/scheduler.ts
6807
6974
  /**
6808
6975
  * Scheduler and concurrency (M1-T08): the per-run semaphore with a FIFO
@@ -10413,8 +10580,7 @@ const WAKE_SUMMARY_RENDER_BUDGET_CHARS = 400;
10413
10580
  * spawn ordinal; the LLM distillation upgrade is M7 territory).
10414
10581
  */
10415
10582
  function summarizeOutput(result) {
10416
- const raw = result.status === "ok" ? typeof result.output === "string" ? result.output : JSON.stringify(result.output ?? null) : result.errorMessage ?? `terminal status ${result.status}`;
10417
- return raw.length <= 400 ? raw : `${raw.slice(0, 400)}...`;
10583
+ return truncateToBudget(result.status === "ok" ? typeof result.output === "string" ? result.output : JSON.stringify(result.output ?? null) : result.errorMessage ?? `terminal status ${result.status}`, 400);
10418
10584
  }
10419
10585
  /** Folds one settled child into its digest (spawn-ordinal ordering is the caller's). */
10420
10586
  function digestOf(record, result) {
@@ -11034,6 +11200,7 @@ function createCtx(internals, rootWorkflow) {
11034
11200
  if (escalation !== void 0) {
11035
11201
  if (escalation.flavor === "B" && escalation.deadlineMs === void 0) throw new ConfigError("flavor 'B' escalation requires an explicit deadlineMs: the suspension deadline has no engine default");
11036
11202
  if (escalation.deadlineMs !== void 0) requirePositiveInteger(escalation.deadlineMs, "escalation.deadlineMs");
11203
+ if (escalation.minSpendUsd !== void 0) requireNonNegativeNumber(escalation.minSpendUsd, "escalation.minSpendUsd");
11037
11204
  if (opts.result !== "full" && internals.onEscalation === void 0) throw new ConfigError("a spawn that opts into escalation from a plain value-form call needs an onEscalation hook (or use result: 'full')");
11038
11205
  if (escalation.flavor === "B" && escalation.deadlineMs === void 0) throw new ConfigError("escalation flavor 'B' requires an explicit deadlineMs");
11039
11206
  }
@@ -11589,50 +11756,8 @@ function createCtx(internals, rootWorkflow) {
11589
11756
  exitActivity?.();
11590
11757
  }
11591
11758
  internals.budget.releaseReserve(reserve, budgetAccount);
11592
- let flavorBDecision;
11593
- if (result.status === "escalated" && escalation?.flavor === "B" && result.escalationRequest !== void 0) {
11594
- if (internals.external === void 0) throw new ConfigError("flavor B escalation requires the engine run context");
11595
- const request = result.escalationRequest;
11596
- const deadlineMs = escalation.deadlineMs;
11597
- if (deadlineMs === void 0) throw new ConfigError("flavor 'B' escalation requires an explicit deadlineMs");
11598
- const defaultDecision = escalation.defaultDecision ?? { kind: "accept" };
11599
- let timer;
11600
- const decisionOutcome = await internals.external.awaitDecision({
11601
- scope: agentScope(state.scope, running.seq),
11602
- spanId: internals.spans.mint(spanId),
11603
- toolName: "escalate",
11604
- input: request,
11605
- deadlineAt: new Date(internals.now() + deadlineMs).toISOString(),
11606
- onPending: (entry, replayed) => {
11607
- internals.events.emit({
11608
- type: "approval:pending",
11609
- toolName: "escalate",
11610
- entryRef: entry.seq
11611
- }, spanId, replayed);
11612
- const registry = internals.external;
11613
- timer = setLongTimeout(() => {
11614
- registry?.submitResolution(entry.seq, {
11615
- by: "timeout",
11616
- value: defaultDecision
11617
- }).catch(() => void 0);
11618
- }, Date.parse(entry.deadlineAt ?? "") || internals.now(), () => internals.now());
11619
- if (internals.onEscalation !== void 0) {
11620
- const preview = buildEscalationReport(request, result, void 0);
11621
- const previewResult = {
11622
- ...result,
11623
- escalation: preview
11624
- };
11625
- Promise.resolve(internals.onEscalation(previewResult)).then((decision) => registry?.submitResolution(entry.seq, {
11626
- by: "external",
11627
- value: decision
11628
- })).catch(() => void 0);
11629
- }
11630
- }
11631
- });
11632
- if (timer !== void 0) timer.cancel();
11633
- flavorBDecision = decisionOutcome.value;
11634
- }
11635
- if (acquired !== void 0) {
11759
+ const collectAndDisposeWorktree = async () => {
11760
+ if (acquired === void 0) return;
11636
11761
  try {
11637
11762
  const { files, patch } = await acquired.collect();
11638
11763
  const patchRef = internals.mintTranscriptRef();
@@ -11652,7 +11777,62 @@ function createCtx(internals, rootWorkflow) {
11652
11777
  }, spanId);
11653
11778
  }
11654
11779
  await acquired.dispose(result.status !== "ok" && result.status !== "escalated");
11780
+ };
11781
+ let flavorBDecision;
11782
+ if (result.status === "escalated" && escalation?.flavor === "B" && result.escalationRequest !== void 0) {
11783
+ if (internals.external === void 0) throw new ConfigError("flavor B escalation requires the engine run context");
11784
+ const request = result.escalationRequest;
11785
+ const deadlineMs = escalation.deadlineMs;
11786
+ if (deadlineMs === void 0) throw new ConfigError("flavor 'B' escalation requires an explicit deadlineMs");
11787
+ const defaultDecision = escalation.defaultDecision ?? { kind: "accept" };
11788
+ let timer;
11789
+ let decisionOutcome;
11790
+ try {
11791
+ decisionOutcome = await internals.external.awaitDecision({
11792
+ scope: agentScope(state.scope, running.seq),
11793
+ spanId: internals.spans.mint(spanId),
11794
+ toolName: "escalate",
11795
+ input: request,
11796
+ deadlineAt: new Date(internals.now() + deadlineMs).toISOString(),
11797
+ signal: branchOrRunSignal,
11798
+ onPending: (entry, replayed) => {
11799
+ internals.events.emit({
11800
+ type: "approval:pending",
11801
+ toolName: "escalate",
11802
+ entryRef: entry.seq
11803
+ }, spanId, replayed);
11804
+ const registry = internals.external;
11805
+ timer = setLongTimeout(() => {
11806
+ registry?.submitResolution(entry.seq, {
11807
+ by: "timeout",
11808
+ value: defaultDecision
11809
+ }).catch(() => void 0);
11810
+ }, Date.parse(entry.deadlineAt ?? "") || internals.now(), () => internals.now());
11811
+ if (internals.onEscalation !== void 0) {
11812
+ const preview = buildEscalationReport(request, result, void 0);
11813
+ const previewResult = {
11814
+ ...result,
11815
+ escalation: preview
11816
+ };
11817
+ Promise.resolve(internals.onEscalation(previewResult)).then((decision) => registry?.submitResolution(entry.seq, {
11818
+ by: "external",
11819
+ value: decision
11820
+ })).catch(() => void 0);
11821
+ }
11822
+ }
11823
+ });
11824
+ } catch (thrown) {
11825
+ if (thrown instanceof EscalationDecisionAbortedError) {
11826
+ await collectAndDisposeWorktree();
11827
+ throw new AgentCallError(thrown.message, result, state.scope, running.seq);
11828
+ }
11829
+ throw thrown;
11830
+ } finally {
11831
+ if (timer !== void 0) timer.cancel();
11832
+ }
11833
+ flavorBDecision = decisionOutcome.value;
11655
11834
  }
11835
+ if (acquired !== void 0) await collectAndDisposeWorktree();
11656
11836
  if (result.status === "escalated" && result.escalationRequest !== void 0) {
11657
11837
  const patchRef = result.artifacts?.find((artifact) => artifact.kind === "patch")?.ref;
11658
11838
  const report = buildEscalationReport(result.escalationRequest, result, patchRef);
@@ -12290,6 +12470,28 @@ async function executeWorkflow(internals, wf, args) {
12290
12470
  * written; escalated children simply settle into their digests.
12291
12471
  */
12292
12472
  const ORCHESTRATE_WORKFLOW_NAME = "rulvar-orchestrate";
12473
+ /**
12474
+ * The orchestrate intake gate (v1.35.0 review P2-2): every numeric
12475
+ * option and the atCap literal validate SYNCHRONOUSLY at workflow
12476
+ * construction, shared by both surfaces (the top level orchestrate() throws
12477
+ * before a run exists; ctx.orchestrate throws before any journal entry,
12478
+ * provider call, or child dispatch). A NaN here previously disabled the
12479
+ * spawn cap (`spawnOrdinal >= NaN` is false forever) and the digest
12480
+ * render bound, and a negative finalize reserve WIDENED the soft cap
12481
+ * boundary instead of reserving from it.
12482
+ */
12483
+ function validateOrchestrateOptions(opts) {
12484
+ if (opts === void 0) return;
12485
+ if (opts.maxSpawns !== void 0) requireNonNegativeInteger(opts.maxSpawns, "orchestrate maxSpawns");
12486
+ if (opts.renderBudgetChars !== void 0) requireNonNegativeInteger(opts.renderBudgetChars, "orchestrate renderBudgetChars");
12487
+ const spec = opts.budget;
12488
+ if (spec === void 0) return;
12489
+ if (spec.capUsd !== void 0) requireNonNegativeNumber(spec.capUsd, "orchestrate budget.capUsd");
12490
+ if (spec.capFraction !== void 0) requireFraction(spec.capFraction, "orchestrate budget.capFraction");
12491
+ if (spec.finalizeReserveUsd !== void 0) requireNonNegativeNumber(spec.finalizeReserveUsd, "orchestrate budget.finalizeReserveUsd");
12492
+ if (spec.finalizeTurns !== void 0) requirePositiveInteger(spec.finalizeTurns, "orchestrate budget.finalizeTurns");
12493
+ if (spec.atCap !== void 0 && spec.atCap !== "finish-with-partial" && spec.atCap !== "fail-run") throw new ConfigError(`orchestrate budget.atCap must be 'finish-with-partial' or 'fail-run'; got ${String(spec.atCap)}`);
12494
+ }
12293
12495
  function orchestratorPrompt(goal, maxSpawns, extensionLines) {
12294
12496
  return [
12295
12497
  "You are the orchestrator of a multi-agent run.",
@@ -12344,6 +12546,7 @@ function filterProfiles(registered, names) {
12344
12546
  * orchestrator agent with the finish terminal tool.
12345
12547
  */
12346
12548
  function makeOrchestratorWorkflow(goal, opts) {
12549
+ validateOrchestrateOptions(opts);
12347
12550
  return defineWorkflow({ name: ORCHESTRATE_WORKFLOW_NAME }, async (ctx) => {
12348
12551
  const runtime = runtimeOf(ctx);
12349
12552
  const { internals } = runtime;
@@ -12369,7 +12572,6 @@ function makeOrchestratorWorkflow(goal, opts) {
12369
12572
  const runCeiling = internals.budget.accountView(callingState.budgetScope ?? "run")?.ceilingUsd;
12370
12573
  const spec = opts?.budget;
12371
12574
  const fraction = spec?.capFraction ?? .2;
12372
- if (fraction > 1) throw new OrchestratorCapConfigError(`capFraction ${String(fraction)} exceeds 1.0 (opting out of the cap is explicit only, up to 1.0 inclusive)`);
12373
12575
  const fromFraction = runCeiling === void 0 ? void 0 : fraction * runCeiling;
12374
12576
  const bounds = [spec?.capUsd, fromFraction].filter((bound) => bound !== void 0);
12375
12577
  const priorReserveDecision = internals.replayer.snapshot().find((entry) => {
@@ -12552,6 +12754,15 @@ function makeOrchestratorWorkflow(goal, opts) {
12552
12754
  byOrdinal.set(spawnOrdinal, record);
12553
12755
  return record;
12554
12756
  };
12757
+ /**
12758
+ * The declared fail-run terminal (v1.35.0 review P2-1): the first
12759
+ * extension terminate() call stores its failure and aborts the
12760
+ * orchestrator loop; the settle boundary rethrows it deterministically
12761
+ * (boot terminates again from the journaled verdict on resume, so the
12762
+ * same failure rolls forward without a model call).
12763
+ */
12764
+ let extensionTermination;
12765
+ const forcedFinishController = new AbortController();
12555
12766
  const io = {
12556
12767
  runId: internals.runId,
12557
12768
  baseScope: callingState.scope,
@@ -12597,7 +12808,12 @@ function makeOrchestratorWorkflow(goal, opts) {
12597
12808
  },
12598
12809
  registerAlias: (donorScope, targetScope) => internals.replayer.registerAlias(donorScope, targetScope),
12599
12810
  priceUsd: (servedBy, usage) => servedBy === void 0 ? void 0 : internals.priceUsd(servedBy, usage),
12600
- emit: (event, options) => internals.events.emit(event, callingState.spanId, options?.replayed)
12811
+ emit: (event, options) => internals.events.emit(event, callingState.spanId, options?.replayed),
12812
+ terminate: (error) => {
12813
+ if (extensionTermination !== void 0) return;
12814
+ extensionTermination = error;
12815
+ forcedFinishController.abort("rulvar:extension-terminate");
12816
+ }
12601
12817
  };
12602
12818
  const cancelByHandle = async (handle, _reason) => {
12603
12819
  const record = records.get(handle);
@@ -12690,7 +12906,6 @@ function makeOrchestratorWorkflow(goal, opts) {
12690
12906
  await runExtensionActivity();
12691
12907
  };
12692
12908
  let capDecisionRef = internals.replayer.snapshot().find((entry) => entry.kind === "decision" && entry.value?.decisionType === "orchestrator_budget_cap")?.seq;
12693
- const forcedFinishController = new AbortController();
12694
12909
  let capInFlight = false;
12695
12910
  /**
12696
12911
  * The at-cap freeze: EXACTLY one decision entry
@@ -12772,11 +12987,11 @@ function makeOrchestratorWorkflow(goal, opts) {
12772
12987
  completedDigests: undelivered.map((record) => {
12773
12988
  const row = digestOf(record, record.settled);
12774
12989
  const budgetChars = opts?.renderBudgetChars ?? 400;
12775
- if (row.outputSummary.length > budgetChars) return {
12990
+ const outputSummary = truncateToBudget(row.outputSummary, budgetChars);
12991
+ return outputSummary === row.outputSummary ? row : {
12776
12992
  ...row,
12777
- outputSummary: `${row.outputSummary.slice(0, budgetChars)}...`
12993
+ outputSummary
12778
12994
  };
12779
- return row;
12780
12995
  }),
12781
12996
  escalations
12782
12997
  };
@@ -13168,9 +13383,32 @@ function makeOrchestratorWorkflow(goal, opts) {
13168
13383
  completed: [...records.values()].filter((record) => record.settled !== void 0).sort((a, b) => a.spawnOrdinal - b.spawnOrdinal).map((record) => digestOf(record, record.settled))
13169
13384
  };
13170
13385
  };
13171
- if (capDecisionRef !== void 0) return await runForcedFinish();
13386
+ /**
13387
+ * The settle at the cap: the JOURNALED cap decision drives the policy
13388
+ * branch (its `fallback` field froze budget.atCap when the cap
13389
+ * tripped), so a crash between the decision and its effect rolls the
13390
+ * SAME outcome forward on resume, immune to drift of the live options.
13391
+ * 'finish-with-partial' runs the reserved finalizer;
13392
+ * 'fail-run' skips it and fails the run typed (v1.35.0 review P2-1:
13393
+ * the policy used to be journaled and then ignored).
13394
+ */
13395
+ const settleCapOutcome = async () => {
13396
+ const capValue = internals.replayer.snapshot().find((entry) => entry.seq === capDecisionRef)?.value;
13397
+ if (capValue?.fallback === "fail-run") throw new FailRunError(`the orchestrator budget cap was reached (decision entry ${String(capDecisionRef ?? -1)}) and budget.atCap is 'fail-run': the reserved finalizer is skipped and the run fails instead of returning a partial result`, { data: {
13398
+ source: "orchestrator_budget_cap",
13399
+ capDecisionRef: capDecisionRef ?? -1,
13400
+ spentUsd: capValue.spentUsd ?? 0,
13401
+ capUsd: capValue.capUsd ?? 0
13402
+ } });
13403
+ return await runForcedFinish();
13404
+ };
13405
+ const bootTermination = extensionTermination;
13406
+ if (bootTermination !== void 0) throw bootTermination;
13407
+ if (capDecisionRef !== void 0) return await settleCapOutcome();
13172
13408
  const result = await runtime.runInScope(orchestratorState, () => ctx.agent(orchestratorPrompt(goal, opts?.maxSpawns, extension?.promptLines?.()), agentOpts));
13173
- if (capDecisionRef !== void 0) return await runForcedFinish();
13409
+ const liveTermination = extensionTermination;
13410
+ if (liveTermination !== void 0) throw liveTermination;
13411
+ if (capDecisionRef !== void 0) return await settleCapOutcome();
13174
13412
  if (orchestratorAccount !== void 0) internals.cost.orchestrator.spentUsd = internals.budget.accountView(orchestratorAccount)?.spentUsd ?? 0;
13175
13413
  if (result.status !== "ok") throw new ConfigError(`the orchestrator agent terminated with status '${result.status}'` + (result.errorMessage === void 0 ? "" : `: ${result.errorMessage}`));
13176
13414
  return result.output;
@@ -13366,6 +13604,29 @@ var EventBus = class {
13366
13604
  }
13367
13605
  };
13368
13606
  //#endregion
13607
+ //#region src/l0/run-id.ts
13608
+ /**
13609
+ * Run id containment (v1.36.0 review SEC-P1). A runId becomes both a
13610
+ * journal path component (JsonlFileStore.safeName) and the PREFIX of every
13611
+ * transcript ref (checkpointRefFor, workflowSourceRef append `/...`). The
13612
+ * journal's whole-token regex rejects a separator, but a bare '.' or '..'
13613
+ * slips through as a single component there and, once a '/suffix' is
13614
+ * appended, becomes a real traversal segment at the transcript store. The
13615
+ * engine validates the runId at its boundary, before the first transcript
13616
+ * write, so an untrusted runId is refused with a typed ConfigError instead
13617
+ * of escaping the configured transcript root.
13618
+ */
13619
+ /** Filesystem-safe token: the journal store's own alphabet. */
13620
+ const SAFE_RUN_ID = /^[A-Za-z0-9._-]+$/;
13621
+ /**
13622
+ * Throws a ConfigError unless runId is a filesystem-safe token: a
13623
+ * non-empty string over [A-Za-z0-9._-] that is neither '.' nor '..'. The
13624
+ * dot pair passes the alphabet on its own, so it is refused explicitly.
13625
+ */
13626
+ function assertSafeRunId(runId, context) {
13627
+ if (typeof runId !== "string" || runId === "" || runId === "." || runId === ".." || !SAFE_RUN_ID.test(runId)) throw new ConfigError(`${context}: runId ${JSON.stringify(runId)} is not filesystem-safe (allowed: [A-Za-z0-9._-], and neither "." nor "..")`);
13628
+ }
13629
+ //#endregion
13369
13630
  //#region src/runner/inprocess.ts
13370
13631
  /**
13371
13632
  * ScriptRunner SPI and InProcessRunner (M1-T11).
@@ -13565,6 +13826,7 @@ function createEngine(options) {
13565
13826
  if (profile.limits !== void 0) validateUsageLimits(profile.limits, `createEngine defaults.profiles['${name}'].limits`);
13566
13827
  if (profile.estCost !== void 0) requireNonNegativeNumber(profile.estCost, `createEngine defaults.profiles['${name}'].estCost`);
13567
13828
  if (profile.escalation?.deadlineMs !== void 0) requirePositiveInteger(profile.escalation.deadlineMs, `createEngine defaults.profiles['${name}'].escalation.deadlineMs`);
13829
+ if (profile.escalation?.minSpendUsd !== void 0) requireNonNegativeNumber(profile.escalation.minSpendUsd, `createEngine defaults.profiles['${name}'].escalation.minSpendUsd`);
13568
13830
  if (profile.compaction?.threshold !== void 0) requireFraction(profile.compaction.threshold, `createEngine defaults.profiles['${name}'].compaction.threshold`);
13569
13831
  }
13570
13832
  const knowledgeStore = options.stores?.modelKnowledge;
@@ -13591,6 +13853,7 @@ function createEngine(options) {
13591
13853
  const compiled = wf.kind === "compiled-workflow" ? wf : void 0;
13592
13854
  if (compiled !== void 0 && options.runners?.sandbox === void 0) throw new ConfigError("running a CompiledWorkflow requires a sandbox runner: pass createEngine({ runners: { sandbox: new WorkerSandboxRunner() } }) from @rulvar/planner ");
13593
13855
  const runId = resumeCtx?.runId ?? opts?.runId ?? mintRunId();
13856
+ assertSafeRunId(runId, "engine.run");
13594
13857
  const registry = buildDeriverRegistry(options.extraDerivers);
13595
13858
  const segmentsBefore = resumeCtx?.segmentsBefore ?? 0;
13596
13859
  const telemetryBase = segmentsBefore * EVENT_SEGMENT_STRIDE;
@@ -14319,4 +14582,4 @@ function createSandboxBridge(ctx, options) {
14319
14582
  };
14320
14583
  }
14321
14584
  //#endregion
14322
- 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, EVENT_SEGMENT_STRIDE, EventBus, ExternalRegistry, FINALIZE_SYNTHESIS_INSTRUCTION, 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, SANDBOX_AGENT_OPT_KEYS, 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, affordableOutputTokens, agentErrorFromWire, agentErrorToWire, agentResultWire, 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, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hasMetaLookup, hashRunArgs, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, metaMatchesFilter, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, priceEntryUsage, priceUsdOf, profileCard, profileRegistrySnapshotHash, projectHistory, projectIdentity, projectToJsonSchema, proposalStatement, providerOf, readRunMeta, readTerminationInit, registryKeyRing, remeasureQueue, replayDisposition, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, sanitizeTerminalText, sanitizeTokenCount, sanitizeUsage, sanitizeUsageDelta, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, snapshotUsage, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, usageViolations, validateEditorialCommit, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateRetryPolicy, validateSchemaSpec, validateTerminationLimits, validateUsageLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
14585
+ 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, EVENT_SEGMENT_STRIDE, EscalationDecisionAbortedError, EventBus, ExternalRegistry, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FailRunError, 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, SANDBOX_AGENT_OPT_KEYS, 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, affordableOutputTokens, agentErrorFromWire, agentErrorToWire, agentResultWire, 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, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hasMetaLookup, hashRunArgs, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, metaMatchesFilter, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, priceEntryUsage, priceUsdOf, profileCard, profileRegistrySnapshotHash, projectHistory, projectIdentity, projectToJsonSchema, proposalStatement, providerOf, readRunMeta, readTerminationInit, registryKeyRing, remeasureQueue, replayDisposition, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, sanitizeTerminalText, sanitizeTokenCount, sanitizeUsage, sanitizeUsageDelta, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, snapshotUsage, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, usageViolations, validateEditorialCommit, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateRetryPolicy, validateSchemaSpec, validateTerminationLimits, validateUsageLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/core",
3
- "version": "1.35.0",
3
+ "version": "1.37.0",
4
4
  "description": "Rulvar core: L0 contracts, journal kernel, ctx primitives, agent runtime, model router, tool system, dynamic orchestrator, InMemory and JSONL stores, event stream.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",