Skip to content

simplify(accounting): give saved-token totals one durable owner and delete asynchronous absolute-total rewrites #4447

Open

Description

@ScriptedAlchemy

Priority / target

P2 · correctness-driven state consolidation · medium accounting/reset risk. Preserve local token savings, costs, resettable counters, history and terminal-monitor behavior. Remove independently authoritative in-memory totals and per-call captured-total rewrites of the same cumulative fact.

Evidence

At 1bf9f0819465b2720241b20057510ff01dfa633a, McpServer::spawn_token_accounting_persist increments an AtomicU64, captures new_total, and spawns an observed async write. That task sets project tokens_saved, increments a separate local counter, and upserts a project total through the ledger sink. The first two errors are discarded.

store_meta.rs::set_tokens_saved stores the supplied absolute value through metadata; it is not an atomic increment or a compare-with-newer-total operation. Shutdown in server/connection.rs writes the in-memory absolute total again. requests.rs separately emits the underlying savings/analytics observation.

Two accounted completions can capture totals A then B while their independently scheduled persistence tasks execute in the reverse order. The setter itself has no monotonic/version condition, so stale captured state is not rejected there. This is a source-derived ordering risk, not a reproduced end-to-end counter regression; implementation must test the actual recorder scheduling and shutdown ordering.

Exact implementation

  1. Choose the existing registered accounting/store owner for the durable cumulative total. Submit the actual per-response accounting delta/identity there once, and update lifetime/resettable projections with their documented semantics. Reuse existing savings observations where they already establish the needed identity; do not add another event-sourcing subsystem.
  2. Replace per-call absolute snapshots with an atomic durable increment or an existing authoritative projection operation. Keep overflow typed. Make any in-memory display total a derived/read-through view, not a competing source that overwrites the database on shutdown.
  3. Delete stale absolute setters and duplicate final-total reconciliation once all production callers use the canonical owner. Where a profile summary remains a necessary projection, update it from committed authority with ordering/replay guarantees rather than independently captured values.
  4. Preserve reset-counter as a distinct operation: lifetime savings and a resettable session/user counter are not interchangeable. Serialize reset versus new deltas at the actual owner so older queued work cannot undo a reset or be counted in the wrong epoch.
  5. Keep nonblocking tool responses and existing observed-write shutdown settlement. Surface persistence failure through existing diagnostics instead of dropping it or crediting a durable total that never committed. Retrying a write must not double-credit the same completed response.
  6. Preserve separate analytics/cost and monitor semantics; their different output purposes do not require duplicating authority for the total. Keep per-project/profile attribution and existing opt-out behavior.

Acceptance

Controlled reverse-order completions cannot decrease or duplicate the durable lifetime total. Concurrent calls, reset interleaving, disconnect, restart and shutdown-with-pending-writes produce consistent committed results. Inject failure in each existing persistence stage; the system reports degraded accounting without fabricated durable success. Historical local totals and monitor output remain readable. Run actual MCP accounting/registered-store integration tests through Bazel, and report eliminated writes/state owners rather than assuming fewer methods means less I/O.

Distinct from #3619's worldwide-counter retirement, which explicitly preserves this local capability, and #2392's observability batching. Exact setter issue search found no matching task. Static source review only; no Rust concurrency test, production accounting incident or performance measurement is claimed.

Activity

  1. ScriptedAlchemy commented on Nov 9, 2026

    @ScriptedAlchemy
    OwnerAuthor

    Coverage checkpoint, 2026-11-09: #4852 is now the single active accounting PR, replacing #4811 (closed unmerged; old branch/history retained). Current head 0ebb86a6a717c80833150093c5548aeadf210901, prerequisite #4831 at 0bdd2a376dea87086bf6ea9c8e4e57ff5d4b88ce, complete tree 042b48cab2d5fe17d3d5f97866f551b3938bd40d identical to repaired #4811 d0f314b. Five existing source/test files retained unchanged. The original strict-Clippy unused-import error is removed; the new conforming single-commit title repairs the immutable historical commitlint blocker without force-rewriting history or changing gates.

    Exact-head CI 42702961402 is queued, not passed. Maintenance should use #4852 and preserve its prerequisite/review/CI holds; do not merge into the feature prerequisite branch. This is Refs #4447 only: durable per-response idempotency, reset/retry/restart/disconnect and all failure-stage acceptance are still outstanding. No issue closure or owner-slot recycling is justified. Existing schedules and protected model/release PRs are unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions