Skip to content

Fix paid usage settlement across resets, retries and late pricing - #4639

Merged
reachjalil merged 1 commit into
devfrom
fix/managed-usage-settlement
Sep 8, 2026
Merged

reachjalil merged 1 commit into
devfrom
fix/managed-usage-settlement

Conversation

@reachjalil

@reachjalil reachjalil commented Sep 8, 2026 •

Copy link
Copy Markdown
Member

Purpose

Account for already-admitted managed inference without losing late receipts,
charging twice, or undoing an administrator's usage reset. This is the accounting
follow-up deferred from #4471, not a budget or reservation feature.

Changes

  • Use the exact policy-locked admission timestamp for all three original allowance
    windows, including provider-key delays and later key revocation/DPA disablement.
  • Resolve one durable request/event identity across unpriced, priced and repeated
    receipts. Preserve its attribution, original time and once-established charge;
    complete later pricing promotes the same row. Blank/missing prices remain null.
  • Serialize both bucket writers, settlement and admin reset. Retain zero-amount
    reset identities so replay cannot resurrect forgiven usage; repair only genuine
    missing charges. Never rewrite limits or advance current pointers to settle old work.
  • Durably defer missing/ambiguous history and legacy missing-charge rows whose
    prior reset intent is unknowable. Invalid usage is 400; persistence failure is
    retryable 503. No automatic reconciliation scheduler is added.
  • Add one nullable provider_usage JSON column through migration
    0094_managed_usage_facts.sql. Existing ledger rows remain unchanged.

Current dev sync

Signed head 216854919a1c93167f5f44cf649a8892f8e8866b, rebased onto
dev@54a7f0fa978de95806b78cec1d35ec89b7a2ba2c.

The proxy conflict is resolved with both sides retained: accounting supplies the
server-owned original admission timestamp, while merged #4471 retains its stream
flag, cancellation signal, safe model identity, response validation and analytics
cleanup. Both DPA checks remain intact. This PR still targets dev independently;
it does not depend on #4468 or a browser branch.

Verification — Incomplete pending new-head CI and broader proof freshness

Passed on this exact head:

  • OPENWORK_WORLD_PLACE=local pnpm evals:pr specs/paid-usage-settlement.test.ts
    — 1 passed, 0 failed, 0 skipped; 6 assertion records. Real inference HTTP,
    Den/admin-reset routes, disposable SQL and the real migration bootstrap runner.
    It covers concurrent duplicate settlement, partial repair, reset/replay races,
    pricing transitions, persistence failures, ambiguous windows, admission boundary
    delays and late revoked/DPA settlement while neighboring usage stays unchanged.
  • The current run reports placement: local (testkit resolvePlace; isolated app-less Den and inference).

Supporting current checks: the merged proxy/webhook test command passed 71
tests with zero failures/skips; git diff --check passed. No paid generation or
production records used.

Historical, not new-head proof: at 696a45fd2, the separate DPA journey passed
18 assertion records and CI was green after rerunning the packaged-smoke job. Its initial
attempt imported the packaged server and reached a healthy UI but failed the
emptySession readiness assertion; the unchanged rerun passed. This history is
retained, not attributed to a proved baseline cause. The accounting and DPA evidence
were published in separate test-evidence sections below. The accounting receipt is
refreshed for this head; the separate DPA receipt remains historical. New-head CI and
any broader reruns are not yet claimed passed. Human review is still required.

The repository-wide boundary ratchet reports untouched benchmark/engine spec
violations; this new journey crosses real product boundaries. That broad failure
was not control-reproduced in this work, so it is not claimed pre-existing here.
It is separate from the passing focused journeys and required CI checks.

Rollout and limits

Apply the additive migration before new readers/writers and reconcile its sequence
with fresh dev before merging. The large generated snapshot is schema metadata.
Legacy deleted-charge ambiguity intentionally stays deferred: resolving it requires
an explicit operator decision, not a guessed charge. Reset forgives known current
charges, not receipts whose prices have not arrived. Provider priced is not a
promise that deferred history has been reconciled.

No allowances, commercial pricing, strict dollar caps, free-Luna rules, catalog
delivery, UI, credentials, merge or deployment are changed. Live broadcasts and
production migration rollout remain unverified.

Integration

