@rulvar/core 1.108.0 → 1.110.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
@@ -3713,6 +3713,18 @@ interface ToolBudgetSummary {
3713
3713
  limiter?: "maxToolCalls" | "toolUnits";
3714
3714
  }
3715
3715
  /**
3716
+ * How an event's `costUsd` was folded (RV702). `'per-call'`: the sum of
3717
+ * each provider request priced individually, the same basis the settled
3718
+ * CostReport and invoice use (RV504), so a nonlinear long-context tier
3719
+ * fires per REQUEST. `'aggregate-estimate'`: the aggregate usage priced
3720
+ * in one call, which a tier can inflate past what any single request
3721
+ * cost; emitted only when per-request records cannot cover the number
3722
+ * (a checkpoint written before the reconciliation ledger shipped, or a
3723
+ * terminal entry whose records do not cover its usage). An absent field
3724
+ * on an event stream recorded before RV702 means the aggregate basis.
3725
+ */
3726
+ type CostBasis = "per-call" | "aggregate-estimate";
3727
+ /**
3716
3728
  * Agent lifecycle. One logical agent dispatch emits EXACTLY ONE
3717
3729
  * `agent:start`/`agent:end` pair on its span (the start carries the
3718
3730
  * primary role), and each model invocation phase inside the span
@@ -3762,6 +3774,14 @@ type AgentEvents = {
3762
3774
  durationMs: number; /** The usage this activation added to its (role, model) slices. */
3763
3775
  usage: Usage; /** That usage priced at each serving model's own rate. */
3764
3776
  costUsd: number;
3777
+ /**
3778
+ * The fold behind `costUsd` (RV702). Live phase deltas are always
3779
+ * per-call (every slice a live activation adds is backed by a
3780
+ * recorded provider call); a replayed pair says 'aggregate-estimate'
3781
+ * exactly when its model's records do not cover its usage. Absent
3782
+ * on streams recorded before RV702, which priced the aggregate.
3783
+ */
3784
+ costBasis?: CostBasis;
3765
3785
  outcome: "ok" | "error";
3766
3786
  /**
3767
3787
  * Transport retries inside this activation. Present only when
@@ -3775,6 +3795,16 @@ type AgentEvents = {
3775
3795
  status: string;
3776
3796
  usage: Usage;
3777
3797
  costUsd: number;
3798
+ /**
3799
+ * The fold behind `costUsd` (RV702): 'per-call' when every usage
3800
+ * slice of the invocation (restored included) is covered by
3801
+ * per-request records priced individually, the settled fold's own
3802
+ * basis; 'aggregate-estimate' when it is not (the aggregate number
3803
+ * is kept so restored spend is never silently dropped, and labeled
3804
+ * so it is never mistaken for the per-request fold). Absent on
3805
+ * streams recorded before RV702, which priced the aggregate.
3806
+ */
3807
+ costBasis?: CostBasis;
3778
3808
  entryRef: number;
3779
3809
  /**
3780
3810
  * Present and true when this agent's usage is approximate rather
@@ -4376,6 +4406,15 @@ interface AgentResult<T> {
4376
4406
  output: T | null;
4377
4407
  usage: Usage;
4378
4408
  costUsd: number;
4409
+ /**
4410
+ * The fold behind `costUsd` (RV702): 'per-call' when every usage
4411
+ * slice (restored included) is covered by per-request records priced
4412
+ * individually, exactly the settled fold's basis; 'aggregate-estimate'
4413
+ * when a restored checkpoint left usage no record backs, in which case
4414
+ * the aggregate-priced number is kept (never silently dropped) and
4415
+ * labeled.
4416
+ */
4417
+ costBasis: CostBasis;
4379
4418
  turns: number;
4380
4419
  /**
4381
4420
  * The model that actually served the loop phase at the end (M4-T04):
@@ -5973,7 +6012,11 @@ declare class AdmissionController {
5973
6012
  * Folds the per-run attribution buckets into the normative CostReport.
5974
6013
  * Live attribution buckets never see abandoned subtrees, so a host
5975
6014
  * that tracked abandoned spend itself passes it as `abandoned`;
5976
- * omitted, the report shows a gross equal to the net.
6015
+ * omitted, the report shows a gross equal to the net. Non-finite
6016
+ * numbers anywhere in the inputs are a typed refusal (RV705): this
6017
+ * exported builder is the same public surface as
6018
+ * {@link costReportFromJournal} and holds the same RV610 doctrine,
6019
+ * instead of letting an Infinity or NaN serialize into null downstream.
5977
6020
  */
5978
6021
  declare function buildCostReport(attribution: CostAttribution, totalUsd: number, abandoned?: CostReport["abandoned"]): CostReport;
5979
6022
  /**
@@ -9430,6 +9473,13 @@ declare class JsonlFileStore implements MetaLookupStore {
9430
9473
  private metaPath;
9431
9474
  append(runId: string, e: JournalEntry): Promise<void>;
9432
9475
  load(runId: string): Promise<JournalEntry[]>;
9476
+ /**
9477
+ * Restores the trailing '\n' of a parseable-but-unterminated tail
9478
+ * (RV701). One byte appended in place terminates the record exactly
9479
+ * where the crash left it; the file's bytes before it stay untouched.
9480
+ * No-op on a missing, empty, or already-terminated journal.
9481
+ */
9482
+ private terminateUnterminatedTail;
9433
9483
  private repairTornTail;
9434
9484
  putMeta(m: RunMeta): Promise<void>;
9435
9485
  getMeta(runId: string): Promise<RunMeta | undefined>;
