Repository navigation
fix(agent-briefing): reconcile charges across summary generations - #8692
Conversation
Every generation a report has run keeps its settlement record, and reconciliation sums all of them plus the preserved baseline under the report row lock. A generated usage identity is recorded by the gateway after usage accounting completes, and is accepted only for the report's current generation, owner, organization scope and capability. Retry stays unavailable until every tracked generation's settlement record and usage row are present, and the pending summary keeps the reconciled total. The estimate check compares against the cost the authorization was granted for, so charges recorded later for an earlier generation do not invalidate the queued generation.
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryThe incremental commit is comment-only and corrects the queued-delivery anchor description in Assumptions: ScopeReviewed the single commit after the previously reviewed SHA Verification of the changed code
Files Reviewed (1 file)
Previous Review Summaries (4 snapshots, latest commit d45e3a5)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit d45e3a5)Status: No Issues Found | Recommendation: Merge Executive SummaryThe incremental commit adds a single guard so a settled report with a leftover charge schedule is rewritten once to clear it, and I found no defect in the changed lines or the new test. Assumptions: ScopeReviewed the one commit after the previously reviewed SHA Verification of the changed code
Residual notes (not findings): a manual DLQ redrive after the queue window can still commit usage for an already-settled generation; that would make the stored total stale until the next Files Reviewed (2 files)
Previous review (commit 30132a3)Status: No Issues Found | Recommendation: Merge Executive SummaryThe incremental commit makes a queued usage receipt keep its generation open for the queue's retention window instead of closing it at the inference deadline, and I found no defect in the changed lines. Assumptions: ScopeReviewed the one commit after the previously reviewed SHA Verification of the requested changes
Residual notes (not findings): after the 14-day window a manual DLQ redrive could commit a row for an already-settled generation; the stored total would then be stale on Files Reviewed (5 files)
Previous review (commit 578e28a)Status: No Issues Found | Recommendation: Merge Executive SummaryThe follow-up commit adds a deadline-bounded repair path for missing settlement receipts and documents the cross-region row lock, resolving both previously reported findings; no new defects were found in the changed lines. Assumptions: Verification of previous findings
Files Reviewed (3 files)
Previous review (commit c24af34)Status: 2 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
SUGGESTION
Files Reviewed (11 files)
Reviewed by deepseek-flash-latest · Input: 54.1K · Output: 2.4K · Cached: 298.2K Review guidance: REVIEW.md from base branch |
Each generation records the deadline its request enforces. When a settlement record is missing, reconciliation adopts the committed usage rows for that generation once the deadline plus a margin has passed, and stops rechecking generations whose settlement can no longer change. Document why the receipt write takes the primary row lock.
|
Changes requested: the deadline repair can stop reconciliation while a known usage receipt is still queued. At apps/web/src/lib/agent-briefing/summary.ts:543-566, missing committed rows become unreachable after the grace period. The code then clears next_charge_check_at. In the supported staging queue-only mode, queue acceptance precedes persistence, and delayed delivery or redrive can commit usage later. The ordinary sweep then no longer revisits the report, leaving its stored/listed cost stale. No production exposure is claimed; queue-only mode is staging-gated. Keep known queued usage scheduled until authoritative persistence or a terminal delivery result. Do not infer accounting finality from the inference deadline alone. Cover a delayed commit past the grace period through the ordinary sweep/list path. This is source-derived analysis, not an executed queue-redrive reproduction. |
Each generation's settlement record now carries the gateway's delivery outcome and when it was recorded. Reconciliation keeps a queued delivery open for the queue's retention window and settles the total from the committed ledger, so a delivery that lands late is still counted.
|
bot: The settlement record now carries the gateway's delivery outcome and the time it was recorded. Reconciliation keeps a queued outcome open for the usage queue's retention window, so a usage row committed after the inference deadline is still counted: the reconciled total follows the ledger whenever the row lands, and retry becomes available only when every tracked generation is final. Verified end to end through the sweep route on the local stack. With only a queued receipt present, the report stayed scheduled and pending while already-committed usage was included in the total. Once the second row was committed, the next sweep settled the report with the full total and enabled retry. Commit: 30132a3. CI is re-running on the new head. |
…s final Reconciliation skipped its write when the reported charge already matched the ledger, which also kept a charge check time that no longer needed to run. The skip now requires the schedule to be clear, so a final report stops being rechecked once.
|
bot: Sweep proof on d45e3a5, run against the local stack with a reference report row and the real charge-sweep route.
Checks on this head: 3 suites, 60 tests pass; typecheck for |
The fallback anchor is the request deadline from the same request lifetime, not a bound that precedes queue acceptance.
|
bot: Re-ran the same three sweep checks on ac83115 (comment-only delta): queued receipt past the inference deadline stays scheduled and pending with retry unavailable; the settled state appears once the ledger holds the receipt's usage row, with the schedule cleared; a delivery time older than the queue window settles from the committed ledger with the schedule cleared. Suites and typecheck are unchanged from the previous head; CI is running on this one. |
…-consistency # Conflicts: # apps/web/src/lib/agent-briefing/summary.ts
Evidence
Evidence: demonstrated — local dev stack on this VM (Next.js dev server, local Postgres), an owned fake account, the real
agentBriefingtRPC routes over HTTP with that account's token, and the realGET /api/cron/agent-briefingcharge-sweep route. Report rows and usage rows were inserted directly into the local database; no production calls were made.pendingpast the inference deadline, includes the usage rows already committed for that generation incostMicrodollars(300 µ$), and keeps retry unavailable. A retry request at that point answered409 CONFLICT.chargeStatus: settled, clears the charge schedule, and makes retry available; the retry request then proceeds to cost-disclosure validation (400 BAD_REQUEST) instead of409 CONFLICT.Change
committedorqueued) and the time the receipt was written.queuedoutcome keeps its generation open for the usage queue's retention window, measured from the receipt time, and settles from the committed ledger as soon as the row exists. After that window, or for a receipt without an outcome, the request-deadline bound applies.Verification
pnpm --filter web exec jest --runInBand src/lib/agent-briefing src/routers/agent-briefing-router.one-off.test.ts src/routers/agent-briefing-router.test.ts: 8 suites, 122 tests pass, after mergingmain.pnpm --filter web exec jest --runInBand ../../packages/web-shared/src/lib/agent-briefing-usage.test.ts ../../packages/web-shared/src/lib/ai-gateway/handlers/llm-proxy.test.ts: 2 suites, 156 tests pass.pnpm --filter @kilocode/worker-utils test: 46 files, 1032 tests pass.pnpm --filter web typecheck,pnpm --filter @kilocode/web-shared typecheck.Production prerequisites
None.
Proxy answers
Answer: Conservative receipt — one request-scoped settlement record per generation, with same-generation history retained.
Confidence: 0.60
Answer: Deadline-bounded repair against the generation's own enforced deadline.
Confidence: 0.70
Answer: Queue retention window (four days).
Confidence: 0.60
Answer: Fourteen days, the platform maximum, so any supported queue setting is covered.
Confidence: 0.60