feat: wire Ledger onto LedgerBackend (precheck/apply_events) - #132
Merged
susheem-k merged 1 commit intoSep 12, 2026
Merged
Conversation
susheem-k
force-pushed
the
feat/local-run-state-and-data-scope
branch
from
September 12, 2026 11:16
5d26170 to
93e7678
Compare
…e Store (#118) Adds a backend= mode to Ledger, additive alongside the existing store=/in-memory modes (mutually exclusive with store=) — the core Ledger/LedgerView piece of the remote-only rewrite's Phase 2 checklist. build_governor/ControlPlaneClient don't construct it yet; that swap, and migrating the ~18 Store-dependent tests, are the next increments (staged deliberately, per the epic's own Phase 2/3 split). - record(): batches the step + spent_add (when cost > 0) into one apply_events call sharing an idempotency seq, so the ack's totals cover the run-total cum spend without a separate read_state round trip for the common case. - admit/complete/mark_halted/clear_halt: one-shot apply_events writes. Their idempotency keys are random (uuid4), not the contract's deterministic {run_id}:...:{seq} recipe — that recipe needs a real run_id to stay collision-free across processes for a non-run-scoped segment key (e.g. an agent-dimension concurrency cap shared across runs), which isn't always available at these call sites. A random key is correct for a one-shot, non-retried write either way; the deterministic recipe only earns its keep once a buffered backend needs a retried flush to regenerate the same key (the existing # TODO(buffering) seam in ledger_backend.py). - cost_micros/budget_left/is_halted/inflight: read via backend.read_state (precheck). No per-call batching across detectors yet (one read per method call) — Governor grouping detectors by data_scope into a single precheck per governed moment is a separate, later optimization, not required for correctness given there's no client-side write buffer yet either (decision #6). - velocity/recent/window/step_count are unchanged: always Tier-1 LocalRunState, never a backend round trip — those are inherently per-process reads. tests/test_ledger_backend_mode.py: 9 new tests against FakeLedgerBackend, including two Ledger instances sharing one backend (the actual cross-process scenario this whole rewire is for) for halt visibility and inflight counting. Full suite: 246 passed, 16 skipped, 11 deselected. ruff check/format and mypy clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
susheem-k
force-pushed
the
feat/ledger-backend-wiring
branch
from
September 12, 2026 11:17
90ee638 to
3c81d40
Compare
susheem-k
merged commit Sep 12, 2026
90fbd93
into
feat/local-run-state-and-data-scope
3 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stacked on #131 (needs
LocalRunState) — the coreLedger/LedgerViewpiece of tokenops#118 Phase 2. Adds abackend=mode toLedger, additive alongside the existingstore=/in-memory modes (mutually exclusive withstore=), so nothing that constructsLedger/build_governortoday is touched.record()batches thestep+spent_add(whencost > 0) into oneapply_eventscall sharing an idempotency seq, so the ack'stotalscovers the run-total cum spend without a separateread_stateround trip for the common case.admit/complete/mark_halted/clear_haltare one-shotapply_eventswrites. Their idempotency keys are random (uuid4), not the control-plane contract's deterministic{run_id}:...:{seq}recipe — that recipe needs a realrun_idto stay collision-free across processes for a non-run-scoped segment key (e.g. anagent-dimension concurrency cap shared across runs), which isn't always available at these call sites (verified: every current call site is actually alwaysrun:-scoped, but the API is more general). A random key is correct for a one-shot, non-retried write either way; the deterministic recipe only earns its keep once a buffered backend needs a retried flush to regenerate the same key (the existing# TODO(buffering)seam inledger_backend.py).cost_micros/budget_left/is_halted/inflightread viabackend.read_state(precheck). No per-call batching across detectors yet — Governor grouping detectors bydata_scopeinto a singleprecheckper governed moment is a separate, later optimization, not required for correctness given there's no client-side write buffer yet either (locked decision #6).velocity/recent/window/step_countare unchanged — always Tier-1LocalRunState, never a backend round trip. Those are inherently per-process reads.Not yet wired into
build_governor/ControlPlaneClient— that swap, and migrating the ~18Store-dependent test files, are the next increments (staged deliberately, matching the epic's own Phase 2 vs. Phase 3 split).Test plan
tests/test_ledger_backend_mode.py— 9 new tests againstFakeLedgerBackend: pricing/cum_spent, zero-cost crossings write no spend,budget_left(incl. unlimited + unknown budget), admit/complete/inflight, mark_halted/clear_halt, and twoLedgerinstances sharing one backend for halt visibility + inflight counting (the actual cross-process scenario this rewire targets) and confirming Tier-1 reads stay local.python -m pytest -q→ 246 passed, 16 skipped, 11 deselected (9 more than refactor: rename RunState to LocalRunState; add PolicyInstance.data_scope #131's baseline, all new)ruff check/ruff format --checkcleanmypy src/tokenops/control/ledger.pyclean🤖 Generated with Claude Code