@@ -10399,6 +10449,12 @@ interface PhaseRow {
10399
10449
  durationMs: number;
10400
10450
  usage: Usage;
10401
10451
  costUsd: number;
10452
+ /**
10453
+ * The fold behind `costUsd` (RV702). An event stream recorded before
10454
+ * the field shipped priced aggregates, so an absent field reduces to
10455
+ * 'aggregate-estimate', never to a per-call claim it cannot back.
10456
+ */
10457
+ costBasis: CostBasis;
10402
10458
  outcome?: "ok" | "error";
10403
10459
  retries: number;
10404
10460
  replayed: boolean;
@@ -10416,6 +10472,12 @@ interface AgentInvocationRow {
10416
10472
  status?: string;
10417
10473
  usage: Usage;
10418
10474
  costUsd: number;
10475
+ /**
10476
+ * The fold behind `costUsd` (RV702), from the span's agent:end; an
10477
+ * absent field (a pre-RV702 stream, or a span still open) reduces to
10478
+ * 'aggregate-estimate', never to a per-call claim it cannot back.
10479
+ */
10480
+ costBasis: CostBasis;
10419
10481
  usageApprox: boolean;
10420
10482
  retryCount: number;
10421
10483
  /**
@@ -10431,10 +10493,15 @@ interface AgentInvocationRow {
10431
10493
  /** The reduced table plus the per-role aggregate across every span. */
10432
10494
  interface InvocationTable {
10433
10495
  agents: AgentInvocationRow[];
10434
- /** Aggregated over COMPLETED phase pairs, keyed by role. */
10496
+ /**
10497
+ * Aggregated over COMPLETED phase pairs, keyed by role. The bucket's
10498
+ * `costBasis` is 'per-call' only while EVERY folded pair carried the
10499
+ * per-call basis; one aggregate-estimate pair degrades the bucket.
10500
+ */
10435
10501
  byRole: Record<string, {
10436
10502
  usage: Usage;
10437
10503
  costUsd: number;
10504
+ costBasis: CostBasis;
10438
10505
  }>;
10439
10506
  /** Sum of agent:end costUsd over settled spans. */
10440
10507
  totalCostUsd: number;
@@ -10546,4 +10613,4 @@ interface SandboxBridge {
10546
10613
  declare const SANDBOX_AGENT_OPT_KEYS: readonly string[];
10547
10614
  declare function createSandboxBridge(ctx: Ctx<never>, options: SandboxBridgeOptions): SandboxBridge;
10548
10615
  //#endregion
10549
- 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, AgentProfileTemplateOptions, AgentResult, AgentResultMeta, AgentStatus, type AppliedPricingRow, ApproachSignatureInputs, ApprovalDecision, ApprovalIdentityInput, Artifact, AttemptOutcomeClass, AuditCategory, AuditRecord, 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_CITATION_SAMPLE, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_EVIDENCE_CALLS_PER_ENTRY, DEFAULT_EVIDENCE_MIN_SHARE, DEFAULT_EVIDENCE_OVERHEAD_CALLS, 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, DataKeyProvider, 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, EngineQuotaConfig, EngineQuotaRuntime, EntryBillingFold, EntryBillingUnit, EntryKind, EntryRef, EntryStatus, EnvelopeEncryption, EnvelopeEncryptionOptions, ErrorClass, ErrorCode, ErrorPolicy, EscalatedResult, EscalationDecision, EscalationDecisionAbortedError, EscalationDigest, EscalationKind, EscalationLimits, EscalationOptions, EscalationReport, EscalationRequest, EventBus, EvidenceContract, type EvidenceRef, type ExecKeyDerivation, type ExecutorRegistry, type ExplorationSummary, ExtensionAppendInput, ExtensionDispatchSpec, ExternalIdentityInput, ExternalRegistry, ExtractNecessityInput, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FailRunError, FailoverTarget, FailoverTrigger, FallbackField, FallbackTrigger, FencedCodeMode, FileModelKnowledgeStore, FileModelKnowledgeStoreOptions, FileTranscriptStore, type FinalizationWindowBudget, FinishContract, FinishContractCitations, FinishContractGoldenReject, FinishContractManifest, FinishInfo, FinishSelfTestFailure, FinishSelfTestFixtures, FinishSelfTestReport, FinishValidationChild, FinishValidationInput, FinishValidationSpec, FinishValidationVerdict, FinishValidator, GET_CHILD_RESULT_SCHEMA, GET_CHILD_RESULT_TOOL_NAME, Gate, GateAudit, type GateRecord, GitWorktreeProvider, GitWorktreeProviderOptions, GraftBoot, HashVersion, HookVerdict, IMPLEMENTATION_PROFILE_LIMITS, INBOX_PROPOSAL_TTL_DAYS, IdentityInput, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, IncrementalSynthesisResult, InvalidResolutionError, InvocationRole, type InvocationTable, InvoiceExport, InvoicePricingProvenance, InvoiceReconciliation, InvoiceRow, type IsolatedExecContext, type IsolatedExecRequest, type IsolatedExecutorTag, type IsolationProvider, type IsolationSpec, Issue$1 as Issue, JOURNAL_ENVELOPE_MARKER, JournalCompatSubCode, JournalCompatibilityError, JournalEntry, JournalMatcher, JournalMissError, JournalOperation, JournalOrderViolation, type JournalPricingSnapshot, JournalSerializationContext, 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, MAX_TIMER_DELAY_MS, MatchResult, McpConfig, McpToolSource, MechanicalGateProfile, MechanicalGateVerdict, MemoryQuotaLimiter, 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, OrchestrateSynthesisSkipReason, OrchestratorBudgetSpec, OrchestratorCapConfigError, OrchestratorExtension, OrchestratorExtensionIO, OrchestratorRuntime, Out, PARALLEL_AGENTS_SCHEMA, PROGRESS_REPORT_TOOL_NAME, ParallelSiteCounter, Part, PendingExternal, PendingToolTurn, PermissionConfig, PermissionGate, PermissionHook, PermissionPreset, PermissionRule, PermissionVerdict, type PhaseRow, PhaseTarget, type PinnedPricingSegment, PipelineCollected, PipelineOpts, PlanInvariantError, PreflightAdmissionRow, PreflightFinding, PreflightInput, PreflightOrchestratorSpec, PreflightReport, PreflightSpawnReport, PreflightSpawnSpec, PreflightToolCeiling, PriceTable, PricedUsage, type Pricing, type PricingTier, ProgressReport, type ProviderAdapter, ProviderCallRecord, QUOTA_WINDOW_MS, QualityFloors, QuotaCounters, type QuotaDecision, type QuotaEstimate, type QuotaLimiter, type QuotaReservationRequest, QuotaRule, QuotaWindowSnapshot, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, RESEARCH_PROFILE_LIMITS, REVIEW_PROFILE_LIMITS, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RUN_SETTLE_DECISION_TYPE, RandIdentityInput, RandPayload, RateLimitObservation, ReconcileOptions, ReconcileResult, RefEntryAppender, RefEntryClassification, RefusalInfo, RepeatedClaim, ReplayDisposition, ReplayMode, ReplayPlanHashMismatch, Replayer, RepositoryResearchToolset, RepositoryResearchToolsetOptions, ResearchAgentProfileOptions, ResearchAgentProfileResult, 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, RunExport, 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, SecretMasker, SectionMatchMode, Semaphore, SerializationHook, Settled, SettlementError, 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, type ToolBudgetSummary, ToolCallRequest, ToolChoice, type ToolContext, ToolContextSeed, ToolContract, type ToolDef, type ToolEvents, type ToolExecutor, type ToolExecutorProvider, 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, compileSecretMasker, compileVerifiedLayer, constantTimeEqual, costReportFromJournal, countsAgainstLimit, createCanonicalIdMinter, createCtx, createEngine, createEnvelopeEncryption, createSandboxBridge, currentOnlyKeyRing, decodeCheckpoint, dedupeRepeatedClaims, defineWorkflow, deriveContentKey, deriverV1, deriverV2, digestOf, dispatchProjectionReserveUsd, dispositionHook, emptyDigestBlocks, emptyToolset, encodeCheckpoint, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, evidencePreservedValidator, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, finishContract, foldTermination, formatRePrompt, formatScopePath, hasFencedWrites, hasMetaLookup, hashRunArgs, hashRunOutput, hashWorkflowBody, hashWorkflowSource, headingStructureValidator, identityJcs, implementationAgentProfile, invoiceFromJournal, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, journalPricingSnapshot, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lastRunSettle, latestProgressReport, lexShellCommand, liftRetainedParts, lineageWeightOf, localKeyProvider, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, memoryQuotaLimiter, mergeQuotaDenial, mergeUsageLimits, metaMatchesFilter, minMatchesValidator, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, orchestratorAdmissionEstCostUsd, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, preflightEstimate, priceEntryBilling, priceEntryUsage, priceUsdOf, profileCard, profileRegistrySnapshotHash, progressReportTool, projectHistory, projectIdentity, projectToJsonSchema, proposalStatement, providerOf, quotaActualTokens, quotaEstimateTokens, quotaRuleAdmission, quotaRuleKey, quotaRuleMatches, readRunMeta, readTerminationInit, reconcileRunMeta, reduceAuditTrail, reduceCriticalPath, reduceInvocationTable, registryKeyRing, remeasureQueue, replayDisposition, repositoryResearchToolset, requiredFieldsValidator, requiredSectionsValidator, researchAgentProfile, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, reviewAgentProfile, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, sanitizeTerminalText, sanitizeTokenCount, sanitizeUsage, sanitizeUsageDelta, scanJournalCompatibility, schemaHash, schemaHashOfSpec, sectionCitationsValidator, selectStructuredOutputTier, selfTestFinishValidation, shouldCompact, snapshotQuotaRules, snapshotUsage, spawnDepthOf, stripFencedBlocks, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, usageViolations, validateEditorialCommit, validateEngineQuotaConfig, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateQuotaRules, validateRetryPolicy, validateSchemaSpec, validateTerminationLimits, validateUsageLimits, wordCountValidator, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
10616
+ 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, AgentProfileTemplateOptions, AgentResult, AgentResultMeta, AgentStatus, type AppliedPricingRow, ApproachSignatureInputs, ApprovalDecision, ApprovalIdentityInput, Artifact, AttemptOutcomeClass, AuditCategory, AuditRecord, 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, type CostBasis, CostReport, CreateEngineOptions, type CriticalPath, Ctx, DEFAULT_CHILD_BUDGET_FRACTION, DEFAULT_CHILD_RESULT_PAGE_CHARS, DEFAULT_CITATION_PATTERN, DEFAULT_CITATION_SAMPLE, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_EVIDENCE_CALLS_PER_ENTRY, DEFAULT_EVIDENCE_MIN_SHARE, DEFAULT_EVIDENCE_OVERHEAD_CALLS, 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, DataKeyProvider, 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, EngineQuotaConfig, EngineQuotaRuntime, EntryBillingFold, EntryBillingUnit, EntryKind, EntryRef, EntryStatus, EnvelopeEncryption, EnvelopeEncryptionOptions, ErrorClass, ErrorCode, ErrorPolicy, EscalatedResult, EscalationDecision, EscalationDecisionAbortedError, EscalationDigest, EscalationKind, EscalationLimits, EscalationOptions, EscalationReport, EscalationRequest, EventBus, EvidenceContract, type EvidenceRef, type ExecKeyDerivation, type ExecutorRegistry, type ExplorationSummary, ExtensionAppendInput, ExtensionDispatchSpec, ExternalIdentityInput, ExternalRegistry, ExtractNecessityInput, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FailRunError, FailoverTarget, FailoverTrigger, FallbackField, FallbackTrigger, FencedCodeMode, FileModelKnowledgeStore, FileModelKnowledgeStoreOptions, FileTranscriptStore, type FinalizationWindowBudget, FinishContract, FinishContractCitations, FinishContractGoldenReject, FinishContractManifest, FinishInfo, FinishSelfTestFailure, FinishSelfTestFixtures, FinishSelfTestReport, FinishValidationChild, FinishValidationInput, FinishValidationSpec, FinishValidationVerdict, FinishValidator, GET_CHILD_RESULT_SCHEMA, GET_CHILD_RESULT_TOOL_NAME, Gate, GateAudit, type GateRecord, GitWorktreeProvider, GitWorktreeProviderOptions, GraftBoot, HashVersion, HookVerdict, IMPLEMENTATION_PROFILE_LIMITS, INBOX_PROPOSAL_TTL_DAYS, IdentityInput, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, IncrementalSynthesisResult, InvalidResolutionError, InvocationRole, type InvocationTable, InvoiceExport, InvoicePricingProvenance, InvoiceReconciliation, InvoiceRow, type IsolatedExecContext, type IsolatedExecRequest, type IsolatedExecutorTag, type IsolationProvider, type IsolationSpec, Issue$1 as Issue, JOURNAL_ENVELOPE_MARKER, JournalCompatSubCode, JournalCompatibilityError, JournalEntry, JournalMatcher, JournalMissError, JournalOperation, JournalOrderViolation, type JournalPricingSnapshot, JournalSerializationContext, 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, MAX_TIMER_DELAY_MS, MatchResult, McpConfig, McpToolSource, MechanicalGateProfile, MechanicalGateVerdict, MemoryQuotaLimiter, 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, OrchestrateSynthesisSkipReason, OrchestratorBudgetSpec, OrchestratorCapConfigError, OrchestratorExtension, OrchestratorExtensionIO, OrchestratorRuntime, Out, PARALLEL_AGENTS_SCHEMA, PROGRESS_REPORT_TOOL_NAME, ParallelSiteCounter, Part, PendingExternal, PendingToolTurn, PermissionConfig, PermissionGate, PermissionHook, PermissionPreset, PermissionRule, PermissionVerdict, type PhaseRow, PhaseTarget, type PinnedPricingSegment, PipelineCollected, PipelineOpts, PlanInvariantError, PreflightAdmissionRow, PreflightFinding, PreflightInput, PreflightOrchestratorSpec, PreflightReport, PreflightSpawnReport, PreflightSpawnSpec, PreflightToolCeiling, PriceTable, PricedUsage, type Pricing, type PricingTier, ProgressReport, type ProviderAdapter, ProviderCallRecord, QUOTA_WINDOW_MS, QualityFloors, QuotaCounters, type QuotaDecision, type QuotaEstimate, type QuotaLimiter, type QuotaReservationRequest, QuotaRule, QuotaWindowSnapshot, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, RESEARCH_PROFILE_LIMITS, REVIEW_PROFILE_LIMITS, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RUN_SETTLE_DECISION_TYPE, RandIdentityInput, RandPayload, RateLimitObservation, ReconcileOptions, ReconcileResult, RefEntryAppender, RefEntryClassification, RefusalInfo, RepeatedClaim, ReplayDisposition, ReplayMode, ReplayPlanHashMismatch, Replayer, RepositoryResearchToolset, RepositoryResearchToolsetOptions, ResearchAgentProfileOptions, ResearchAgentProfileResult, 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, RunExport, 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, SecretMasker, SectionMatchMode, Semaphore, SerializationHook, Settled, SettlementError, 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, type ToolBudgetSummary, ToolCallRequest, ToolChoice, type ToolContext, ToolContextSeed, ToolContract, type ToolDef, type ToolEvents, type ToolExecutor, type ToolExecutorProvider, 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, compileSecretMasker, compileVerifiedLayer, constantTimeEqual, costReportFromJournal, countsAgainstLimit, createCanonicalIdMinter, createCtx, createEngine, createEnvelopeEncryption, createSandboxBridge, currentOnlyKeyRing, decodeCheckpoint, dedupeRepeatedClaims, defineWorkflow, deriveContentKey, deriverV1, deriverV2, digestOf, dispatchProjectionReserveUsd, dispositionHook, emptyDigestBlocks, emptyToolset, encodeCheckpoint, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, evidencePreservedValidator, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, finishContract, foldTermination, formatRePrompt, formatScopePath, hasFencedWrites, hasMetaLookup, hashRunArgs, hashRunOutput, hashWorkflowBody, hashWorkflowSource, headingStructureValidator, identityJcs, implementationAgentProfile, invoiceFromJournal, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, journalPricingSnapshot, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lastRunSettle, latestProgressReport, lexShellCommand, liftRetainedParts, lineageWeightOf, localKeyProvider, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, memoryQuotaLimiter, mergeQuotaDenial, mergeUsageLimits, metaMatchesFilter, minMatchesValidator, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, orchestratorAdmissionEstCostUsd, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, preflightEstimate, priceEntryBilling, priceEntryUsage, priceUsdOf, profileCard, profileRegistrySnapshotHash, progressReportTool, projectHistory, projectIdentity, projectToJsonSchema, proposalStatement, providerOf, quotaActualTokens, quotaEstimateTokens, quotaRuleAdmission, quotaRuleKey, quotaRuleMatches, readRunMeta, readTerminationInit, reconcileRunMeta, reduceAuditTrail, reduceCriticalPath, reduceInvocationTable, registryKeyRing, remeasureQueue, replayDisposition, repositoryResearchToolset, requiredFieldsValidator, requiredSectionsValidator, researchAgentProfile, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, reviewAgentProfile, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, sanitizeTerminalText, sanitizeTokenCount, sanitizeUsage, sanitizeUsageDelta, scanJournalCompatibility, schemaHash, schemaHashOfSpec, sectionCitationsValidator, selectStructuredOutputTier, selfTestFinishValidation, shouldCompact, snapshotQuotaRules, snapshotUsage, spawnDepthOf, stripFencedBlocks, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, usageViolations, validateEditorialCommit, validateEngineQuotaConfig, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateQuotaRules, validateRetryPolicy, validateSchemaSpec, validateTerminationLimits, validateUsageLimits, wordCountValidator, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createCipheriv, createDecipheriv, createHash, createHmac, getRandomValues, hkdfSync, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
2
- import { appendFileSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
2
+ import { appendFileSync, closeSync, fstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
3
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";
@@ -8080,7 +8080,13 @@ async function reconcileRunMeta(store, runId, opts) {
8080
8080
  *
8081
8081
  * Contract (DEF-4 tightening):
8082
8082
  * - A1 atomicity: a torn trailing line (crash mid-append) is never
8083
- * visible in load; it is dropped and overwritten by the next append.
8083
+ * visible in load; the incomplete fragment is dropped and overwritten
8084
+ * by the next append. Whole records on that line are data, never
8085
+ * fragment (RV701): a crash that persisted every JSON byte but not
8086
+ * the '\n' leaves a parseable tail that load serves and append
8087
+ * terminates before writing, and repair salvages complete records a
8088
+ * glued line carries instead of discarding the line, so an entry a
8089
+ * load has served can never be un-served by a later repair.
8084
8090
  * - A2 total per-run order: load returns append order, stable across
8085
8091
  * calls (the kernel's per-run queue serializes appends).
8086
8092
  * - A3 read-your-writes: append resolves after the line is written.
@@ -8097,6 +8103,62 @@ function safeName(runId) {
8097
8103
  if (!/^[A-Za-z0-9._-]+$/.test(runId)) throw new JournalOrderViolation(`JsonlFileStore: runId '${runId}' is not filesystem-safe ([A-Za-z0-9._-] only)`);
8098
8104
  return runId;
8099
8105
  }
8106
+ /**
8107
+ * Whole JSON values glued on one line, split apart without parser
8108
+ * ambiguity (RV701): depth is tracked outside string literals only, and
8109
+ * every candidate must still round-trip JSON.parse. A line that is not a
8110
+ * clean concatenation from its first byte salvages its whole prefix
8111
+ * values and returns everything after them as the torn fragment, so the
8112
+ * caller keeps accepted records and drops exactly the unacknowledged
8113
+ * tail a crash tore.
8114
+ */
8115
+ function splitConcatenatedJson(line) {
8116
+ const whole = [];
8117
+ let start = 0;
8118
+ let depth = 0;
8119
+ let inString = false;
8120
+ let escaped = false;
8121
+ for (let i = 0; i < line.length; i += 1) {
8122
+ const ch = line[i];
8123
+ if (inString) {
8124
+ if (escaped) escaped = false;
8125
+ else if (ch === "\\") escaped = true;
8126
+ else if (ch === "\"") inString = false;
8127
+ continue;
8128
+ }
8129
+ if (ch === "\"") {
8130
+ inString = true;
8131
+ continue;
8132
+ }
8133
+ if (ch === "{" || ch === "[") {
8134
+ depth += 1;
8135
+ continue;
8136
+ }
8137
+ if (ch === "}" || ch === "]") {
8138
+ depth -= 1;
8139
+ if (depth < 0) return {
8140
+ whole,
8141
+ fragment: line.slice(start)
8142
+ };
8143
+ if (depth === 0) {
8144
+ const candidate = line.slice(start, i + 1);
8145
+ try {
8146
+ whole.push(JSON.parse(candidate));
8147
+ } catch {
8148
+ return {
8149
+ whole,
8150
+ fragment: line.slice(start)
8151
+ };
8152
+ }
8153
+ start = i + 1;
8154
+ }
8155
+ }
8156
+ }
8157
+ return {
8158
+ whole,
8159
+ fragment: line.slice(start)
8160
+ };
8161
+ }
8100
8162
  var JsonlFileStore = class {
8101
8163
  dir;
8102
8164
  /**
@@ -8119,6 +8181,7 @@ var JsonlFileStore = class {
8119
8181
  let tail = this.lastSeq.get(runId);
8120
8182
  if (tail === void 0) {
8121
8183
  const existing = await this.load(runId);
8184
+ this.terminateUnterminatedTail(runId);
8122
8185
  const last = existing[existing.length - 1];
8123
8186
  tail = last !== void 0 && Number.isFinite(last.seq) ? last.seq : Number.NEGATIVE_INFINITY;
8124
8187
  this.lastSeq.set(runId, tail);
@@ -8144,6 +8207,7 @@ var JsonlFileStore = class {
8144
8207
  entries.push(JSON.parse(line));
8145
8208
  } catch (thrown) {
8146
8209
  if (lines.slice(i + 1).every((rest) => rest === "")) {
8210
+ for (const value of splitConcatenatedJson(line).whole) entries.push(value);
8147
8211
  this.repairTornTail(runId, entries);
8148
8212
  break;
8149
8213
  }
@@ -8152,6 +8216,34 @@ var JsonlFileStore = class {
8152
8216
  }
8153
8217
  return entries;
8154
8218
  }
8219
+ /**
8220
+ * Restores the trailing '\n' of a parseable-but-unterminated tail
8221
+ * (RV701). One byte appended in place terminates the record exactly
8222
+ * where the crash left it; the file's bytes before it stay untouched.
8223
+ * No-op on a missing, empty, or already-terminated journal.
8224
+ */
8225
+ terminateUnterminatedTail(runId) {
8226
+ const path = this.journalPath(runId);
8227
+ let fd;
8228
+ try {
8229
+ fd = openSync(path, "r");
8230
+ } catch (thrown) {
8231
+ if (thrown.code === "ENOENT") return;
8232
+ throw thrown;
8233
+ }
8234
+ let needsNewline = false;
8235
+ try {
8236
+ const size = fstatSync(fd).size;
8237
+ if (size > 0) {
8238
+ const lastByte = /* @__PURE__ */ new Uint8Array(1);
8239
+ readSync(fd, lastByte, 0, 1, size - 1);
8240
+ needsNewline = lastByte[0] !== 10;
8241
+ }
8242
+ } finally {
8243
+ closeSync(fd);
8244
+ }
8245
+ if (needsNewline) appendFileSync(path, "\n", "utf8");
8246
+ }
8155
8247
  repairTornTail(runId, whole) {
8156
8248
  const path = this.journalPath(runId);
8157
8249
  const temp = `${path}.tmp`;
@@ -8308,7 +8400,11 @@ function isOrchestratorAccount(scope) {
8308
8400
  * Folds the per-run attribution buckets into the normative CostReport.
8309
8401
  * Live attribution buckets never see abandoned subtrees, so a host
8310
8402
  * that tracked abandoned spend itself passes it as `abandoned`;
8311
- * omitted, the report shows a gross equal to the net.
8403
+ * omitted, the report shows a gross equal to the net. Non-finite
8404
+ * numbers anywhere in the inputs are a typed refusal (RV705): this
8405
+ * exported builder is the same public surface as
8406
+ * {@link costReportFromJournal} and holds the same RV610 doctrine,
8407
+ * instead of letting an Infinity or NaN serialize into null downstream.
8312
8408
  */
8313
8409
  function buildCostReport(attribution, totalUsd, abandoned = {
8314
8410
  usd: 0,
@@ -8322,7 +8418,7 @@ function buildCostReport(attribution, totalUsd, abandoned = {
8322
8418
  forcedFinish: false,
8323
8419
  reserveUsedUsd: 0
8324
8420
  };
8325
- return {
8421
+ const report = {
8326
8422
  totalUsd,
8327
8423
  grossUsd: totalUsd + abandoned.usd,
8328
8424
  abandoned,
@@ -8336,6 +8432,8 @@ function buildCostReport(attribution, totalUsd, abandoned = {
8336
8432
  },
8337
8433
  unpriced: attribution.unpriced
8338
8434
  };
8435
+ requireFiniteNumbersDeep(report, "costReport");
8436
+ return report;
8339
8437
  }
8340
8438
  /**
8341
8439
  * The pure journal fold: the complete CostReport from terminal entries,
@@ -10969,6 +11067,18 @@ async function runAgent(options) {
10969
11067
  });
10970
11068
  };
10971
11069
  const providerCalls = [];
11070
+ const usdByPhaseModel = /* @__PURE__ */ new Map();
11071
+ const addCallUsd = (role, ref, usage) => {
11072
+ const priced = options.priceUsd?.(ref, usage) ?? 0;
11073
+ const usd = Number.isFinite(priced) && priced > 0 ? priced : 0;
11074
+ const key = `${role}\u0000${ref}`;
11075
+ const prior = usdByPhaseModel.get(key);
11076
+ usdByPhaseModel.set(key, {
11077
+ role,
11078
+ usd: (prior?.usd ?? 0) + usd
11079
+ });
11080
+ };
11081
+ let perCallCoverage = true;
10972
11082
  let invocationCounter = 0;
10973
11083
  let transportRetries = 0;
10974
11084
  let schemaRecoveredTerminalExchanges = 0;
@@ -10978,6 +11088,11 @@ async function runAgent(options) {
10978
11088
  for (const [key, slice] of usageByPhaseModel) if (slice.role === role) snapshot.set(key, slice.usage);
10979
11089
  return snapshot;
10980
11090
  };
11091
+ const roleUsdSnapshot = (role) => {
11092
+ const snapshot = /* @__PURE__ */ new Map();
11093
+ for (const [key, cell] of usdByPhaseModel) if (cell.role === role) snapshot.set(key, cell.usd);
11094
+ return snapshot;
11095
+ };
10981
11096
  const usageDelta = (after, before) => {
10982
11097
  const base = before ?? ZERO_USAGE$1;
10983
11098
  const delta = {
@@ -11005,19 +11120,22 @@ async function runAgent(options) {
11005
11120
  role,
11006
11121
  model,
11007
11122
  before: roleUsageSnapshot(role),
11123
+ beforeUsd: roleUsdSnapshot(role),
11008
11124
  startedAtMs: now(),
11009
11125
  retriesBefore: transportRetries
11010
11126
  };
11011
11127
  };
11012
11128
  const endPhase = (phase, outcome, servedModel) => {
11013
11129
  let phaseUsage = ZERO_USAGE$1;
11014
- let phaseUsd = 0;
11015
11130
  for (const [key, slice] of usageByPhaseModel) {
11016
11131
  if (slice.role !== phase.role) continue;
11017
11132
  const delta = usageDelta(slice.usage, phase.before.get(key));
11018
11133
  phaseUsage = addUsage$1(phaseUsage, delta);
11019
- const priced = options.priceUsd?.(slice.servedBy, delta) ?? 0;
11020
- if (Number.isFinite(priced) && priced > 0) phaseUsd += priced;
11134
+ }
11135
+ let phaseUsd = 0;
11136
+ for (const [key, cell] of usdByPhaseModel) {
11137
+ if (cell.role !== phase.role) continue;
11138
+ phaseUsd += cell.usd - (phase.beforeUsd.get(key) ?? 0);
11021
11139
  }
11022
11140
  const retries = transportRetries - phase.retriesBefore;
11023
11141
  events?.emit({
@@ -11030,6 +11148,7 @@ async function runAgent(options) {
11030
11148
  durationMs: Math.max(0, now() - phase.startedAtMs),
11031
11149
  usage: phaseUsage,
11032
11150
  costUsd: phaseUsd,
11151
+ costBasis: "per-call",
11033
11152
  outcome,
11034
11153
  ...retries > 0 ? { retries } : {}
11035
11154
  });
@@ -11278,15 +11397,28 @@ async function runAgent(options) {
11278
11397
  servedBy,
11279
11398
  usage: totalUsage
11280
11399
  }];
11400
+ const restoredSliceSums = /* @__PURE__ */ new Map();
11281
11401
  for (const slice of restoredSlices) {
11282
11402
  const sliceUsage = usageViolations(slice.usage).length === 0 ? slice.usage : sanitizeUsage(slice.usage);
11283
11403
  addPhaseUsage(slice.role ?? primaryRole, slice.servedBy, sliceUsage);
11284
11404
  options.budget?.onUsage(sliceUsage, slice.servedBy);
11285
- }
11286
- for (const record of restored.providerCalls ?? []) providerCalls.push(usageViolations(record.usage).length === 0 ? record : {
11287
- ...record,
11288
- usage: sanitizeUsage(record.usage)
11289
- });
11405
+ const key = `${slice.role ?? primaryRole} ${slice.servedBy}`;
11406
+ restoredSliceSums.set(key, addUsage$1(restoredSliceSums.get(key) ?? ZERO_USAGE$1, sliceUsage));
11407
+ }
11408
+ const restoredRecordSums = /* @__PURE__ */ new Map();
11409
+ for (const record of restored.providerCalls ?? []) {
11410
+ const sane = usageViolations(record.usage).length === 0 ? record : {
11411
+ ...record,
11412
+ usage: sanitizeUsage(record.usage)
11413
+ };
11414
+ providerCalls.push(sane);
11415
+ addCallUsd(sane.role ?? primaryRole, sane.servedBy, sane.usage);
11416
+ const key = `${sane.role ?? primaryRole} ${sane.servedBy}`;
11417
+ restoredRecordSums.set(key, addUsage$1(restoredRecordSums.get(key) ?? ZERO_USAGE$1, sane.usage));
11418
+ }
11419
+ const usageEquals = (a, b) => a.inputTokens === b.inputTokens && a.outputTokens === b.outputTokens && a.cacheReadTokens === b.cacheReadTokens && a.cacheWriteTokens === b.cacheWriteTokens && (a.reasoningTokens ?? 0) === (b.reasoningTokens ?? 0);
11420
+ for (const [key, sliceSum] of restoredSliceSums) if (!usageEquals(sliceSum, restoredRecordSums.get(key) ?? ZERO_USAGE$1)) perCallCoverage = false;
11421
+ for (const key of restoredRecordSums.keys()) if (!restoredSliceSums.has(key)) perCallCoverage = false;
11290
11422
  guard?.restore(messages);
11291
11423
  if (limits.toolBudgetNotices === true && limits.maxToolCalls !== void 0) for (const threshold of crossedNoticeThresholds(toolCallsUsed, limits.maxToolCalls)) firedNotices.add(threshold);
11292
11424
  if (extension !== void 0 && limits.maxToolCalls !== void 0 && toolCallsUsed > limits.maxToolCalls) {
@@ -11337,6 +11469,25 @@ async function runAgent(options) {
11337
11469
  }
11338
11470
  return usd;
11339
11471
  };
11472
+ /**
11473
+ * The invocation's recorded spend (RV702): the per-call accumulator
11474
+ * when every slice is covered by records, the settled fold's own
11475
+ * basis; the labeled aggregate estimate when a restored checkpoint
11476
+ * left usage no record backs, so restored spend is never silently
11477
+ * dropped and an estimate never poses as the per-request fold.
11478
+ */
11479
+ const recordedSpend = () => {
11480
+ if (!perCallCoverage) return {
11481
+ usd: priceRecordedUsage(),
11482
+ basis: "aggregate-estimate"
11483
+ };
11484
+ let usd = 0;
11485
+ for (const cell of usdByPhaseModel.values()) usd += cell.usd;
11486
+ return {
11487
+ usd,
11488
+ basis: "per-call"
11489
+ };
11490
+ };
11340
11491
  const saveBoundary = async (pending) => {
11341
11492
  if (options.checkpoint === void 0) return;
11342
11493
  await options.checkpoint.save({
@@ -11510,7 +11661,7 @@ async function runAgent(options) {
11510
11661
  continue;
11511
11662
  }
11512
11663
  const request = validation.value;
11513
- const spentSoFar = priceRecordedUsage();
11664
+ const spentSoFar = recordedSpend().usd;
11514
11665
  if (countsAgainstLimit(request.kind) && spentSoFar < options.escalation.minSpendUsd) {
11515
11666
  events?.emit({
11516
11667
  type: "tool:end",
@@ -11918,6 +12069,7 @@ async function runAgent(options) {
11918
12069
  if (outcome.aborted !== void 0) record.aborted = outcome.aborted;
11919
12070
  else if (outcome.wireError !== void 0) record.errorCode = outcome.wireError.code;
11920
12071
  providerCalls.push(record);
12072
+ addCallUsd(site.role, target.resolved.ref, accounted);
11921
12073
  const limited = outcome.wireError?.data;
11922
12074
  if (limited?.kind === "rate-limit" && typeof limited.reportedLimits === "object" && limited.reportedLimits !== null) rateLimitObservations.set(`${target.adapter.id}:${target.resolved.model}`, {
11923
12075
  provider: target.adapter.id,
@@ -12748,12 +12900,13 @@ async function runAgent(options) {
12748
12900
  const blob = new TextEncoder().encode(JSON.stringify({ messages }));
12749
12901
  await options.transcript.put(transcriptRef, blob);
12750
12902
  }
12751
- const costUsd = priceRecordedUsage();
12903
+ const spend = recordedSpend();
12752
12904
  const result = {
12753
12905
  status,
12754
12906
  output: status === "ok" ? output : output ?? null,
12755
12907
  usage: totalUsage,
12756
- costUsd,
12908
+ costUsd: spend.usd,
12909
+ costBasis: spend.basis,
12757
12910
  turns,
12758
12911
  servedBy,
12759
12912
  transcriptRef
@@ -14569,13 +14722,15 @@ function createCtx(internals, rootWorkflow) {
14569
14722
  cacheReadTokens: 0,
14570
14723
  cacheWriteTokens: 0
14571
14724
  };
14572
- const replayPriced = terminal === void 0 ? void 0 : priceEntryUsage(terminal, (ref, sliceUsage) => internals.priceUsd(ref, sliceUsage));
14725
+ const replayPriced = terminal === void 0 ? void 0 : priceEntryBilling(terminal, (ref, sliceUsage) => internals.priceUsd(ref, sliceUsage));
14573
14726
  const costUsd = replayPriced?.usd ?? 0;
14727
+ const replayBasis = replayPriced === void 0 || replayPriced.fullyAttributed ? "per-call" : "aggregate-estimate";
14574
14728
  const result = {
14575
14729
  status: matched.kind === "skip" ? "skipped" : terminal?.status ?? "ok",
14576
14730
  output: matched.kind === "skip" ? null : terminal?.value ?? null,
14577
14731
  usage,
14578
14732
  costUsd,
14733
+ costBasis: replayBasis,
14579
14734
  servedBy: terminal?.servedBy ?? loopResolved.ref,
14580
14735
  turns: 0,
14581
14736
  transcriptRef: terminal?.transcriptRef ?? ""
@@ -14639,29 +14794,37 @@ function createCtx(internals, rootWorkflow) {
14639
14794
  durationMs: 0
14640
14795
  }, spanId, true);
14641
14796
  }
14642
- if (terminal !== void 0) entryUsageSlices(terminal).forEach((slice, index) => {
14643
- const priced = internals.priceUsd(slice.servedBy, slice.usage) ?? 0;
14644
- const sliceUsd = Number.isFinite(priced) && priced > 0 ? priced : 0;
14645
- const common = {
14646
- agentType,
14647
- label: opts.label,
14648
- role: slice.role ?? primaryRole,
14649
- model: slice.servedBy,
14650
- invocation: index + 1
14651
- };
14652
- internals.events.emit({
14653
- type: "agent:phase:start",
14654
- ...common
14655
- }, spanId, true);
14656
- internals.events.emit({
14657
- type: "agent:phase:end",
14658
- ...common,
14659
- durationMs: 0,
14660
- usage: slice.usage,
14661
- costUsd: sliceUsd,
14662
- outcome: terminal.status === "error" || terminal.status === "cancelled" ? "error" : "ok"
14663
- }, spanId, true);
14664
- });
14797
+ if (terminal !== void 0) {
14798
+ const usdByRoleModel = /* @__PURE__ */ new Map();
14799
+ const perCallModels = /* @__PURE__ */ new Set();
14800
+ for (const unit of replayPriced?.units ?? []) {
14801
+ const key = `${unit.role ?? primaryRole} ${unit.servedBy}`;
14802
+ usdByRoleModel.set(key, (usdByRoleModel.get(key) ?? 0) + unit.usd);
14803
+ if (unit.source === "call") perCallModels.add(unit.servedBy);
14804
+ }
14805
+ entryUsageSlices(terminal).forEach((slice, index) => {
14806
+ const common = {
14807
+ agentType,
14808
+ label: opts.label,
14809
+ role: slice.role ?? primaryRole,
14810
+ model: slice.servedBy,
14811
+ invocation: index + 1
14812
+ };
14813
+ internals.events.emit({
14814
+ type: "agent:phase:start",
14815
+ ...common
14816
+ }, spanId, true);
14817
+ internals.events.emit({
14818
+ type: "agent:phase:end",
14819
+ ...common,
14820
+ durationMs: 0,
14821
+ usage: slice.usage,
14822
+ costUsd: usdByRoleModel.get(`${slice.role ?? primaryRole} ${slice.servedBy}`) ?? 0,
14823
+ costBasis: perCallModels.has(slice.servedBy) ? "per-call" : "aggregate-estimate",
14824
+ outcome: terminal.status === "error" || terminal.status === "cancelled" ? "error" : "ok"
14825
+ }, spanId, true);
14826
+ });
14827
+ }
14665
14828
  internals.events.emit({
14666
14829
  type: "agent:end",
14667
14830
  agentType,
@@ -14669,12 +14832,13 @@ function createCtx(internals, rootWorkflow) {
14669
14832
  status: result.status,
14670
14833
  usage,
14671
14834
  costUsd,
14835
+ costBasis: replayBasis,
14672
14836
  entryRef: terminal?.seq ?? matched.running.seq,
14673
14837
  ...terminal?.usageApprox === true ? { usageApprox: true } : {},
14674
14838
  ...result.exploration === void 0 ? {} : { exploration: result.exploration },
14675
14839
  ...result.toolBudget === void 0 ? {} : { toolBudget: result.toolBudget }
14676
14840
  }, spanId, true);
14677
- for (const slice of replayPriced?.priced ?? []) bump(internals.cost.byModel, slice.servedBy, slice.usd);
14841
+ for (const unit of replayPriced?.units ?? []) bump(internals.cost.byModel, unit.servedBy, unit.usd);
14678
14842
  for (const slice of replayPriced?.unpriced ?? []) internals.cost.unpriced.push({
14679
14843
  model: slice.servedBy,
14680
14844
  usage: slice.usage
@@ -15306,6 +15470,7 @@ function createCtx(internals, rootWorkflow) {
15306
15470
  status: result.status,
15307
15471
  usage: result.usage,
15308
15472
  costUsd: result.costUsd,
15473
+ costBasis: result.costBasis,
15309
15474
  entryRef: terminal.seq,
15310
15475
  ...resultUsageApprox ? { usageApprox: true } : {},
15311
15476
  ...result.transportRetries !== void 0 && result.transportRetries > 0 ? { retryCount: result.transportRetries } : {},
@@ -17508,6 +17673,7 @@ function makeOrchestratorWorkflow(goal, opts) {
17508
17673
  cacheWriteTokens: 0
17509
17674
  },
17510
17675
  costUsd: 0,
17676
+ costBasis: "per-call",
17511
17677
  turns: 0,
17512
17678
  servedBy: "unknown:unknown",
17513
17679
  transcriptRef: "",
@@ -18485,6 +18651,7 @@ function makeOrchestratorWorkflow(goal, opts) {
18485
18651
  cacheWriteTokens: 0
18486
18652
  },
18487
18653
  costUsd: 0,
18654
+ costBasis: "per-call",
18488
18655
  turns: 0,
18489
18656
  servedBy: "unknown:unknown",
18490
18657
  transcriptRef: "",
@@ -20257,6 +20424,7 @@ function reduceInvocationTable(events) {
20257
20424
  ...event.label === void 0 ? {} : { label: event.label },
20258
20425
  usage: ZERO,
20259
20426
  costUsd: 0,
20427
+ costBasis: "aggregate-estimate",
20260
20428
  usageApprox: false,
20261
20429
  retryCount: 0,
20262
20430
  replayed: event.replayed === true,
@@ -20283,6 +20451,7 @@ function reduceInvocationTable(events) {
20283
20451
  durationMs: 0,
20284
20452
  usage: ZERO,
20285
20453
  costUsd: 0,
20454
+ costBasis: "aggregate-estimate",
20286
20455
  retries: 0,
20287
20456
  replayed: event.replayed === true,
20288
20457
  open: true
@@ -20302,6 +20471,7 @@ function reduceInvocationTable(events) {
20302
20471
  durationMs: 0,
20303
20472
  usage: ZERO,
20304
20473
  costUsd: 0,
20474
+ costBasis: "aggregate-estimate",
20305
20475
  retries: 0,
20306
20476
  replayed: event.replayed === true,
20307
20477
  open: true
@@ -20315,14 +20485,17 @@ function reduceInvocationTable(events) {
20315
20485
  phase.durationMs = event.durationMs;
20316
20486
  phase.usage = event.usage;
20317
20487
  phase.costUsd = event.costUsd;
20488
+ phase.costBasis = event.costBasis ?? "aggregate-estimate";
20318
20489
  phase.outcome = event.outcome;
20319
20490
  phase.retries = event.retries ?? 0;
20320
20491
  const bucket = byRole[event.role] ??= {
20321
20492
  usage: ZERO,
20322
- costUsd: 0
20493
+ costUsd: 0,
20494
+ costBasis: "per-call"
20323
20495
  };
20324
20496
  bucket.usage = addUsage(bucket.usage, event.usage);
20325
20497
  bucket.costUsd += event.costUsd;
20498
+ if (phase.costBasis === "aggregate-estimate") bucket.costBasis = "aggregate-estimate";
20326
20499
  break;
20327
20500
  }
20328
20501
  case "agent:end": {
@@ -20331,6 +20504,7 @@ function reduceInvocationTable(events) {
20331
20504
  row.status = event.status;
20332
20505
  row.usage = event.usage;
20333
20506
  row.costUsd = event.costUsd;
20507
+ row.costBasis = event.costBasis ?? "aggregate-estimate";
20334
20508
  row.usageApprox = event.usageApprox === true;
20335
20509
  row.retryCount = event.retryCount ?? 0;
20336
20510
  if (event.toolBudget !== void 0) row.toolBudget = event.toolBudget;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/core",
3
- "version": "1.108.0",
3
+ "version": "1.110.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",