@rulvar/core 1.53.0 → 1.54.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.
package/dist/index.d.ts CHANGED
@@ -2958,6 +2958,26 @@ type CoreEvents = {
2958
2958
  * charge. Absent means every contributing turn reported exact usage.
2959
2959
  */
2960
2960
  usageApprox?: boolean;
2961
+ /**
2962
+ * The semantic completion lift (RV-207 tail): present when the
2963
+ * workflow reported semantic completion through the completion
2964
+ * envelope contract: an `ok`/`exhausted` run whose result value is
2965
+ * an object carrying a valid `completion` literal, or an `error`
2966
+ * run whose typed error data carries one (the orchestrator
2967
+ * acceptance path emits both). Transport status says whether the
2968
+ * run ran; completion says whether the work is COMPLETE: an
2969
+ * accepted degraded run is `status: 'ok'` with `completion:
2970
+ * 'partial'`. Replay recomputes the same value from the re-executed
2971
+ * workflow, so the field is identical live and replayed. Absent
2972
+ * when the workflow makes no completion claim.
2973
+ */
2974
+ completion?: "complete" | "partial" | "rejected";
2975
+ /**
2976
+ * Settled child statuses by status name, lifted from the same
2977
+ * envelope (or typed error data) when it carries a valid record of
2978
+ * nonnegative integers. Absent otherwise.
2979
+ */
2980
+ childStatusCounts?: Record<string, number>;
2961
2981
  } | {
2962
2982
  type: "phase:start";
2963
2983
  phase: string;
@@ -5313,6 +5333,48 @@ declare function hashRunArgs(args: unknown): string | undefined;
5313
5333
  declare function hashRunOutput(value: unknown): string | undefined;
5314
5334
  declare function createEngine(options: CreateEngineOptions): Engine;
5315
5335
  //#endregion
5336
+ //#region src/orchestrator/claims.d.ts
5337
+ /**
5338
+ * Repeated-claim deduplication (RV-211 remainder): a PURE, deterministic
5339
+ * fold that removes byte-repeated claim lines across children BEFORE any
5340
+ * model call, so the synthesis invocation never spends context re-reading
5341
+ * what several children reported identically. Matching is deliberately
5342
+ * conservative: lines compare by whitespace-collapsed exact equality
5343
+ * (trim, inner runs of whitespace to one space), never fuzzily, so two
5344
+ * DISTINCT claims can never merge; the first occurrence survives verbatim
5345
+ * and every later occurrence is dropped and indexed. Empty lines are
5346
+ * structure, not claims: they always survive.
5347
+ *
5348
+ * Public docs: https://docs.rulvar.com/guide/orchestration-modes
5349
+ */
5350
+ /** One claim reported more than once across the input rows. */
5351
+ interface RepeatedClaim {
5352
+ /** The first-seen line, verbatim. */
5353
+ claim: string;
5354
+ /** Reporters in input order; the first entry made the surviving copy. */
5355
+ nodeIds: string[];
5356
+ /** Total occurrences across all rows, the surviving one included. */
5357
+ count: number;
5358
+ }
5359
+ interface DedupedClaims {
5360
+ /** The input rows with every repeated line's later occurrences removed. */
5361
+ rows: {
5362
+ nodeId: string;
5363
+ text: string;
5364
+ }[];
5365
+ /** Claims seen more than once, in first-occurrence order. */
5366
+ repeated: RepeatedClaim[];
5367
+ }
5368
+ /**
5369
+ * Removes later occurrences of repeated claim lines across the rows and
5370
+ * indexes each repeated claim with its reporters. Deterministic: output
5371
+ * depends only on the input order and bytes.
5372
+ */
5373
+ declare function dedupeRepeatedClaims(rows: {
5374
+ nodeId: string;
5375
+ text: string;
5376
+ }[]): DedupedClaims;
5377
+ //#endregion
5316
5378
  //#region src/orchestrator/finish-validators.d.ts
5317
5379
  /**
5318
5380
  * One child as the finish validators see it (the RV-202 provenance
@@ -5945,6 +6007,12 @@ declare const DEFAULT_FINISH_MAX_REPAIRS = 1;
5945
6007
  */
5946
6008
  declare const DEFAULT_SYNTHESIS_MAX_TURNS = 4;
5947
6009
  /**
6010
+ * Default maxTurns of ONE incremental synthesis note (RV-211 remainder):
6011
+ * a note summarizes a single settled child into a bounded finish call,
6012
+ * so it needs less headroom than the full synthesis invocation.
6013
+ */
6014
+ declare const DEFAULT_SYNTHESIS_NOTE_MAX_TURNS = 2;
6015
+ /**
5948
6016
  * The opt in deterministic validation of the orchestrator finish result
5949
6017
  * (the v1.40.0 improvement plan's RV-204 slice). Every SCHEMA valid
5950
6018
  * finish({ result }) call first passes the configured host validators;
@@ -6075,9 +6143,71 @@ interface OrchestrateSynthesis {
6075
6143
  * Admission estimate for the synthesize invocation, like
6076
6144
  * AgentOpts.estCost: under a tight orchestrator cap the default
6077
6145
  * reserve (full maxOutputTokens pricing) can refuse the dispatch; an
6078
- * explicit estimate is the host speaking.
6146
+ * explicit estimate is the host speaking. In 'incremental' mode the
6147
+ * estimate applies to EACH note invocation.
6079
6148
  */
6080
6149
  estCost?: number;
6150
+ /**
6151
+ * The synthesis shape (RV-211 remainder). Default 'single': one
6152
+ * post-fan-in synthesize invocation composes the final result from the
6153
+ * draft and the whole settled digest. 'incremental': every settled
6154
+ * child triggers ONE bounded synthesize-role NOTE invocation as soon
6155
+ * as it settles (concurrent with the still-running fan-out, which is
6156
+ * what moves synthesis wall time off the post-fan-in critical path),
6157
+ * and the FINAL result is a DETERMINISTIC reconciliation, never
6158
+ * another model call: an {@link IncrementalSynthesisResult} envelope
6159
+ * composed from the draft and the notes in spawn order. The tradeoffs
6160
+ * are explicit: notes are paid DURING the run, so an acceptance
6161
+ * rejection can no longer guarantee "a rejected run never paid for
6162
+ * synthesis"; and because the reconciliation has no model-composed
6163
+ * finish, `finishValidation` cannot bind it: configuring both is a
6164
+ * ConfigError at intake. A note that dies falls back to the child's
6165
+ * raw digest summary under a journaled per-child
6166
+ * 'orchestrator_synthesis_note_fallback' decision and a warn log.
6167
+ * Cap paths are unchanged: a capped run settles through the reserved
6168
+ * finalizer and never reconciles.
6169
+ */
6170
+ mode?: "single" | "incremental";
6171
+ /**
6172
+ * Deduplicate repeated claim lines across children BEFORE any model
6173
+ * call (RV-211 remainder; default false, and the prompt stays byte
6174
+ * identical when unset). In 'single' mode the digest entering the
6175
+ * synthesis prompt keeps only the FIRST occurrence of every repeated
6176
+ * line and a REPEATED CLAIMS index (each claim with its reporters)
6177
+ * rides the prompt beside it. In 'incremental' mode the deterministic
6178
+ * reconciliation dedupes the note texts the same way and the envelope
6179
+ * carries the `repeatedClaims` index. Matching is whitespace-collapsed
6180
+ * exact line equality: nothing fuzzy ever merges two distinct claims.
6181
+ */
6182
+ dedupeClaims?: boolean;
6183
+ /**
6184
+ * UsageLimits of ONE incremental note invocation; default
6185
+ * { maxTurns: 2 }. Ignored in 'single' mode.
6186
+ */
6187
+ noteLimits?: UsageLimits;
6188
+ }
6189
+ /**
6190
+ * The deterministic reconciliation envelope an 'incremental' synthesis
6191
+ * returns as the run result (RV-211 remainder): the coordination draft
6192
+ * plus one section per settled child in spawn order, each carrying the
6193
+ * child's terminal status and its note (the note invocation's finish
6194
+ * output, or the child's raw digest summary when the note fell back).
6195
+ * With `dedupeClaims`, repeated claim lines keep their first occurrence
6196
+ * only and the `repeatedClaims` index lists each with its reporters.
6197
+ * Everything here derives from journaled state, so a resume reproduces
6198
+ * the envelope byte for byte with zero paid calls.
6199
+ */
6200
+ interface IncrementalSynthesisResult {
6201
+ synthesis: "incremental";
6202
+ draft: unknown;
6203
+ sections: {
6204
+ nodeId: string;
6205
+ logicalTaskId: string; /** The child's terminal status. */
6206
+ status: string; /** The note invocation's terminal status ('ok' unless it fell back). */
6207
+ noteStatus: string;
6208
+ note: string;
6209
+ }[];
6210
+ repeatedClaims?: RepeatedClaim[];
6081
6211
  }
6082
6212
  declare const ORCHESTRATE_WORKFLOW_NAME = "rulvar-orchestrate";
6083
6213
  /**
@@ -6990,6 +7120,44 @@ declare class GitWorktreeProvider implements IsolationProvider {
6990
7120
  }>;
6991
7121
  }
6992
7122
  //#endregion
7123
+ //#region src/tools/research.d.ts
7124
+ interface RepositoryResearchToolsetOptions {
7125
+ /** The confining directory root; everything resolves under it. */
7126
+ root: string;
7127
+ /** Rows per list/search/evidence page; default 50. */
7128
+ pageSize?: number;
7129
+ /** Content budget of one read_file page in characters; default 4000. */
7130
+ readPageChars?: number;
7131
+ /** Files larger than this many bytes are refused; default 262144. */
7132
+ maxFileBytes?: number;
7133
+ /** Walk ceiling per call (files visited); default 20000. */
7134
+ maxScannedFiles?: number;
7135
+ /**
7136
+ * Extra ignored basenames (files and directories), merged over the
7137
+ * always-on defaults '.git' and 'node_modules'.
7138
+ */
7139
+ ignore?: string[];
7140
+ /** Walk dot-entries too; default false. */
7141
+ includeHidden?: boolean;
7142
+ }
7143
+ /** One verified evidence entry recorded by `record_evidence`. */
7144
+ interface ResearchEvidenceEntry {
7145
+ claim: string;
7146
+ /** Root-relative POSIX path, verified to exist at record time. */
7147
+ file: string;
7148
+ /** 'N' or 'N-M', 1-based, verified inside the file's line count. */
7149
+ lines?: string;
7150
+ /** Verified verbatim substring of the file at record time. */
7151
+ quote?: string;
7152
+ }
7153
+ interface RepositoryResearchToolset {
7154
+ /** list_files, search_files, read_file, record_evidence, list_evidence. */
7155
+ tools: ToolDef[];
7156
+ /** Snapshot copy of the evidence collected so far, in record order. */
7157
+ evidence(): ResearchEvidenceEntry[];
7158
+ }
7159
+ declare function repositoryResearchToolset(options: RepositoryResearchToolsetOptions): RepositoryResearchToolset;
7160
+ //#endregion
6993
7161
  //#region src/journal/scope.d.ts
6994
7162
  /**
6995
7163
  * Scope-path grammar (M1-T04): deterministic structural paths, independent
@@ -7756,4 +7924,4 @@ interface SandboxBridge {
7756
7924
  declare const SANDBOX_AGENT_OPT_KEYS: readonly string[];
7757
7925
  declare function createSandboxBridge(ctx: Ctx<never>, options: SandboxBridgeOptions): SandboxBridge;
7758
7926
  //#endregion
7759
- export { AWAIT_SCHEMA, AbandonAttempt, AbandonFold, AbandonPayload, AbandonedSpendView, AbortClass, type AdaptiveEvents, AdmissionController, AdmissionDecision, AdmissionRejectedError, AdmissionStatsBefore, AdmitLineage, AdmitRejectReason, AdmitSpec, AdmitVerdict, AgentCallError, AgentError, type AgentEvents, AgentIdentityInput, type AgentInvocationRow, AgentOpts, AgentProfile, AgentProfilePermissions, AgentResult, AgentResultMeta, AgentStatus, ApproachSignatureInputs, ApprovalDecision, ApprovalIdentityInput, Artifact, AttemptOutcomeClass, AuditRunsOptions, 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, ChildArtifactPage, ChildIdentityInput, ChildResultPage, type ClaimClass, type ClaimOp, type ClaimStatus, ClaimValidationOptions, CollectOpts, CollectedTurn, CompactionConfig, CompiledPermissionChain, CompiledWorkflow, ConfigError, type CoreEvents, CostAttribution, CostAttributionFacts, CostReport, CreateEngineOptions, type CriticalPath, Ctx, DEFAULT_CHILD_BUDGET_FRACTION, DEFAULT_CHILD_RESULT_PAGE_CHARS, DEFAULT_CITATION_PATTERN, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_EVIDENCE_MIN_SHARE, DEFAULT_FINISH_MAX_REPAIRS, 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, DEFAULT_SYNTHESIS_MAX_TURNS, DebitResult, DeclaredLadder, DedupIndex, DedupNote, DerivedKey, DeriverRegistry, type DeterminismConfig, DeterminismError, type DeterminismEvents, type DeterminismMode, 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, type ExplorationSummary, ExtensionAppendInput, ExtensionDispatchSpec, ExternalIdentityInput, ExternalRegistry, ExtractNecessityInput, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FailRunError, FailoverTarget, FailoverTrigger, FallbackField, FallbackTrigger, FileModelKnowledgeStore, FileModelKnowledgeStoreOptions, FileTranscriptStore, FinishInfo, FinishValidationChild, FinishValidationInput, FinishValidationSpec, FinishValidationVerdict, FinishValidator, GET_CHILD_RESULT_SCHEMA, GET_CHILD_RESULT_TOOL_NAME, Gate, GateAudit, type GateRecord, GitWorktreeProvider, GitWorktreeProviderOptions, GraftBoot, HashVersion, HookVerdict, INBOX_PROPOSAL_TTL_DAYS, IdentityInput, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, InvalidResolutionError, InvocationRole, type InvocationTable, 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_CHILD_RESULT_PAGE_CHARS, 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, OrchestrateAcceptance, OrchestrateOptions, OrchestrateSynthesis, OrchestratorBudgetSpec, OrchestratorCapConfigError, OrchestratorExtension, OrchestratorExtensionIO, OrchestratorRuntime, Out, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, Part, PendingExternal, PendingToolTurn, PermissionConfig, PermissionGate, PermissionHook, PermissionPreset, PermissionRule, PermissionVerdict, type PhaseRow, PhaseTarget, PipelineCollected, PipelineOpts, PlanInvariantError, PriceTable, PricedUsage, type Pricing, type PricingTier, type ProviderAdapter, QualityFloors, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RUN_SETTLE_DECISION_TYPE, RandIdentityInput, RandPayload, ReconcileOptions, ReconcileResult, 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, RunAuditVerdict, RunBudget, RunEventSink, type RunFilter, RunHandle, RunInternals, type RunMeta, RunOptions, RunOutcome, RunProfile, RunStateAudit, 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, assertFencedWrites, atCompactionThreshold, auditRun, auditRuns, 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, evidencePreservedValidator, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hasFencedWrites, hasMetaLookup, hashRunArgs, hashRunOutput, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lastRunSettle, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, metaMatchesFilter, minMatchesValidator, 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, reconcileRunMeta, reduceCriticalPath, reduceInvocationTable, registryKeyRing, remeasureQueue, replayDisposition, requiredFieldsValidator, requiredSectionsValidator, 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 };
7927
+ export { AWAIT_SCHEMA, AbandonAttempt, AbandonFold, AbandonPayload, AbandonedSpendView, AbortClass, type AdaptiveEvents, AdmissionController, AdmissionDecision, AdmissionRejectedError, AdmissionStatsBefore, AdmitLineage, AdmitRejectReason, AdmitSpec, AdmitVerdict, AgentCallError, AgentError, type AgentEvents, AgentIdentityInput, type AgentInvocationRow, AgentOpts, AgentProfile, AgentProfilePermissions, AgentResult, AgentResultMeta, AgentStatus, ApproachSignatureInputs, ApprovalDecision, ApprovalIdentityInput, Artifact, AttemptOutcomeClass, AuditRunsOptions, 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, ChildArtifactPage, ChildIdentityInput, ChildResultPage, type ClaimClass, type ClaimOp, type ClaimStatus, ClaimValidationOptions, CollectOpts, CollectedTurn, CompactionConfig, CompiledPermissionChain, CompiledWorkflow, ConfigError, type CoreEvents, CostAttribution, CostAttributionFacts, CostReport, CreateEngineOptions, type CriticalPath, Ctx, DEFAULT_CHILD_BUDGET_FRACTION, DEFAULT_CHILD_RESULT_PAGE_CHARS, DEFAULT_CITATION_PATTERN, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_EVIDENCE_MIN_SHARE, DEFAULT_FINISH_MAX_REPAIRS, 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, DEFAULT_SYNTHESIS_MAX_TURNS, DEFAULT_SYNTHESIS_NOTE_MAX_TURNS, DebitResult, DeclaredLadder, DedupIndex, DedupNote, DedupedClaims, DerivedKey, DeriverRegistry, type DeterminismConfig, DeterminismError, type DeterminismEvents, type DeterminismMode, 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, type ExplorationSummary, ExtensionAppendInput, ExtensionDispatchSpec, ExternalIdentityInput, ExternalRegistry, ExtractNecessityInput, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FailRunError, FailoverTarget, FailoverTrigger, FallbackField, FallbackTrigger, FileModelKnowledgeStore, FileModelKnowledgeStoreOptions, FileTranscriptStore, FinishInfo, FinishValidationChild, FinishValidationInput, FinishValidationSpec, FinishValidationVerdict, FinishValidator, GET_CHILD_RESULT_SCHEMA, GET_CHILD_RESULT_TOOL_NAME, Gate, GateAudit, type GateRecord, GitWorktreeProvider, GitWorktreeProviderOptions, GraftBoot, HashVersion, HookVerdict, INBOX_PROPOSAL_TTL_DAYS, IdentityInput, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, IncrementalSynthesisResult, InvalidResolutionError, InvocationRole, type InvocationTable, 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_CHILD_RESULT_PAGE_CHARS, 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, OrchestrateAcceptance, OrchestrateOptions, OrchestrateSynthesis, OrchestratorBudgetSpec, OrchestratorCapConfigError, OrchestratorExtension, OrchestratorExtensionIO, OrchestratorRuntime, Out, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, Part, PendingExternal, PendingToolTurn, PermissionConfig, PermissionGate, PermissionHook, PermissionPreset, PermissionRule, PermissionVerdict, type PhaseRow, PhaseTarget, PipelineCollected, PipelineOpts, PlanInvariantError, PriceTable, PricedUsage, type Pricing, type PricingTier, type ProviderAdapter, QualityFloors, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RUN_SETTLE_DECISION_TYPE, RandIdentityInput, RandPayload, ReconcileOptions, ReconcileResult, RefEntryAppender, RefEntryClassification, RefusalInfo, RepeatedClaim, ReplayDisposition, ReplayMode, ReplayPlanHashMismatch, Replayer, RepositoryResearchToolset, RepositoryResearchToolsetOptions, ResearchEvidenceEntry, ResolutionArbiter, ResolutionAttempt, ResolutionBy, ResolutionFold, ResolutionLayer, ResolutionOutcome, ResolutionPayload, ResolvedInvocation, ResolvedToolset, ResumeHandle, ResumeOptions, ResumePreview, ResumeReport, RetryClass, RetryPolicy, ReuseConfig, RiskRuleValue, Role, RulvarError, RulvarErrorCode, RunAgentOptions, RunAuditVerdict, RunBudget, RunEventSink, type RunFilter, RunHandle, RunInternals, type RunMeta, RunOptions, RunOutcome, RunProfile, RunStateAudit, 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, assertFencedWrites, atCompactionThreshold, auditRun, auditRuns, 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, dedupeRepeatedClaims, defineWorkflow, deriveContentKey, deriverV1, deriverV2, digestOf, dispositionHook, emptyDigestBlocks, emptyToolset, encodeCheckpoint, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, evidencePreservedValidator, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hasFencedWrites, hasMetaLookup, hashRunArgs, hashRunOutput, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lastRunSettle, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, metaMatchesFilter, minMatchesValidator, 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, reconcileRunMeta, reduceCriticalPath, reduceInvocationTable, registryKeyRing, remeasureQueue, replayDisposition, repositoryResearchToolset, requiredFieldsValidator, requiredSectionsValidator, 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,13 +1,13 @@
1
1
  import { createHash, getRandomValues, randomUUID } from "node:crypto";
2
- import { appendFileSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
3
- import { dirname, join, resolve, sep } from "node:path";
2
+ import { appendFileSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
3
+ import path, { 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";
7
7
  import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
8
8
  import { ToolListChangedNotificationSchema } from "@modelcontextprotocol/sdk/types.js";
9
9
  import { execFile } from "node:child_process";
10
- import { mkdtemp, rm } from "node:fs/promises";
10
+ import { mkdtemp, readFile, readdir, realpath, rm, stat } from "node:fs/promises";
11
11
  import { tmpdir } from "node:os";
12
12
  import { promisify } from "node:util";
13
13
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -3297,6 +3297,459 @@ var GitWorktreeProvider = class {
3297
3297
  }
3298
3298
  };
3299
3299
  //#endregion
3300
+ //#region src/tools/research.ts
3301
+ /**
3302
+ * The standard repository research toolset (RV-210 remainder): paginated
3303
+ * list/search/read tools over a confined directory root with STABLE
3304
+ * keyset cursors, plus an evidence collector that verifies citations at
3305
+ * collection time. Design contract:
3306
+ *
3307
+ * - Responses are CANONICAL: a page is a pure function of (root
3308
+ * filesystem state, logical window), never of how the window was
3309
+ * addressed, so reading the same page through a cursor and through
3310
+ * fresh arguments returns byte-identical results. That is what makes
3311
+ * the RV-210 `maxNoNewEvidenceCalls` guard measure duplicate-page
3312
+ * reads correctly, and the `maxRepeatedToolSignature` guard already
3313
+ * denies byte-identical repeat calls: deduplication is composition,
3314
+ * not a marker field.
3315
+ * - Cursors are keyset cursors (the last path / line, not an offset), so
3316
+ * a page boundary never shifts when unrelated entries appear or
3317
+ * disappear, and every cursor embeds the query identity: replaying a
3318
+ * cursor against different arguments is a typed error result.
3319
+ * - Ordering is deterministic byte order (UTF-16 code unit sort), never
3320
+ * locale collation.
3321
+ * - The root confines everything: relative paths only, `..` escapes and
3322
+ * symlink escapes are typed error results, symlinked directories are
3323
+ * never walked.
3324
+ * - User-level failures (bad path, binary file, oversized file, invalid
3325
+ * cursor, an unverifiable citation) are RETURNED `{ error }` values,
3326
+ * deterministic and visible to the model; only host misconfiguration
3327
+ * throws (ConfigError at construction).
3328
+ * - Tool results are journaled at execution time, so replay never
3329
+ * touches the filesystem; live pages read the live tree.
3330
+ *
3331
+ * Public docs: https://docs.rulvar.com/guide/tools
3332
+ */
3333
+ const DEFAULT_PAGE_SIZE = 50;
3334
+ const DEFAULT_READ_PAGE_CHARS = 4e3;
3335
+ const DEFAULT_MAX_FILE_BYTES = 262144;
3336
+ const DEFAULT_MAX_SCANNED_FILES = 2e4;
3337
+ const ALWAYS_IGNORED = [".git", "node_modules"];
3338
+ const SEARCH_SNIPPET_CHARS = 200;
3339
+ const BINARY_SNIFF_BYTES = 8192;
3340
+ const LIST_SCHEMA = {
3341
+ type: "object",
3342
+ additionalProperties: false,
3343
+ properties: {
3344
+ dir: {
3345
+ type: "string",
3346
+ description: "Root-relative directory to list; default the root."
3347
+ },
3348
+ cursor: {
3349
+ type: "string",
3350
+ description: "Opaque cursor from a previous page."
3351
+ }
3352
+ }
3353
+ };
3354
+ const SEARCH_SCHEMA = {
3355
+ type: "object",
3356
+ additionalProperties: false,
3357
+ required: ["query"],
3358
+ properties: {
3359
+ query: {
3360
+ type: "string",
3361
+ minLength: 1,
3362
+ description: "Literal substring to find."
3363
+ },
3364
+ dir: {
3365
+ type: "string",
3366
+ description: "Root-relative directory to search; default the root."
3367
+ },
3368
+ cursor: {
3369
+ type: "string",
3370
+ description: "Opaque cursor from a previous page."
3371
+ }
3372
+ }
3373
+ };
3374
+ const READ_SCHEMA = {
3375
+ type: "object",
3376
+ additionalProperties: false,
3377
+ required: ["path"],
3378
+ properties: {
3379
+ path: {
3380
+ type: "string",
3381
+ minLength: 1,
3382
+ description: "Root-relative file path."
3383
+ },
3384
+ cursor: {
3385
+ type: "string",
3386
+ description: "Opaque cursor from a previous page."
3387
+ }
3388
+ }
3389
+ };
3390
+ const RECORD_EVIDENCE_SCHEMA = {
3391
+ type: "object",
3392
+ additionalProperties: false,
3393
+ required: ["claim", "file"],
3394
+ properties: {
3395
+ claim: {
3396
+ type: "string",
3397
+ minLength: 1,
3398
+ description: "The claim this evidence supports."
3399
+ },
3400
+ file: {
3401
+ type: "string",
3402
+ minLength: 1,
3403
+ description: "Root-relative file the claim cites."
3404
+ },
3405
+ lines: {
3406
+ type: "string",
3407
+ description: "Cited line or range, 1-based: '12' or '12-40'."
3408
+ },
3409
+ quote: {
3410
+ type: "string",
3411
+ minLength: 1,
3412
+ description: "Verbatim quote; verified to appear in the file."
3413
+ }
3414
+ }
3415
+ };
3416
+ const LIST_EVIDENCE_SCHEMA = {
3417
+ type: "object",
3418
+ additionalProperties: false,
3419
+ properties: { cursor: {
3420
+ type: "string",
3421
+ description: "Opaque cursor from a previous page."
3422
+ } }
3423
+ };
3424
+ function encodeCursor(payload) {
3425
+ return Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
3426
+ }
3427
+ function decodeCursor(raw) {
3428
+ try {
3429
+ return JSON.parse(Buffer.from(raw, "base64url").toString("utf8"));
3430
+ } catch {
3431
+ return;
3432
+ }
3433
+ }
3434
+ function isBinary(buffer) {
3435
+ return buffer.subarray(0, BINARY_SNIFF_BYTES).includes(0);
3436
+ }
3437
+ /** Split into lines on LF; a trailing CR per line is presentation, not content. */
3438
+ function splitLines(text) {
3439
+ return text.split("\n").map((line) => line.endsWith("\r") ? line.slice(0, -1) : line);
3440
+ }
3441
+ function repositoryResearchToolset(options) {
3442
+ if (typeof options.root !== "string" || options.root.length === 0) throw new ConfigError("repositoryResearchToolset root must be a non-empty string");
3443
+ let realRoot;
3444
+ try {
3445
+ realRoot = realpathSync(path.resolve(options.root));
3446
+ } catch {
3447
+ throw new ConfigError(`repositoryResearchToolset root '${options.root}' does not exist`);
3448
+ }
3449
+ if (!statSync(realRoot).isDirectory()) throw new ConfigError(`repositoryResearchToolset root '${options.root}' is not a directory`);
3450
+ for (const [name, value] of [
3451
+ ["pageSize", options.pageSize],
3452
+ ["readPageChars", options.readPageChars],
3453
+ ["maxFileBytes", options.maxFileBytes],
3454
+ ["maxScannedFiles", options.maxScannedFiles]
3455
+ ]) if (value !== void 0 && (!Number.isSafeInteger(value) || value < 1)) throw new ConfigError(`repositoryResearchToolset ${name} must be a positive integer; got ${String(value)}`);
3456
+ const pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;
3457
+ const readPageChars = options.readPageChars ?? DEFAULT_READ_PAGE_CHARS;
3458
+ const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
3459
+ const maxScannedFiles = options.maxScannedFiles ?? DEFAULT_MAX_SCANNED_FILES;
3460
+ const includeHidden = options.includeHidden ?? false;
3461
+ const ignored = /* @__PURE__ */ new Set([...ALWAYS_IGNORED, ...options.ignore ?? []]);
3462
+ const evidence = [];
3463
+ /**
3464
+ * Resolves a root-relative POSIX path and confines it: absolute paths,
3465
+ * `..` escapes, and symlink escapes are error strings, never throws.
3466
+ * `mustExist` additionally resolves symlinks and re-checks containment
3467
+ * of the REAL path (the FileTranscriptStore traversal lesson).
3468
+ */
3469
+ const resolveWithin = async (rel, kind) => {
3470
+ const normalizedInput = rel.replaceAll("\\", "/");
3471
+ if (path.posix.isAbsolute(normalizedInput) || path.isAbsolute(rel)) return { error: `path must be relative to the research root; got '${rel}'` };
3472
+ const normalized = path.posix.normalize(normalizedInput);
3473
+ if (normalized === ".." || normalized.startsWith("../")) return { error: `path escapes the research root: '${rel}'` };
3474
+ const cleaned = normalized === "." ? "" : normalized;
3475
+ if (kind === "file" && cleaned === "") return { error: "path must name a file inside the research root" };
3476
+ const abs = path.resolve(realRoot, cleaned);
3477
+ let real;
3478
+ try {
3479
+ real = await realpath(abs);
3480
+ } catch {
3481
+ return { error: `no such ${kind} under the research root: '${cleaned === "" ? "." : cleaned}'` };
3482
+ }
3483
+ if (real !== realRoot && !real.startsWith(realRoot + path.sep)) return { error: `path escapes the research root: '${rel}'` };
3484
+ try {
3485
+ const info = await stat(real);
3486
+ if (kind === "file" && !info.isFile()) return { error: `not a regular file: '${cleaned}'` };
3487
+ if (kind === "dir" && !info.isDirectory()) return { error: `not a directory: '${cleaned === "" ? "." : cleaned}'` };
3488
+ } catch {
3489
+ return { error: `no such ${kind} under the research root: '${cleaned === "" ? "." : cleaned}'` };
3490
+ }
3491
+ return {
3492
+ abs: real,
3493
+ rel: cleaned
3494
+ };
3495
+ };
3496
+ /**
3497
+ * Deterministic recursive walk: sorted entries, ignored and hidden
3498
+ * names skipped, symlinks never followed, regular files only. Returns
3499
+ * root-relative POSIX paths in byte order, or an error when the walk
3500
+ * exceeds maxScannedFiles.
3501
+ */
3502
+ const walkFiles = async (absDir, relDir) => {
3503
+ const files = [];
3504
+ let visited = 0;
3505
+ const recurse = async (dirAbs, dirRel) => {
3506
+ let entries;
3507
+ try {
3508
+ entries = await readdir(dirAbs, { withFileTypes: true });
3509
+ } catch {
3510
+ return `directory disappeared during the walk: '${dirRel === "" ? "." : dirRel}'`;
3511
+ }
3512
+ const sorted = [...entries].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
3513
+ for (const entry of sorted) {
3514
+ const name = entry.name;
3515
+ if (ignored.has(name)) continue;
3516
+ if (!includeHidden && name.startsWith(".")) continue;
3517
+ const childRel = dirRel === "" ? name : `${dirRel}/${name}`;
3518
+ if (entry.isDirectory()) {
3519
+ const failure = await recurse(path.join(dirAbs, name), childRel);
3520
+ if (failure !== void 0) return failure;
3521
+ continue;
3522
+ }
3523
+ if (!entry.isFile()) continue;
3524
+ visited += 1;
3525
+ if (visited > maxScannedFiles) return `the walk exceeded maxScannedFiles (${String(maxScannedFiles)}); narrow dir or raise the limit`;
3526
+ files.push(childRel);
3527
+ }
3528
+ };
3529
+ const failure = await recurse(absDir, relDir);
3530
+ if (failure !== void 0) return { error: failure };
3531
+ return { files };
3532
+ };
3533
+ const loadTextFile = async (abs, rel) => {
3534
+ let info;
3535
+ try {
3536
+ info = await stat(abs);
3537
+ } catch {
3538
+ return { error: `no such file under the research root: '${rel}'` };
3539
+ }
3540
+ if (info.size > maxFileBytes) return { error: `file '${rel}' is ${String(info.size)} bytes, over the maxFileBytes limit (${String(maxFileBytes)})` };
3541
+ const buffer = await readFile(abs);
3542
+ if (isBinary(buffer)) return { error: `file '${rel}' is binary` };
3543
+ return { text: buffer.toString("utf8") };
3544
+ };
3545
+ return {
3546
+ tools: [
3547
+ tool({
3548
+ name: "list_files",
3549
+ description: "List files under a directory of the research root, recursively, in deterministic byte order, one page at a time. Returns { files, totalFiles, nextCursor? }; pass cursor to continue where the last page ended (the cursor is stable: unrelated changes never shift the boundary).",
3550
+ parameters: LIST_SCHEMA,
3551
+ risk: "read",
3552
+ execute: async (input) => {
3553
+ const params = input;
3554
+ let dir = params.dir ?? "";
3555
+ let after;
3556
+ if (params.cursor !== void 0) {
3557
+ const payload = decodeCursor(params.cursor);
3558
+ if (payload === void 0 || payload.t !== "list" || typeof payload.dir !== "string" || typeof payload.after !== "string" || params.dir !== void 0 && params.dir !== payload.dir) return { error: "invalid cursor: pass the nextCursor of a previous list_files page" };
3559
+ dir = payload.dir;
3560
+ after = payload.after;
3561
+ }
3562
+ const resolved = await resolveWithin(dir, "dir");
3563
+ if ("error" in resolved) return resolved;
3564
+ const walked = await walkFiles(resolved.abs, resolved.rel);
3565
+ if ("error" in walked) return walked;
3566
+ const remaining = after === void 0 ? walked.files : walked.files.filter((file) => file > after);
3567
+ const page = remaining.slice(0, pageSize);
3568
+ const more = remaining.length > pageSize;
3569
+ return {
3570
+ files: page,
3571
+ totalFiles: walked.files.length,
3572
+ ...more ? { nextCursor: encodeCursor({
3573
+ t: "list",
3574
+ dir: resolved.rel,
3575
+ after: page[page.length - 1]
3576
+ }) } : {}
3577
+ };
3578
+ }
3579
+ }),
3580
+ tool({
3581
+ name: "search_files",
3582
+ description: "Search files under the research root for a literal substring (case-sensitive, never a regex), one page of matches at a time in deterministic (path, line) order. Returns { matches: [{ file, line, text }], filesScanned, filesSkipped, nextCursor? }; binary and oversized files are skipped and counted.",
3583
+ parameters: SEARCH_SCHEMA,
3584
+ risk: "read",
3585
+ execute: async (input) => {
3586
+ const params = input;
3587
+ let dir = params.dir ?? "";
3588
+ let query = params.query;
3589
+ let after;
3590
+ if (params.cursor !== void 0) {
3591
+ const payload = decodeCursor(params.cursor);
3592
+ if (payload === void 0 || payload.t !== "search" || typeof payload.query !== "string" || typeof payload.dir !== "string" || typeof payload.file !== "string" || typeof payload.line !== "number" || payload.query !== params.query || params.dir !== void 0 && params.dir !== payload.dir) return { error: "invalid cursor: pass the nextCursor of a previous search_files page with the same query and dir" };
3593
+ dir = payload.dir;
3594
+ query = payload.query;
3595
+ after = {
3596
+ file: payload.file,
3597
+ line: payload.line
3598
+ };
3599
+ }
3600
+ if (query.length === 0) return { error: "query must be a non-empty literal substring" };
3601
+ const resolved = await resolveWithin(dir, "dir");
3602
+ if ("error" in resolved) return resolved;
3603
+ const walked = await walkFiles(resolved.abs, resolved.rel);
3604
+ if ("error" in walked) return walked;
3605
+ const matches = [];
3606
+ let filesScanned = 0;
3607
+ let filesSkipped = 0;
3608
+ for (const file of walked.files) {
3609
+ const loaded = await loadTextFile(path.join(realRoot, file), file);
3610
+ if ("error" in loaded) {
3611
+ filesSkipped += 1;
3612
+ continue;
3613
+ }
3614
+ filesScanned += 1;
3615
+ const lines = splitLines(loaded.text);
3616
+ for (let index = 0; index < lines.length; index += 1) if (lines[index].includes(query)) matches.push({
3617
+ file,
3618
+ line: index + 1,
3619
+ text: lines[index].trim().slice(0, SEARCH_SNIPPET_CHARS)
3620
+ });
3621
+ }
3622
+ const remaining = after === void 0 ? matches : matches.filter((match) => match.file > after.file || match.file === after.file && match.line > after.line);
3623
+ const page = remaining.slice(0, pageSize);
3624
+ const more = remaining.length > pageSize;
3625
+ const last = page[page.length - 1];
3626
+ return {
3627
+ matches: page,
3628
+ filesScanned,
3629
+ filesSkipped,
3630
+ ...more && last !== void 0 ? { nextCursor: encodeCursor({
3631
+ t: "search",
3632
+ query,
3633
+ dir: resolved.rel,
3634
+ file: last.file,
3635
+ line: last.line
3636
+ }) } : {}
3637
+ };
3638
+ }
3639
+ }),
3640
+ tool({
3641
+ name: "read_file",
3642
+ description: "Read a file of the research root as numbered lines, one page at a time (whole lines up to the page character budget). Returns { path, totalLines, fromLine, toLine, content, nextCursor? }; the same page reads byte-identically however it is addressed, so duplicate reads are visible to the exploration guards.",
3643
+ parameters: READ_SCHEMA,
3644
+ risk: "read",
3645
+ execute: async (input) => {
3646
+ const params = input;
3647
+ let rel = params.path;
3648
+ let fromLine = 1;
3649
+ if (params.cursor !== void 0) {
3650
+ const payload = decodeCursor(params.cursor);
3651
+ if (payload === void 0 || payload.t !== "read" || typeof payload.path !== "string" || typeof payload.after !== "number" || payload.path !== params.path) return { error: "invalid cursor: pass the nextCursor of a previous read_file page for the same path" };
3652
+ rel = payload.path;
3653
+ fromLine = payload.after + 1;
3654
+ }
3655
+ const resolved = await resolveWithin(rel, "file");
3656
+ if ("error" in resolved) return resolved;
3657
+ const loaded = await loadTextFile(resolved.abs, resolved.rel);
3658
+ if ("error" in loaded) return loaded;
3659
+ const lines = splitLines(loaded.text);
3660
+ const totalLines = lines.length;
3661
+ if (fromLine > totalLines) return { error: `fromLine ${String(fromLine)} is past the end of '${resolved.rel}' (${String(totalLines)} lines)` };
3662
+ const rendered = [];
3663
+ let used = 0;
3664
+ let toLine = fromLine - 1;
3665
+ for (let index = fromLine - 1; index < totalLines; index += 1) {
3666
+ const row = `${String(index + 1)}: ${lines[index]}`;
3667
+ if (rendered.length > 0 && used + 1 + row.length > readPageChars) break;
3668
+ rendered.push(row);
3669
+ used += (rendered.length > 1 ? 1 : 0) + row.length;
3670
+ toLine = index + 1;
3671
+ }
3672
+ const more = toLine < totalLines;
3673
+ return {
3674
+ path: resolved.rel,
3675
+ totalLines,
3676
+ fromLine,
3677
+ toLine,
3678
+ content: rendered.join("\n"),
3679
+ ...more ? { nextCursor: encodeCursor({
3680
+ t: "read",
3681
+ path: resolved.rel,
3682
+ after: toLine
3683
+ }) } : {}
3684
+ };
3685
+ }
3686
+ }),
3687
+ tool({
3688
+ name: "record_evidence",
3689
+ description: "Record one evidence entry supporting a claim. The citation is VERIFIED at record time: the file must exist under the research root, lines must be a valid 1-based line or range inside it ('12' or '12-40'), and quote (when given) must appear verbatim in the file. Returns { recorded, duplicate, totalEvidence }.",
3690
+ parameters: RECORD_EVIDENCE_SCHEMA,
3691
+ risk: "read",
3692
+ execute: async (input) => {
3693
+ const params = input;
3694
+ if (params.claim.trim().length === 0) return { error: "claim must be a non-empty string" };
3695
+ const resolved = await resolveWithin(params.file, "file");
3696
+ if ("error" in resolved) return resolved;
3697
+ const loaded = await loadTextFile(resolved.abs, resolved.rel);
3698
+ if ("error" in loaded) return loaded;
3699
+ const lines = splitLines(loaded.text);
3700
+ if (params.lines !== void 0) {
3701
+ const match = /^(\d+)(?:-(\d+))?$/u.exec(params.lines);
3702
+ if (match === null) return { error: "lines must be '12' or '12-40' (1-based)" };
3703
+ const from = Number(match[1]);
3704
+ const to = match[2] === void 0 ? from : Number(match[2]);
3705
+ if (from < 1 || to < from || to > lines.length) return { error: `lines '${params.lines}' is outside '${resolved.rel}' (${String(lines.length)} lines)` };
3706
+ }
3707
+ if (params.quote !== void 0 && !loaded.text.includes(params.quote)) return { error: `quote not found verbatim in '${resolved.rel}'; cite what the file actually says` };
3708
+ const entry = {
3709
+ claim: params.claim,
3710
+ file: resolved.rel,
3711
+ ...params.lines === void 0 ? {} : { lines: params.lines },
3712
+ ...params.quote === void 0 ? {} : { quote: params.quote }
3713
+ };
3714
+ const duplicate = evidence.some((existing) => existing.claim === entry.claim && existing.file === entry.file && existing.lines === entry.lines && existing.quote === entry.quote);
3715
+ if (!duplicate) evidence.push(entry);
3716
+ return {
3717
+ recorded: !duplicate,
3718
+ duplicate,
3719
+ totalEvidence: evidence.length
3720
+ };
3721
+ }
3722
+ }),
3723
+ tool({
3724
+ name: "list_evidence",
3725
+ description: "List the evidence recorded so far, one page at a time in record order. Returns { evidence, totalEvidence, nextCursor? }.",
3726
+ parameters: LIST_EVIDENCE_SCHEMA,
3727
+ risk: "read",
3728
+ execute: (input) => {
3729
+ const params = input;
3730
+ let from = 0;
3731
+ if (params.cursor !== void 0) {
3732
+ const payload = decodeCursor(params.cursor);
3733
+ if (payload === void 0 || payload.t !== "evidence" || typeof payload.after !== "number") return Promise.resolve({ error: "invalid cursor: pass the nextCursor of a previous list_evidence page" });
3734
+ from = payload.after;
3735
+ }
3736
+ const page = evidence.slice(from, from + pageSize);
3737
+ const more = from + pageSize < evidence.length;
3738
+ return Promise.resolve({
3739
+ evidence: page,
3740
+ totalEvidence: evidence.length,
3741
+ ...more ? { nextCursor: encodeCursor({
3742
+ t: "evidence",
3743
+ after: from + pageSize
3744
+ }) } : {}
3745
+ });
3746
+ }
3747
+ })
3748
+ ],
3749
+ evidence: () => evidence.map((entry) => ({ ...entry }))
3750
+ };
3751
+ }
3752
+ //#endregion
3300
3753
  //#region src/journal/identity.ts
