ledger

package
v0.22.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package ledger records per-call telemetry to an append-only JSONL file and reports estimated tokens (and dollars) kept out of Opus — how the harness proves it earns its keep.

JSONL, not a locked key-value store, on purpose: the long-running MCP server and an occasional `local-offload ledger` invocation must both touch the ledger at once. Writers append with O_APPEND (atomic for the small one-line records on both POSIX and Windows); the reader takes no lock and tolerates a not-yet-complete trailing line. This is what lets the savings report run while the MCP server is live (the bbolt version could not — exclusive file lock).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AppendLabel

func AppendLabel(path string, e Entry) error

AppendLabel appends e as ONE JSON line to a correctness-label sidecar file (NOT the main ledger — kept separate so the router/calibration/savings report stay pristine). Only the confhead reads it. It creates the parent dir and stamps TS if unset; concurrent callers are serialized by labelMu.

Types

type Entry

type Entry struct {
	TS        int64   `json:"ts"`
	Task      string  `json:"task"`
	TokensIn  int     `json:"tokens_in"`
	TokensOut int     `json:"tokens_out"`
	LatencyMs int64   `json:"latency_ms"`
	TokPerSec float64 `json:"tok_per_s"`
	CacheHit  bool    `json:"cache_hit"`
	Deferred  bool    `json:"deferred"`
	// --- self-learning signals (Phase 0 enrichment) ---
	Margin          float64            `json:"margin,omitempty"`
	ModelTier       string             `json:"model_tier,omitempty"`
	Escalations     int                `json:"escalations,omitempty"`
	Reasoning       bool               `json:"reasoning,omitempty"` // produced by the terminal reasoning tier (a reclaimed deferral)
	Retries         int                `json:"retries,omitempty"`
	Truncated       bool               `json:"truncated,omitempty"`
	Grounded        *bool              `json:"grounded,omitempty"`
	EscalatedAgreed *bool              `json:"escalated_agreed,omitempty"`
	ErrClass        string             `json:"err_class,omitempty"`
	InputChars      int                `json:"input_chars,omitempty"`
	Feat            map[string]float64 `json:"feat,omitempty"`
	// Reason is the human-readable defer reason (LO-8), set only on deferred
	// entries and truncated to maxReasonLen on write. Old ledger lines without
	// the field parse fine (empty string).
	Reason string `json:"reason,omitempty"`
}

Entry is one offload call. The self-learning fields (margin..feat) are written by the pipeline from core.Meta; old lines without them parse fine (zero values).

func ReadAll

func ReadAll(path string) ([]Entry, error)

ReadAll loads every parseable entry from a JSONL ledger (lock-free; skips malformed/partial lines). Missing file => empty slice, no error.

func ReadLabelFile

func ReadLabelFile(path string) ([]Entry, error)

ReadLabelFile loads every parseable entry from a correctness-label sidecar (mirrors ReadAll). A missing file returns (nil, nil); blank/malformed lines are skipped.

type Ledger

type Ledger struct {
	// contains filtered or unexported fields
}

Ledger appends entries to a JSONL file. The mutex serializes in-process writes; cross-process safety relies on O_APPEND atomicity for small lines.

func Open

func Open(path string) (*Ledger, error)

Open opens (creating if needed) the JSONL ledger for appending. It does NOT take an exclusive lock, so multiple processes can append concurrently.

func (*Ledger) Close

func (l *Ledger) Close() error

Close releases the append handle.

func (*Ledger) Record

func (l *Ledger) Record(e Entry) error

Record appends one entry as a single JSON line.

func (*Ledger) Summarize

func (l *Ledger) Summarize(since int64, opusPricePerMTok float64) (Summary, error)

Summarize aggregates this ledger's file since `since` (unix; 0 = all).

type ReasonCount added in v0.6.1

type ReasonCount struct {
	Reason string `json:"reason"`
	Count  int    `json:"count"`
}

ReasonCount is one aggregated defer reason for the ledger report.

func TopDeferReasons added in v0.6.1

func TopDeferReasons(path string, since int64, topN int) ([]ReasonCount, error)

TopDeferReasons aggregates the defer reasons of entries since `since` (unix; 0 = all) and returns the topN most frequent, ties broken alphabetically for deterministic output. Deferred entries written before the reason field existed count under "(unrecorded)" so the denominator stays honest. Lock-free like SummarizeFile; a missing file returns nil.

type Summary

type Summary struct {
	Calls             int `json:"calls"`
	CacheHits         int `json:"cache_hits"`
	Deferred          int `json:"deferred"`
	Completed         int `json:"completed"`
	ReasoningReclaims int `json:"reasoning_reclaims"` // completed via the terminal reasoning tier (deferrals it reclaimed before Opus)
	TokensSaved       int `json:"tokens_saved"`       // input tokens kept out of Opus on completed/cache calls
	TokensOut         int `json:"tokens_out"`
	// EstValueKeptLocal is the estimated Opus-INPUT value of the tokens kept
	// local (tokens_saved x opus_input_price_per_mtok / 1M). It is an estimate
	// of avoided cloud input pricing, NOT literal billed dollars saved (LO-12:
	// the old est_dollar_saved name presented it as money in the bank).
	EstValueKeptLocal float64 `json:"est_value_kept_local"`
	// Deprecated: the same number under the old, misleading name — kept
	// emitted for one release for consumers of the JSON; remove in v0.7.
	EstDollarSaved float64        `json:"est_dollar_saved"`
	ByTask         map[string]int `json:"by_task"`
}

Summary aggregates the ledger.

func SummarizeFile

func SummarizeFile(path string, since int64, opusPricePerMTok float64) (Summary, error)

SummarizeFile reads a JSONL ledger without any lock — safe to call while another process is appending (a partial final line is skipped). A missing file reports an empty summary (nothing offloaded yet), not an error.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL