Context
The MCP server's two tool handlers — currentBlock and sessionCost — both call queryAll() from @relayburn/ledger (packages/mcp/src/tools/current-block.ts:6,47, packages/mcp/src/tools/session-cost.ts:3,28). Every in-session self-query from a running agent therefore re-walks the entire ledger and re-folds stamps. The MCP path is explicitly the place where latency matters most — the agent is paying per-token to wait for the answer.
PR #78 explicitly defers this rewire:
Rewiring burn summary / compare / plans / @relayburn/mcp to read from the archive (each command is a self-contained migration that keeps the in-memory fallback intact).
Issue #40 calls this out as a primary motivation for the archive:
@relayburn/mcp (#26) wants low-latency self-query from inside a running agent.
The MCP tools accept a queryTurns dependency injection in their Deps types already (current-block.ts:35-40, session-cost.ts:21-25), so the rewire surface is small.
Proposal
- Add a
queryTurnsFromArchive(query) helper in @relayburn/ledger that prepares a parameterized SQL SELECT against the archive's turns table and returns the same EnrichedTurn[] shape callers already consume. The archive already carries workflow_id / agent_id / persona / tier plus the JSON enrichment blob, so the result shape can be reconstructed without folding.
- Default
currentBlock's queryTurns and sessionCost's queryTurns to the archive-backed helper.
- Run
buildArchive() (incremental tail apply) at MCP server startup so the first tool call doesn't pay the cold cost. Optionally re-run on a low-frequency interval, or on-demand before each call if the ledger has grown — measure first.
- Fallback path: if the archive open or query throws, log via
onLog and fall through to queryAll(). The MCP server must never fail a tool call because the archive is unavailable.
Tests:
- Existing MCP unit tests pass with the archive-backed helper injected via
Deps.
- New end-to-end test: spin up the MCP server against a fixture archive + ledger, call both tools, assert results match the ledger-backed equivalents.
- Fallback path: archive missing/corrupt -> tools still succeed via
queryAll.
- Cold-start path: first MCP call after a new ledger tail applies the tail incrementally before responding.
Acceptance criteria
Out of scope
- New MCP tools or new tool inputs.
- Schema additions to the archive.
- The CLI
summary/compare/plans rewires.
Refs
Context
The MCP server's two tool handlers —
currentBlockandsessionCost— both callqueryAll()from@relayburn/ledger(packages/mcp/src/tools/current-block.ts:6,47,packages/mcp/src/tools/session-cost.ts:3,28). Every in-session self-query from a running agent therefore re-walks the entire ledger and re-folds stamps. The MCP path is explicitly the place where latency matters most — the agent is paying per-token to wait for the answer.PR #78 explicitly defers this rewire:
Issue #40 calls this out as a primary motivation for the archive:
The MCP tools accept a
queryTurnsdependency injection in theirDepstypes already (current-block.ts:35-40,session-cost.ts:21-25), so the rewire surface is small.Proposal
queryTurnsFromArchive(query)helper in@relayburn/ledgerthat prepares a parameterized SQLSELECTagainst the archive'sturnstable and returns the sameEnrichedTurn[]shape callers already consume. The archive already carriesworkflow_id/agent_id/persona/tierplus the JSON enrichment blob, so the result shape can be reconstructed without folding.currentBlock'squeryTurnsandsessionCost'squeryTurnsto the archive-backed helper.buildArchive()(incremental tail apply) at MCP server startup so the first tool call doesn't pay the cold cost. Optionally re-run on a low-frequency interval, or on-demand before each call if the ledger has grown — measure first.onLogand fall through toqueryAll(). The MCP server must never fail a tool call because the archive is unavailable.Tests:
Deps.queryAll.Acceptance criteria
burn__currentBlockandburn__sessionCostissue SQL againstarchive.sqliteon the hot path, not full ledger walks.queryAll().Out of scope
summary/compare/plansrewires.Refs
burn archive(#40) #78 (Derived analytics archive: materialize the ledger into a local queryable store #40 follow-up)