3301
3754
  /**
3302
3755
  * Content-addressed entry identity (M1-T04): IdentityInput records per
@@ -13265,6 +13718,52 @@ async function executeWorkflow(internals, wf, args) {
13265
13718
  }
13266
13719
  }
13267
13720
  //#endregion
13721
+ //#region src/orchestrator/claims.ts
13722
+ /** The conservative matching key: trim plus inner-whitespace collapse. */
13723
+ function claimKey(line) {
13724
+ return line.trim().replace(/\s+/gu, " ");
13725
+ }
13726
+ /**
13727
+ * Removes later occurrences of repeated claim lines across the rows and
13728
+ * indexes each repeated claim with its reporters. Deterministic: output
13729
+ * depends only on the input order and bytes.
13730
+ */
13731
+ function dedupeRepeatedClaims(rows) {
13732
+ const seen = /* @__PURE__ */ new Map();
13733
+ const order = [];
13734
+ return {
13735
+ rows: rows.map((row) => {
13736
+ const kept = [];
13737
+ for (const line of row.text.split("\n")) {
13738
+ const key = claimKey(line);
13739
+ if (key === "") {
13740
+ kept.push(line);
13741
+ continue;
13742
+ }
13743
+ const prior = seen.get(key);
13744
+ if (prior === void 0) {
13745
+ const entry = {
13746
+ claim: line,
13747
+ nodeIds: [row.nodeId],
13748
+ count: 1
13749
+ };
13750
+ seen.set(key, entry);
13751
+ order.push(entry);
13752
+ kept.push(line);
13753
+ continue;
13754
+ }
13755
+ prior.count += 1;
13756
+ if (!prior.nodeIds.includes(row.nodeId)) prior.nodeIds.push(row.nodeId);
13757
+ }
13758
+ return {
13759
+ nodeId: row.nodeId,
13760
+ text: kept.join("\n")
13761
+ };
13762
+ }),
13763
+ repeated: order.filter((entry) => entry.count > 1)
13764
+ };
13765
+ }
13766
+ //#endregion
13268
13767
  //#region src/orchestrator/orchestrate.ts