The response reliability change in #4471 is now on dev and is retained by this
integration. Reconcile overlapping paths with #4358 (gateway),
#3648 (status rollover) and #4620 (separate free allowance); none is imported here.

Details: docs/managed-usage-settlement.md.

@vercel

vercel Bot commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
openwork-app Ready Ready Preview Sep 8, 2026 9:27pm UTC
openwork-den Ready Ready Preview Sep 8, 2026 9:27pm UTC
openwork-diagnostics Ready Ready Preview Sep 8, 2026 9:27pm UTC
openwork-landing Ready Ready Preview, v0 Sep 8, 2026 9:27pm UTC

Comment thread evals/specs/paid-usage-settlement.test.ts
diff-warden[bot]
diff-warden Bot previously approved these changes Sep 8, 2026

@diff-warden diff-warden Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warden security clearance: clear. No blocking findings (security or desktop↔den sync) in this diff (696a45fd2982b5d475ca7d9351505f9b3d6d1cb1). Automated clearance satisfies the required-review gate only — a human still reviews and merges. Analysis run

@reachjalil

reachjalil commented Sep 8, 2026 •

Copy link
Copy Markdown
Member Author

Test evidence — dpa-policy-blocks-warm-managed-keys-without-revoking-customer-owned-models-or-an — ✅ passed

SHA 2168549 · engine v1

✅ passed · 18 expectations passed · 0 failed · 0 pending

Supplementary exact-head DPA regression evidence; no screenshots required.

[world] den(local) · [seed] api GET /v1/org · [seed] api PATCH /v1/inference
[probe] eventually(inference admitted and blocked on limits SQL) · eventually(real Stripe checkout retrieval held)
verdict passed · 0 user observations · 2 probes · steps 0/0

ℹ️ ASSERTION — 1. Absent DPA flag permits real managed inference

A pre-issued DB-backed key returned HTTP 200 and the independent upstream saw exactly one authenticated managed request.

  • ✅ PASS Absent DPA flag permits real managed inference — A pre-issued DB-backed key returned HTTP 200 and the independent upstream saw exactly one authenticated managed request.

ℹ️ ASSERTION — 2. Only allowlisted platform administrators may record DPA decisions

Workspace admin and foreign admin received 403, anonymous caller 401, invalid payloads 400; independent storage still had no flag or audit events.

  • ✅ PASS Only allowlisted platform administrators may record DPA decisions — Workspace admin and foreign admin received 403, anonymous caller 401, invalid payloads 400; independent storage still had no flag or audit events.

ℹ️ ASSERTION — 3. Warm-key denial is organization-bound and cannot be spoofed or retried around

Same process, key, bearer and session: completion and models are 403, body/header scope spoofing, fallback payloads and retries add zero upstream calls. Same user in a second organization still completes with its own key; foreign membership does not confer access.

  • ✅ PASS Warm-key denial is organization-bound and cannot be spoofed or retried around — Same process, key, bearer and session: completion and models are 403, body/header scope spoofing, fallback payloads and retries add zero upstream calls. Same user in a second organization still completes with its own key; foreign membership does not confer access.

ℹ️ ASSERTION — 4. Managed denial follows source, not display name

Name-only public PATCH is rejected with 400. A datastore-arranged rename preserves source=openwork; lists still hide it, direct connect stays redacted, and the warm inference key returns 403 with no upstream call. This does not claim public rename support.

  • ✅ PASS Managed denial follows source, not display name — Name-only public PATCH is rejected with 400. A datastore-arranged rename preserves source=openwork; lists still hide it, direct connect stays redacted, and the warm inference key returns 403 with no upstream call. This does not claim public rename support.

ℹ️ ASSERTION — 5. Managed inventory and purchase admission are disabled without breaking connect sync

Usable/manageable lists and resource snapshot hide managed providers. Direct connect stays 200 with null credentials and no models. Enable and both checkout forms return policy 403 without new keys or external HTTP attempts.

  • ✅ PASS Managed inventory and purchase admission are disabled without breaking connect sync — Usable/manageable lists and resource snapshot hide managed providers. Direct connect stays 200 with null credentials and no models. Enable and both checkout forms return policy 403 without new keys or external HTTP attempts.

ℹ️ ASSERTION — 6. GET repair cannot restore missing managed member access

