Skip to content

feat(accounting): durable per-turn accounting lifecycle and backend decorator (governance G-A2.1) - #189

Merged
shoedog merged 1 commit into
mainfrom
feat/accounting-decorator
Oct 19, 2026
Merged

shoedog merged 1 commit into
mainfrom
feat/accounting-decorator

Conversation

@shoedog

@shoedog shoedog commented Oct 19, 2026

Copy link
Copy Markdown
Owner

Phase 1 of cost and quota governance (H1-2), lane G-A2.1. This adds the accounting contract and the single capture boundary. Production wiring of the decorator onto every dispatch path is lane G-A2.2.

Why one decorator: the first attempt (G-A) captured usage at each call site. Two reviews each found new uncovered paths: smoke, compatibility, MCP continuations, implement setup, compaction and preflight. That design was open-class, so the owner approved a redesign around one capture boundary.

What it adds

  • Durable lifecycle:
    • an immutable attempt start is persisted before provider dispatch;
    • usage is persisted before it is forwarded, and completion before the terminal result is exposed;
    • duplicate completion is harmless;
    • interruption or failed completion persistence leaves durable pending accounting.
  • The accounting backend decorator is the only usage capture point. Context-free prompt calls refuse instead of dispatching unaccounted. Lifecycle, capability, diagnostic and custody hooks are forwarded unchanged.
  • The per-turn accounting envelope: execution/run-attempt identity, a distinct concrete-turn attempt ID, and the frozen effective model/effort/mode.
  • Storage reuses G-A's summary contract and merge rules:
    • repeated snapshots never double-charge;
    • context occupancy never becomes consumed tokens;
    • missing or invalid cost is unknown, never zero.
  • Store safety: the accounting database and SQLite sidecars are checked through retained directory-descriptor identity snapshots, and SQLite owns every open and close. Opening and closing a side descriptor would drop the process's POSIX fcntl locks and admit a conflicting writer. A multiprocess regression covers this.

Review: gpt-6.1-sol implemented; gpt-6-astra reviewed. Round history:

Round Result
1 REJECT: interrupted turns were finalized as settled
2 REJECT: POSIX lock dropped by the identity check
3 Fix applied; APPROVE

Verify (macOS, touched crates bridge-core, bridge-store): fmt, clippy -D warnings and validate --repo-hygiene ok; 1,989 passed / 0 failed. The lock regression fails on the round-2 commit. Not covered locally: the rest of the workspace (CI is the full gate). No production activation, so there is no behavior change for existing runs.

🤖 Generated with Claude Code

https://claude.ai/code/session_017izEynabPeSUBT573AtvaZ

…ecorator

Cost and quota governance phase 1, lane G-A2.1: the accounting contract and the single capture boundary. Production wiring is G-A2.2.

- Accounting lifecycle: an immutable attempt start is persisted before provider dispatch. Usage is persisted before it is forwarded, and completion before the terminal result is exposed. Completion is idempotent. Interrupted or failed completion leaves durable pending accounting.
- An accounting backend decorator is the only usage capture point. Context-free prompt calls refuse instead of dispatching unaccounted.
- The per-turn accounting envelope carries execution/run-attempt identity, the concrete-turn attempt ID and the frozen effective model/effort/mode.
- Storage reuses the G-A summary contract, snapshot merging and cost-quality rules (missing or invalid cost is never zero).
- The accounting database and SQLite sidecars are checked through retained directory-descriptor identity snapshots. SQLite owns every open and close, so POSIX advisory locks are never dropped by a side descriptor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017izEynabPeSUBT573AtvaZ
@shoedog

shoedog commented Oct 19, 2026

Copy link
Copy Markdown
Owner Author

Fixed the Windows job: UsageAllocationV1's identity fields are read only by the Unix descriptor checks, so on Windows they tripped -D dead-code. Added #[cfg_attr(not(unix), allow(dead_code))] on the struct. A local cross-check for Windows could not build the C dependencies (ring, libsqlite3-sys), so CI is the verification.

@shoedog
shoedog force-pushed the feat/accounting-decorator branch from fae0f92 to 8777c2a Compare October 19, 2026 05:23
@shoedog
shoedog merged commit c487d6c into main Oct 19, 2026
9 checks passed
@shoedog
shoedog deleted the feat/accounting-decorator branch October 19, 2026 05:57
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant