Rulvar API reference / @rulvar/core / JournalEntry
Type Alias: JournalEntry
type JournalEntry = {
abandon?: AbandonPayload;
artifacts?: Json;
checkpointRef?: string;
costAttribution?: CostAttributionFacts;
deadlineAt?: string;
endedAt?: string;
error?: WireError;
escalation?: Json;
evidence?: {
met: boolean;
minEntries: number;
recordedEntries: number;
};
evidenceEntries?: {
citation?: string;
claim: string;
}[];
hashVersion: HashVersion;
hostRejected?: boolean;
key: string;
kind: EntryKind;
memoizeOutcome?: boolean;
ordinal: number;
providerCalls?: ProviderCallRecord[];
ref?: number;
resolution?: ResolutionPayload;
scope: string;
seq: number;
servedBy?: ModelRef;
spanId: string;
startedAt: string;
status: EntryStatus;
toolBudget?: {
cap?: number;
used: number;
};
transcriptRef?: string;
usage?: Usage;
usageApprox?: boolean;
usageByModel?: UsageSlice[];
usageSemantics?: string;
value?: Json;
};Defined in: packages/core/src/l0/entries.ts:517
Final entry form (hashVersion 2). All journaled values MUST be JSON-serializable; a violation raises a typed NonSerializableValueError at the call site. append is serialized by a per-run queue.
Properties
abandon?
optional abandon?: AbandonPayload;Defined in: packages/core/src/l0/entries.ts:648
Only when kind === 'abandon'.
artifacts?
optional artifacts?: Json;Defined in: packages/core/src/l0/entries.ts:593
Terminal agent entries: the Artifact list (worktree patch refs and inline values); rides the terminal payload so replay reconstructs AgentResult.artifacts without live calls.
checkpointRef?
optional checkpointRef?: string;Defined in: packages/core/src/l0/entries.ts:587
costAttribution?
optional costAttribution?: CostAttributionFacts;Defined in: packages/core/src/l0/entries.ts:558
Terminal usage-bearing entries: the attribution facts behind the CostReport breakdowns, so a pure journal fold reproduces the live report byte for byte on replay. Policy, never identity, exactly like usageByModel.
deadlineAt?
optional deadlineAt?: string;Defined in: packages/core/src/l0/entries.ts:657
On suspended entries: the journaled deadline.
endedAt?
optional endedAt?: string;Defined in: packages/core/src/l0/entries.ts:660
error?
optional error?: WireError;Defined in: packages/core/src/l0/entries.ts:534
escalation?
optional escalation?: Json;Defined in: packages/core/src/l0/entries.ts:644
Terminal escalated entries ONLY: the schema-validated EscalationReport with runtime-filled costToDate and salvage; replay synthesizes the byte-identical report from here (DEF-1).
evidence?
optional evidence?: {
met: boolean;
minEntries: number;
recordedEntries: number;
};Defined in: packages/core/src/l0/entries.ts:601
Terminal agent entries: the evidence verdict under a declared contract (RV806), journaled so replay restores AgentResult.evidence without re-deriving a window it no longer holds (the RV1501 entries plumbing). Policy, never identity, exactly like usageByModel.
met
met: boolean;minEntries
minEntries: number;recordedEntries
recordedEntries: number;evidenceEntries?
optional evidenceEntries?: {
citation?: string;
claim: string;
}[];Defined in: packages/core/src/l0/entries.ts:613
Terminal agent entries: the recorded evidence entry CONTENT (the RV1501 entries plumbing): each successful record_evidence execution's claim plus its file or file:lines citation, in record order, bounded at collection time (40 entries, 400 chars per claim). Rides the terminal payload so replay reconstructs AgentResult.evidenceEntries without live calls and a resumed orchestrator pairs its claim pools against what the child actually recorded, exactly like a live run. Policy, never identity.
citation?
optional citation?: string;claim
claim: string;hashVersion
hashVersion: HashVersion;Defined in: packages/core/src/l0/entries.ts:519
Identity-derivation and replay-semantics version of THIS entry.
hostRejected?
optional hostRejected?: boolean;Defined in: packages/core/src/l0/entries.ts:638
Terminal agent entries whose invocation was aborted by the host's finish rejection (RV3702): the declared finish contract rejected the candidate past its repair bound, so the span died by host hand with its wires fine. Stamped at settle from the typed abort reason; never on a defective (throwing) validator, whose abort carries its own reason, because a host defect is not a verdict on the candidate. Policy, never identity, exactly like usageByModel.
key
key: string;Defined in: packages/core/src/l0/entries.ts:529
kind
kind: EntryKind;Defined in: packages/core/src/l0/entries.ts:531
memoizeOutcome?
optional memoizeOutcome?: boolean;Defined in: packages/core/src/l0/entries.ts:655
Policy field on agent entries, fixed in the payload at dispatch time: the M2 predicate reads the flag from the ENTRY, never from current code. Excluded from identity like every policy field.
ordinal
ordinal: number;Defined in: packages/core/src/l0/entries.ts:530
providerCalls?
optional providerCalls?: ProviderCallRecord[];Defined in: packages/core/src/l0/entries.ts:570
Terminal agent entries: the per-dispatch reconciliation ledger (P1.3), one record per live provider call the invocation made, failed and retried attempts included, so every billable wire call maps to a journal entry and the invoice export can name the provider response ids behind the usage total. Absent on entries written before this shipped and on fully replayed invocations (which made no calls); the invoice fold surfaces such entries as unattributed rows instead of losing their spend. Policy, never identity, exactly like usageByModel.
ref?
optional ref?: number;Defined in: packages/core/src/l0/entries.ts:527
Backward reference by seq, always ref < seq: on ref-entries (resolution/abandon) the seq of the target; on terminal phase entries the seq of the running entry.
resolution?
optional resolution?: ResolutionPayload;Defined in: packages/core/src/l0/entries.ts:646
Only when kind === 'resolution'.
scope
scope: string;Defined in: packages/core/src/l0/entries.ts:528
seq
seq: number;Defined in: packages/core/src/l0/entries.ts:521
Total order per run; canonical EntryRef = seq.
servedBy?
optional servedBy?: ModelRef;Defined in: packages/core/src/l0/entries.ts:539
Who actually served (failover changes only this, never the key).
spanId
spanId: string;Defined in: packages/core/src/l0/entries.ts:658
startedAt
startedAt: string;Defined in: packages/core/src/l0/entries.ts:659
status
status: EntryStatus;Defined in: packages/core/src/l0/entries.ts:532
toolBudget?
optional toolBudget?: {
cap?: number;
used: number;
};Defined in: packages/core/src/l0/entries.ts:628
Terminal agent entries: the durable subset of the tool-budget summary (RV3002): the loop's executed-call counter and the effective cap at the end, journaled at settle whenever the live result carried a summary. The counter has always been durable in the terminal checkpoint, but checkpoints are blobs and journal folds read entries only, so without this field observed calls-per-evidence-entry calibration cannot be a pure fold. Replay restores AgentResult.toolBudget from here unconditionally; entries without the field (every pre-existing journal) keep the RV509 decision-conditional path byte for byte. Live-only summary fields (unitsUsed, noticesFired, limiter, and the rest) never journal. Policy, never identity, exactly like evidence.
cap?
optional cap?: number;used
used: number;transcriptRef?
optional transcriptRef?: string;Defined in: packages/core/src/l0/entries.ts:586
usage?
optional usage?: Usage;Defined in: packages/core/src/l0/entries.ts:535
usageApprox?
optional usageApprox?: boolean;Defined in: packages/core/src/l0/entries.ts:537
True when the stream was cut at the budget ceiling or by a stream failure.
usageByModel?
optional usageByModel?: UsageSlice[];Defined in: packages/core/src/l0/entries.ts:551
Terminal agent entries whose phases were served by MORE THAN ONE model: usage split by the model that actually served each slice. The loop, extract, finalize, and summarize roles resolve independently, so a single agent call routinely spans models at different prices; pricing the whole call at servedBy bills the cheap extract at the loop model's rate. Absent when one model served the whole call, and on entries written before the split shipped: readers fall back to pricing usage at servedBy, which is exactly correct for those. Policy, never identity: it does not enter the content key.
usageSemantics?
optional usageSemantics?: string;Defined in: packages/core/src/l0/entries.ts:585
The serving adapters' declared usage-telemetry semantics at write time (ProviderAdapter.usageSemantics), stamped so cost numbers stay auditable across normalization corrections: an UNSTAMPED OpenAI entry with cacheWriteTokens > 0 may have been written by rulvar v1.19.0, whose adapter double-counted cache writes into inputTokens (v1.20.0 review P1/P2-2). The stamp unions every adapter that served a slice of the entry, distinct declarations joined with '+' in first-appearance order, so a mixed-adapter call whose primary declares nothing is still dated by its declaring slices. Absent only when NO serving adapter declares semantics, and on all entries written before this shipped. Policy, never identity, exactly like usageByModel.
value?
optional value?: Json;Defined in: packages/core/src/l0/entries.ts:533