After arranging a missing member provider and revoked member key, both members' inference/list GETs returned 200 without changing stored keys/providers; the owner's pre-issued key remains 403.

  • ✅ PASS GET repair cannot restore missing managed member access — After arranging a missing member provider and revoked member key, both members' inference/list GETs returned 200 without changing stored keys/providers; the owner's pre-issued key remains 403.

ℹ️ ASSERTION — 7. New member acceptance does not provision managed access under DPA

An existing foreign account accepted a real invitation as an ordinary member; its scoped list is empty and independent storage contains no managed key or provider for that new membership.

  • ✅ PASS New member acceptance does not provision managed access under DPA — An existing foreign account accepted a real invitation as an ordinary member; its scoped list is empty and independent storage contains no managed key or provider for that new membership.

ℹ️ ASSERTION — 8. Customer-owned providers survive branding overlap and route with delivered credentials

Owner and member list/connect the custom OpenRouter/OpenWork-branded provider, then use its delivered endpoint, model and credential for real HTTP completions witnessed as authenticated BYOK. Managed key stays blocked. This is a delivered-config client, not an OpenCode runtime claim.

  • ✅ PASS Customer-owned providers survive branding overlap and route with delivered credentials — Owner and member list/connect the custom OpenRouter/OpenWork-branded provider, then use its delivered endpoint, model and credential for real HTTP completions witnessed as authenticated BYOK. Managed key stays blocked. This is a delivered-config client, not an OpenCode runtime claim.

ℹ️ ASSERTION — 9. Ordinary and raw BetterAuth metadata writes cannot set or erase the flag

Strict Den writes rejected extra metadata/flag with 400; raw BetterAuth replacement and creation attempts returned 403. Flag remains true with exactly one approved audit event.

  • ✅ PASS Ordinary and raw BetterAuth metadata writes cannot set or erase the flag — Strict Den writes rejected extra metadata/flag with 400; raw BetterAuth replacement and creation attempts returned 403. Flag remains true with exactly one approved audit event.

ℹ️ ASSERTION — 10. Approved unset restores the original key and records the transition

The warm key returned 200 with explicit false; datastore audit identifies the approving actor, previous true, new false and reason.

  • ✅ PASS Approved unset restores the original key and records the transition — The warm key returned 200 with explicit false; datastore audit identifies the approving actor, previous true, new false and reason.

ℹ️ ASSERTION — 11. Generated SDK carries the DPA body and preserves admin authorization

Generated typed set/unset calls send the flag and reason and return the declared success body, verified against persisted metadata and audit transitions. A workspace admin using the same generated method receives 403 with no mutation or new audit.

  • ✅ PASS Generated SDK carries the DPA body and preserves admin authorization — Generated typed set/unset calls send the flag and reason and return the declared success body, verified against persisted metadata and audit transitions. A workspace admin using the same generated method receives 403 with no mutation or new audit.

ℹ️ ASSERTION — 12. Audit insertion and DPA mutation are atomic

A real audit column outage caused admin PATCH 500; after storage recovery no event was added and the flag stayed false with the original key usable.

  • ✅ PASS Audit insertion and DPA mutation are atomic — A real audit column outage caused admin PATCH 500; after storage recovery no event was added and the flag stayed false with the original key usable.

ℹ️ ASSERTION — 13. Concurrent ordinary/admin metadata changes preserve DPA and unrelated nested data

Three concurrent rounds of branding, capability and DPA updates all returned 200, preserved nested fixture metadata and all requested changes, added one audit each, and kept inference blocked.

  • ✅ PASS Concurrent ordinary/admin metadata changes preserve DPA and unrelated nested data — Three concurrent rounds of branding, capability and DPA updates all returned 200, preserved nested fixture metadata and all requested changes, added one audit each, and kept inference blocked.

ℹ️ ASSERTION — 14. Policy parsing and unavailable storage fail closed

Serialized object true returns 403; malformed JSON, array, scalar, non-boolean flags and real missing metadata column return 503 with zero upstream calls. Restoring absent flag permits the original key.

  • ✅ PASS Policy parsing and unavailable storage fail closed — Serialized object true returns 403; malformed JSON, array, scalar, non-boolean flags and real missing metadata column return 503 with zero upstream calls. Restoring absent flag permits the original key.