13269
13768
  /**
13270
13769
  * The mode (c) dynamic orchestrator (M6-T07/T08).
@@ -13291,6 +13790,12 @@ const DEFAULT_FINISH_MAX_REPAIRS = 1;
13291
13790
  * call plus headroom for one validator repair exchange.
13292
13791
  */
13293
13792
  const DEFAULT_SYNTHESIS_MAX_TURNS = 4;
13793
+ /**
13794
+ * Default maxTurns of ONE incremental synthesis note (RV-211 remainder):
13795
+ * a note summarizes a single settled child into a bounded finish call,
13796
+ * so it needs less headroom than the full synthesis invocation.
13797
+ */
13798
+ const DEFAULT_SYNTHESIS_NOTE_MAX_TURNS = 2;
13294
13799
  const ORCHESTRATE_WORKFLOW_NAME = "rulvar-orchestrate";
13295
13800
  /**
13296
13801
  * One page of a string, for the child result evidence tools: maxChars is
@@ -13350,6 +13855,10 @@ function validateOrchestrateOptions(opts) {
13350
13855
  }
13351
13856
  if (opts.synthesis !== void 0) {
13352
13857
  const synthesis = opts.synthesis;
13858
+ if (synthesis.mode !== void 0 && synthesis.mode !== "single" && synthesis.mode !== "incremental") throw new ConfigError("orchestrate synthesis.mode must be 'single' or 'incremental'; got " + JSON.stringify(synthesis.mode));
13859
+ if (synthesis.mode === "incremental" && opts.finishValidation !== void 0) throw new ConfigError("orchestrate synthesis.mode 'incremental' reconciles deterministically and has no model-composed final finish for finishValidation to bind; configure validators with mode 'single', or drop them");
13860
+ if (synthesis.dedupeClaims !== void 0 && typeof synthesis.dedupeClaims !== "boolean") throw new ConfigError("orchestrate synthesis.dedupeClaims must be a boolean; got " + typeof synthesis.dedupeClaims);
13861
+ if (synthesis.noteLimits !== void 0) validateUsageLimits(synthesis.noteLimits, "orchestrate synthesis.noteLimits");
13353
13862
  if (synthesis.effort !== void 0 && ![
13354
13863
  "low",
13355
13864
  "medium",
@@ -13551,6 +14060,22 @@ function makeOrchestratorWorkflow(goal, opts) {
13551
14060
  const recoveryDone = new Promise((resolve) => {
13552
14061
  releaseRecovery = resolve;
13553
14062
  });
14063
+ /**
14064
+ * Incremental synthesis notes (RV-211 remainder): one bounded
14065
+ * synthesize-role invocation per settled child, keyed by nodeId so a
14066
+ * note can never double-dispatch. The settle hook fires the note the
14067
+ * moment its child settles (overlapping the still-running fan-out);
14068
+ * the deterministic reconciliation is the completeness backstop and
14069
+ * dispatches any note the hook missed. The dispatcher installs right
14070
+ * before the coordination loop because it closes over runtime pieces
14071
+ * built below; these bindings are declared HERE, before
14072
+ * dispatchChild, so a recovered child's settle hook (which can fire
14073
+ * during the recovery scan) never touches a binding in its temporal
14074
+ * dead zone.
14075
+ */
14076
+ const synthesisNotes = /* @__PURE__ */ new Map();
14077
+ let synthesisNoteDispatcher;
14078
+ let synthesisSettleFrozen = false;
13554
14079
  let activityChain = Promise.resolve();
13555
14080
  const childScopeOf = () => {
13556
14081
  if (orchSeq === void 0) throw new ConfigError("orchestrator dispatch seq unknown before the loop started");
@@ -13636,6 +14161,7 @@ function makeOrchestratorWorkflow(goal, opts) {
13636
14161
  };
13637
14162
  settledResult.then(async (settled) => {
13638
14163
  record.settled = settled;
14164
+ if (!synthesisSettleFrozen) synthesisNoteDispatcher?.(record);
13639
14165
  await runExtensionActivity();
13640
14166
  for (const listener of [...settleListeners]) listener();
13641
14167
  });
@@ -14425,33 +14951,198 @@ function makeOrchestratorWorkflow(goal, opts) {
14425
14951
  };
14426
14952
  };
14427
14953
  /**
14954
+ * One incremental synthesis note (RV-211 remainder): a FRESH agent
14955
+ * entry with role 'synthesize' on the finish-only toolset whose
14956
+ * prompt derives deterministically from the goal and the ONE settled
14957
+ * child's digest, so a resume replays it by identity with zero paid
14958
+ * calls. The invocation itself never throws out of here: an infra
14959
+ * failure settles as a synthesized error result and the
14960
+ * reconciliation falls back to the raw digest summary.
14961
+ */
14962
+ const runSynthesisNote = async (record) => {
14963
+ const spec = opts?.synthesis;
14964
+ const finishOnly = buildOrchestratorTools(orchestratorRuntime, fullCardText).filter((tool) => tool.name === FINISH_TOOL_NAME);
14965
+ const digest = digestOf(record, record.settled);
14966
+ const prompt = [
14967
+ "You are an incremental synthesis note of an orchestrated run. Digest the SINGLE settled child below into a self-contained note for the final deterministic reconciliation by calling finish({ result }) EXACTLY once, where result is a STRING. Preserve concrete evidence and citations; do not invent findings. No other tool exists.",
14968
+ ...spec.instructions === void 0 ? [] : [spec.instructions],
14969
+ `GOAL: ${goal}`,
14970
+ `CHILD: ${JSON.stringify(digest)}`
14971
+ ].join("\n");
14972
+ const noteState = { ...callingState };
14973
+ if (orchestratorAccount !== void 0) noteState.budgetScope = orchestratorAccount;
14974
+ const noteOpts = {
14975
+ role: "synthesize",
14976
+ result: "full",
14977
+ tools: finishOnly,
14978
+ limits: spec.noteLimits ?? { maxTurns: 2 },
14979
+ ...spec.model === void 0 ? {} : { model: spec.model },
14980
+ ...spec.effort === void 0 ? {} : { effort: spec.effort },
14981
+ ...spec.estCost === void 0 ? {} : { estCost: spec.estCost },
14982
+ [kTerminalTool]: { name: FINISH_TOOL_NAME }
14983
+ };
14984
+ return runtime.runInScope(noteState, () => ctx.agent(prompt, noteOpts));
14985
+ };
14986
+ /**
14987
+ * Note dispatch is idempotent per child: the settle hook and the
14988
+ * reconciliation both come through here, and the map guarantees one
14989
+ * dispatch per nodeId (a concurrent identical dispatch would mint a
14990
+ * second occurrence and PAY twice: the v1.32.0 lesson).
14991
+ */
14992
+ const ensureSynthesisNote = (record) => {
14993
+ const existing = synthesisNotes.get(record.nodeId);
14994
+ if (existing !== void 0) return existing;
14995
+ const note = runSynthesisNote(record).catch((thrown) => ({
14996
+ status: "error",
14997
+ output: null,
14998
+ usage: {
14999
+ inputTokens: 0,
15000
+ outputTokens: 0,
15001
+ cacheReadTokens: 0,
15002
+ cacheWriteTokens: 0
15003
+ },
15004
+ costUsd: 0,
15005
+ turns: 0,
15006
+ servedBy: "unknown:unknown",
15007
+ transcriptRef: "",
15008
+ errorMessage: thrown instanceof Error ? thrown.message : String(thrown)
15009
+ }));
15010
+ synthesisNotes.set(record.nodeId, note);
15011
+ return note;
15012
+ };
15013
+ if (opts?.synthesis?.mode === "incremental" && capDecisionRef === void 0) synthesisNoteDispatcher = ensureSynthesisNote;
15014
+ /**
15015
+ * The deterministic reconciliation of 'incremental' synthesis: the
15016
+ * final result is a PURE fold of the journaled draft and the note
15017
+ * results in spawn order, never another model call. A note that died
15018
+ * falls back to the child's raw digest summary under a journaled
15019
+ * per-child decision and a warn log. With dedupeClaims, repeated
15020
+ * claim lines keep their first occurrence and the envelope carries
15021
+ * the repeatedClaims index.
15022
+ */
15023
+ const reconcileIncremental = async (draft, spec) => {
15024
+ synthesisSettleFrozen = true;
15025
+ const settledRecords = [...records.values()].filter((record) => record.settled !== void 0).sort((a, b) => a.spawnOrdinal - b.spawnOrdinal);
15026
+ const sections = [];
15027
+ for (const record of settledRecords) {
15028
+ const settled = record.settled;
15029
+ const note = await ensureSynthesisNote(record);
15030
+ let noteText;
15031
+ if (note.status === "ok") noteText = typeof note.output === "string" ? note.output : JSON.stringify(note.output ?? null);
15032
+ else {
15033
+ const fallbackKey = deriverV2.deriveKey({
15034
+ kind: "orchestrator-synthesis-note-fallback",
15035
+ nodeId: record.nodeId
15036
+ });
15037
+ if (!internals.replayer.snapshot().some((entry) => entry.kind === "decision" && entry.key === fallbackKey)) await internals.replayer.appendSinglePhase({
15038
+ scope: callingState.scope,
15039
+ key: fallbackKey,
15040
+ kind: "decision",
15041
+ status: "ok",
15042
+ spanId: internals.spans.mint(callingState.spanId),
15043
+ site: "orchestrator-synthesis",
15044
+ value: {
15045
+ decisionType: "orchestrator_synthesis_note_fallback",
15046
+ nodeId: record.nodeId,
15047
+ status: note.status,
15048
+ turnsUsed: note.turns
15049
+ }
15050
+ });
15051
+ internals.events.emit({
15052
+ type: "log",
15053
+ level: "warn",
15054
+ msg: `the synthesis note for child '${record.nodeId}' terminated with status '${note.status}'; falling back to the raw digest summary (journaled decision 'orchestrator_synthesis_note_fallback')`
15055
+ }, callingState.spanId);
15056
+ noteText = digestOf(record, settled).outputSummary;
15057
+ }
15058
+ sections.push({
15059
+ nodeId: record.nodeId,
15060
+ logicalTaskId: record.logicalTaskId,
15061
+ status: settled.status,
15062
+ noteStatus: note.status,
15063
+ note: noteText
15064
+ });
15065
+ }
15066
+ let repeatedClaims;
15067
+ if (spec.dedupeClaims === true) {
15068
+ const deduped = dedupeRepeatedClaims(sections.map((section) => ({
15069
+ nodeId: section.nodeId,
15070
+ text: section.note
15071
+ })));
15072
+ const textByNode = new Map(deduped.rows.map((row) => [row.nodeId, row.text]));
15073
+ for (const section of sections) section.note = textByNode.get(section.nodeId) ?? section.note;
15074
+ repeatedClaims = deduped.repeated;
15075
+ }
15076
+ const draftJson = JSON.stringify(draft ?? null);
15077
+ internals.events.emit({
15078
+ type: "log",
15079
+ level: "debug",
15080
+ msg: "orchestrator synthesis reconciliation",
15081
+ data: {
15082
+ children: sections.length,
15083
+ draftChars: draftJson.length,
15084
+ notesChars: sections.reduce((sum, section) => sum + section.note.length, 0),
15085
+ perChild: sections.map((section) => ({
15086
+ nodeId: section.nodeId,
15087
+ chars: section.note.length
15088
+ })),
15089
+ ...repeatedClaims === void 0 ? {} : { repeatedClaims: repeatedClaims.length }
15090
+ }
15091
+ }, callingState.spanId);
15092
+ return {
15093
+ synthesis: "incremental",
15094
+ draft,
15095
+ sections,
15096
+ ...repeatedClaims === void 0 ? {} : { repeatedClaims }
15097
+ };
15098
+ };
15099
+ /**
14428
15100
  * The post-fan-in synthesis invocation (RV-211): a FRESH agent entry
14429
15101
  * with role 'synthesize' on the finish-only toolset (a distinct
14430
15102
  * toolsetHash, the reserved-finalizer precedent), its prompt derived
14431
15103
  * deterministically from the goal, the journaled coordination draft,
14432
15104
  * and the settled child digest, so a resume replays it by identity
14433
15105
  * with zero paid calls. Runs strictly AFTER the acceptance verdict
14434
- * (a rejected run never pays for synthesis) and owns the finish
14435
- * validators when they are configured. Failure posture: with
14436
- * validators the run fails typed (the validated path is mandatory);
14437
- * without them the run falls back to the draft under a journaled
14438
- * decision and a warn log, never silently.
15106
+ * (a rejected run never pays for synthesis; in 'incremental' mode
15107
+ * the per-child notes are paid DURING the run, so only the
15108
+ * reconciliation itself is deferred) and owns the finish validators
15109
+ * when they are configured. Failure posture: with validators the run
15110
+ * fails typed (the validated path is mandatory); without them the
15111
+ * run falls back to the draft under a journaled decision and a warn
15112
+ * log, never silently.
14439
15113
  */
14440
15114
  const runSynthesis = async (draft) => {
14441
15115
  const spec = opts?.synthesis;
14442
15116
  if (spec === void 0) return draft;
14443
15117
  await recoveryDone;
15118
+ if (spec.mode === "incremental") return await reconcileIncremental(draft, spec);
14444
15119
  const finishOnly = buildOrchestratorTools(orchestratorRuntime, fullCardText).filter((tool) => tool.name === FINISH_TOOL_NAME);
14445
15120
  const settledDigests = [...records.values()].filter((record) => record.settled !== void 0).sort((a, b) => a.spawnOrdinal - b.spawnOrdinal).map((record) => digestOf(record, record.settled));
15121
+ let digestRows = settledDigests;
15122
+ let repeatedClaims;
15123
+ if (spec.dedupeClaims === true) {
15124
+ const deduped = dedupeRepeatedClaims(settledDigests.map((row) => ({
15125
+ nodeId: row.nodeId,
15126
+ text: row.outputSummary
15127
+ })));
15128
+ const textByNode = new Map(deduped.rows.map((row) => [row.nodeId, row.text]));
15129
+ digestRows = settledDigests.map((row) => ({
15130
+ ...row,
15131
+ outputSummary: textByNode.get(row.nodeId) ?? row.outputSummary
15132
+ }));
15133
+ repeatedClaims = deduped.repeated;
15134
+ }
14446
15135
  const draftJson = JSON.stringify(draft ?? null);
14447
- const digestJson = JSON.stringify(settledDigests);
15136
+ const digestJson = JSON.stringify(digestRows);
14448
15137
  const prompt = [
14449
15138
  "You are the synthesis invocation of an orchestrated run. Compose the FINAL result of the run from the goal, the coordination draft, and the settled child evidence below by calling finish({ result }) EXACTLY once. Preserve the evidence and citations the draft relies on; do not invent findings. No other tool exists.",
15139
+ ...repeatedClaims === void 0 ? [] : ["Repeated claims across children were deduplicated before this prompt: only the first occurrence of each repeated line remains in the digest, and the REPEATED CLAIMS index below lists each one with its reporters."],
14450
15140
  ...spec.instructions === void 0 ? [] : [spec.instructions],
14451
15141
  ...finishValidationPromptLines(validationSpec),
14452
15142
  `GOAL: ${goal}`,
14453
15143
  `DRAFT: ${draftJson}`,
14454
- `DIGEST: ${digestJson}`
15144
+ `DIGEST: ${digestJson}`,
15145
+ ...repeatedClaims === void 0 ? [] : [`REPEATED CLAIMS: ${JSON.stringify(repeatedClaims)}`]
14455
15146
  ].join("\n");
14456
15147
  internals.events.emit({
14457
15148
  type: "log",
@@ -14462,10 +15153,11 @@ function makeOrchestratorWorkflow(goal, opts) {
14462
15153
  draftChars: draftJson.length,
14463
15154
  digestChars: digestJson.length,
14464
15155
  promptChars: prompt.length,
14465
- perChild: settledDigests.map((entry) => ({
15156
+ perChild: digestRows.map((entry) => ({
14466
15157
  nodeId: entry.nodeId,
14467
15158
  chars: JSON.stringify(entry).length
14468
- }))
15159
+ })),
15160
+ ...repeatedClaims === void 0 ? {} : { repeatedClaims: repeatedClaims.length }
14469
15161
  }
14470
15162
  }, callingState.spanId);
14471
15163
  const synthesisState = { ...callingState };
@@ -14586,6 +15278,7 @@ function makeOrchestratorWorkflow(goal, opts) {
14586
15278
  const required = decision.childPolicy === "all-ok" ? "every child ok" : `at least ${String(decision.childPolicy.minSuccessful)} children ok`;
14587
15279
  throw new FailRunError(`the orchestrator acceptance policy rejected the finish: ${String(decision.childStatusCounts.ok ?? 0)} children settled 'ok' but the policy requires ${required}; degraded: ${decision.degradedReasons.join("; ")}`, { data: {
14588
15280
  source: "orchestrator_acceptance",
15281
+ completion: "rejected",
14589
15282
  childPolicy: decision.childPolicy,
14590
15283
  childStatusCounts: decision.childStatusCounts,
14591
15284
  degradedReasons: decision.degradedReasons
@@ -15243,6 +15936,32 @@ function workflowSourceRef(runId) {
15243
15936
  return `${runId}/workflow-source`;
15244
15937
  }
15245
15938
  /**
15939
+ * The completion envelope contract (RV-207 tail): a workflow reports
15940
+ * SEMANTIC completion by returning an object result carrying a
15941
+ * `completion` literal (and optionally `childStatusCounts`), or by
15942
+ * throwing a typed RulvarError whose `data` carries them; the engine
15943
+ * lifts the validated fields onto the `run:end` event so telemetry
15944
+ * consumers read completeness without parsing workflow-specific result
15945
+ * shapes. The orchestrator acceptance path emits this envelope. Pure
15946
+ * shape validation: anything malformed is silently absent (the event is
15947
+ * telemetry, never authority), and an invalid counts record drops the
15948
+ * counts while keeping a valid completion.
15949
+ */
15950
+ function liftRunCompletion(candidate) {
15951
+ if (typeof candidate !== "object" || candidate === null || Array.isArray(candidate)) return;
15952
+ const completion = candidate.completion;
15953
+ if (completion !== "complete" && completion !== "partial" && completion !== "rejected") return;
15954
+ const counts = candidate.childStatusCounts;
15955
+ if (typeof counts === "object" && counts !== null && !Array.isArray(counts)) {
15956
+ const entries = Object.entries(counts);
15957
+ if (entries.every(([, value]) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0)) return {
15958
+ completion,
15959
+ childStatusCounts: Object.fromEntries(entries)
15960
+ };
15961
+ }
15962
+ return { completion };
15963
+ }
15964
+ /**
15246
15965
  * sha256 hex over the JCS canonical serialization of a run's args: the
15247
15966
  * value the engine records as `RunMeta.argsHash` at genesis, exposed so
15248
15967
  * hosts can verify re-supplied resume args against the recorded hash
@@ -15613,11 +16332,13 @@ function createEngine(options) {
15613
16332
  }
15614
16333
  }
15615
16334
  await putMeta(status).catch(() => void 0);
16335
+ const lifted = liftRunCompletion(status === "ok" || status === "exhausted" ? outcome.value : status === "error" ? wireError?.data : void 0);
15616
16336
  bus.emit({
15617
16337
  type: "run:end",
15618
16338
  status,
15619
16339
  totalUsd: ledger.usd,
15620
- ...outcome.cost.usageApprox === true ? { usageApprox: true } : {}
16340
+ ...outcome.cost.usageApprox === true ? { usageApprox: true } : {},
16341
+ ...lifted === void 0 ? {} : lifted
15621
16342
  }, rootSpanId);
15622
16343
  bus.end();
15623
16344
  resumeCtx?.previewResolve({
@@ -16089,4 +16810,4 @@ function createSandboxBridge(ctx, options) {
16089
16810
  };
16090
16811
  }
16091
16812
  //#endregion
16092
- 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_CHILD_RESULT_PAGE_CHARS, DEFAULT_CITATION_PATTERN, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_EVIDENCE_MIN_SHARE, DEFAULT_FINISH_MAX_REPAIRS, 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, DEFAULT_SYNTHESIS_MAX_TURNS, DedupIndex, DeterminismError, 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, GET_CHILD_RESULT_SCHEMA, GET_CHILD_RESULT_TOOL_NAME, 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_CHILD_RESULT_PAGE_CHARS, MAX_DEPTH_CEILING, ModelRetry, NoProgressDetector, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OrchestratorCapConfigError, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, PlanInvariantError, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RUN_SETTLE_DECISION_TYPE, 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, assertFencedWrites, atCompactionThreshold, auditRun, auditRuns, 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, evidencePreservedValidator, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hasFencedWrites, hasMetaLookup, hashRunArgs, hashRunOutput, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lastRunSettle, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, metaMatchesFilter, minMatchesValidator, 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, reconcileRunMeta, reduceCriticalPath, reduceInvocationTable, registryKeyRing, remeasureQueue, replayDisposition, requiredFieldsValidator, requiredSectionsValidator, 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 };
16813
+ 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_CHILD_RESULT_PAGE_CHARS, DEFAULT_CITATION_PATTERN, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_EVIDENCE_MIN_SHARE, DEFAULT_FINISH_MAX_REPAIRS, 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, DEFAULT_SYNTHESIS_MAX_TURNS, DEFAULT_SYNTHESIS_NOTE_MAX_TURNS, DedupIndex, DeterminismError, 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, GET_CHILD_RESULT_SCHEMA, GET_CHILD_RESULT_TOOL_NAME, 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_CHILD_RESULT_PAGE_CHARS, MAX_DEPTH_CEILING, ModelRetry, NoProgressDetector, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OrchestratorCapConfigError, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, PlanInvariantError, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RUN_SETTLE_DECISION_TYPE, 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, assertFencedWrites, atCompactionThreshold, auditRun, auditRuns, 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, dedupeRepeatedClaims, defineWorkflow, deriveContentKey, deriverV1, deriverV2, digestOf, dispositionHook, emptyDigestBlocks, emptyToolset, encodeCheckpoint, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, evidencePreservedValidator, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hasFencedWrites, hasMetaLookup, hashRunArgs, hashRunOutput, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lastRunSettle, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, metaMatchesFilter, minMatchesValidator, 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, reconcileRunMeta, reduceCriticalPath, reduceInvocationTable, registryKeyRing, remeasureQueue, replayDisposition, repositoryResearchToolset, requiredFieldsValidator, requiredSectionsValidator, 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.53.0",
3
+ "version": "1.54.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",