ℹ️ ASSERTION — 15. Policy is re-read immediately before dispatch

Independent SQL processlist proved a request had passed initial admission and was blocked on limits. An approved policy change committed before releasing that lock. Same in-flight request returned 403 with zero upstream calls; unset restored 200.

  • ✅ PASS Policy is re-read immediately before dispatch — Independent SQL processlist proved a request had passed initial admission and was blocked on limits. An approved policy change committed before releasing that lock. Same in-flight request returned 403 with zero upstream calls; unset restored 200.

ℹ️ ASSERTION — 16. Delayed checkout sync records purchase history without reactivation

A real SDK checkout retrieval was held over the approved DPA transition. Release returned sync 200 and persisted active purchase quantity 7 plus checkout event ID. Revoked keys, absent managed providers and disabled inference metadata stayed unchanged; zero inference calls.

  • ✅ PASS Delayed checkout sync records purchase history without reactivation — A real SDK checkout retrieval was held over the approved DPA transition. Release returned sync 200 and persisted active purchase quantity 7 plus checkout event ID. Revoked keys, absent managed providers and disabled inference metadata stayed unchanged; zero inference calls.

ℹ️ ASSERTION — 17. Signed delayed Stripe webhooks retain history without managed reactivation

Invalid HMAC was rejected with 400 before any SDK read or history change. Real signature verification accepted completed and async-payment-success events, including repeated deliveries, with event IDs persisted. Keys/providers and disabled inference remained unchanged; no inference upstream calls.

  • ✅ PASS Signed delayed Stripe webhooks retain history without managed reactivation — Invalid HMAC was rejected with 400 before any SDK read or history change. Real signature verification accepted completed and async-payment-success events, including repeated deliveries, with event IDs persisted. Keys/providers and disabled inference remained unchanged; no inference upstream calls.

ℹ️ ASSERTION — 18. Synthetic providers only

Den/inference child environments blank real provider, Stripe and telemetry credentials. Stripe uses only a fixture key and loopback SDK transport. Preload refuses non-loopback HTTP; zero external attempts were recorded and every provider request carried the expected synthetic credential.

  • ✅ PASS Synthetic providers only — Den/inference child environments blank real provider, Stripe and telemetry credentials. Stripe uses only a fixture key and loopback SDK transport. Preload refuses non-loopback HTTP; zero external attempts were recorded and every provider request carried the expected synthetic credential.

Test run created 2026-09-08T21:44:57.538Z · Source: evals/results/test-runs/2026-09-08T21-44-57-538Z-dpa-policy-blocks-warm-managed-keys-without-revoking-customer-owned-models-or-an/test-run.json · Repro: pnpm --dir evals artifacts:publish -- --pr 4639 --test-run 2026-09-08T21-44-57-538Z-dpa-policy-blocks-warm-managed-keys-without-revoking-customer-owned-models-or-an

@reachjalil

Copy link
Copy Markdown
Member Author

Test evidence — paid-usage-keeps-its-admitted-windows-through-retries-reset-repricing-and-revoca — ✅ passed

SHA 2168549 · engine v1

✅ passed · 6 expectations passed · 0 failed · 0 pending

screenshots not attached (gh < 2.99; run brew upgrade gh)

[world] den(local) · [seed] api GET /v1/org · [seed] api PATCH /v1/inference
[probe] eventually(admitted request waiting for provider lookup) · eventually(provider lookup crosses window end)
steps 1 ✅ upgrade an existing paid ledger with the real migration runner, then rerun it (0.3s) · 2 ✅ settle all exhausted windows once, repair a partial write, and keep reset intentional (0.1s) · 3 ✅ retain unpriced facts and promote the same identity without accepting another key's event (0.1s) · 4 ✅ defer overlapping historical windows rather than selecting one arbitrarily (0.0s) · 5 ✅ attribute a provider-key delay to admission time, then settle after revocation and DPA (5.1s)
verdict passed · 0 user observations · 2 probes · steps 5/5

ℹ️ ASSERTION — 1. The additive accounting upgrade preserves paid history and reruns idempotently

The production bootstrap runner applied generated migration 0094 to a 0093 ledger with existing usage; ledger identity/time/cost and migration journal were unchanged on rerun.

  • ✅ PASS The additive accounting upgrade preserves paid history and reruns idempotently — The production bootstrap runner applied generated migration 0094 to a 0093 ledger with existing usage; ledger identity/time/cost and migration journal were unchanged on rerun.

ℹ️ ASSERTION — 2. Legacy reset ambiguity never silently restores forgiven usage

A legacy receipt with no provider facts and a missing charge was acknowledged as durably deferred, not backfilled: old reset deletion is indistinguishable from interrupted settlement.

  • ✅ PASS Legacy reset ambiguity never silently restores forgiven usage — A legacy receipt with no provider facts and a missing charge was acknowledged as durably deferred, not backfilled: old reset deletion is indistinguishable from interrupted settlement.

ℹ️ ASSERTION — 3. Exhaustion does not truncate settlement and reset survives replay

Concurrent receipts charged all three original buckets once without changing limits; a missing charge repaired without double charging, and reset plus replay races preserved zero forgiven identities and the other member's usage.

  • ✅ PASS Exhaustion does not truncate settlement and reset survives replay — Concurrent receipts charged all three original buckets once without changing limits; a missing charge repaired without double charging, and reset plus replay races preserved zero forgiven identities and the other member's usage.

ℹ️ ASSERTION — 4. Pricing and delivery changes do not create a second ledger identity

Missing costs stayed nullable; complete costs promoted one row in place. Changed event IDs, later timestamps, different costs and a cross-key event collision did not alter its identity/time or charge again. Malformed inherited OTLP usage was 400; a real persistence outage was retryable 503.

  • ✅ PASS Pricing and delivery changes do not create a second ledger identity — Missing costs stayed nullable; complete costs promoted one row in place. Changed event IDs, later timestamps, different costs and a cross-key event collision did not alter its identity/time or charge again. Malformed inherited OTLP usage was 400; a real persistence outage was retryable 503.

ℹ️ ASSERTION — 5. Ambiguous history is retained without guessing a charge destination

Overlapping windows caused durable deferral with unchanged charges and bucket totals. After the fixture repaired that overlap, redelivery charged once using the original receipt.

  • ✅ PASS Ambiguous history is retained without guessing a charge destination — Overlapping windows caused durable deferral with unchanged charges and bucket totals. After the fixture repaired that overlap, redelivery charged once using the original receipt.

ℹ️ ASSERTION — 6. Late usage settles original windows without re-enabling revoked or DPA-blocked access

The real provider-key SQL lookup crossed a window boundary; the server trace kept its earlier admission timestamp. After rollover, revocation and DPA marking, all three old buckets settled, current windows/limits stayed identical, replay used durable time and new generation made no upstream call.

  • ✅ PASS Late usage settles original windows without re-enabling revoked or DPA-blocked access — The real provider-key SQL lookup crossed a window boundary; the server trace kept its earlier admission timestamp. After rollover, revocation and DPA marking, all three old buckets settled, current windows/limits stayed identical, replay used durable time and new generation made no upstream call.

Test run created 2026-09-08T21:23:37.595Z · Source: evals/results/test-runs/2026-09-08T21-23-37-594Z-paid-usage-keeps-its-admitted-windows-through-retries-reset-repricing-and-revoca/test-run.json · Repro: pnpm --dir evals artifacts:publish -- --pr 4639 --test-run 2026-09-08T21-23-37-594Z-paid-usage-keeps-its-admitted-windows-through-retries-reset-repricing-and-revoca

@diff-warden diff-warden Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warden security clearance: clear. No blocking findings (security or desktop↔den sync) in this diff (216854919a1c93167f5f44cf649a8892f8e8866b). Automated clearance satisfies the required-review gate only — a human still reviews and merges. Analysis run

@reachjalil
reachjalil merged commit 3bb8d0d into dev Sep 8, 2026
36 checks passed

This branch was successfully deployed

4 active deployments
Preview – openwork-landing — 21685491 Deployed Sep 8, 2026 by vercel[bot]
Preview – openwork-den — 21685491 Deployed Sep 8, 2026 by vercel[bot]
Preview – openwork-app — 21685491 Deployed Sep 8, 2026 by vercel[bot]
Preview – openwork-diagnostics — 21685491 Deployed Sep 8, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant