Skip to content

refactor(usage): let a store answer precomputed [ING-586] - #6428

Merged
vincent-pochet merged 1 commit into
mainfrom
feat/usage-precomputed-store
Sep 18, 2026
Merged

vincent-pochet merged 1 commit into
mainfrom
feat/usage-precomputed-store

Conversation

@vincent-pochet

Copy link
Copy Markdown
Collaborator

Stacked on #6427, which adds the service that builds the bucket set.

Context

A fee computed out of the pre-aggregated ClickHouse buckets is already fresh, so the charge cache
has nothing to add to it: caching it would put back the staleness the buckets remove. Nothing can
express that today, as neither an event store nor the cache knows that some answers need no caching.

Description

  • Add precomputed? to the event stores, false everywhere but on the new UsageBucketStore, a
    decorator answering a covered aggregation from a UsageBucketSet and delegating the rest.
  • Forward the predicate from an aggregation to its store.
  • Take a per-filter bypass on the charge cache middleware, skipping the cache round-trip.
  • Hold one event store provider per charge service, passed in by callers running one of their own.
  • Reuse a single aggregator per pricing bucket, so the aggregation factory is called once where the
    zero-units hydration used to build a second one for the same bucket.

Nothing mints a UsageBucketStore yet, so precomputed? is false and the bypass is never taken.
The routing that reaches for both is the next PR of the stack.

@lago-claude-ai-agent

Copy link
Copy Markdown
Contributor

Automated pre-review (advisory, not a required check) — verdict: HOLD · CI green

HOLD — the new precomputed-store path is not connected to production.

  • Update Events::Stores::Provider#store_for to return a UsageBucketStore when served_from_buckets?; it currently always returns the raw store, so the new wrapper is unused.
  • Pass the aggregator's precomputed? state to ChargeCacheMiddleware#call; no application call supplies the new bypass: argument, so bucket-backed fees would still use the stale fee cache.
  • Add an integration spec through the provider and fee service that proves eligible usage comes from buckets and bypasses the fee cache; the new specs exercise the disconnected pieces only in isolation.

@vincent-pochet
vincent-pochet force-pushed the feat/usage-precomputed-store branch from 05ea5d9 to 5000b01 Compare September 18, 2026 07:38
@vincent-pochet
vincent-pochet force-pushed the feat/usage-precomputed-store branch from 5000b01 to 4f0485c Compare September 18, 2026 07:47
Base automatically changed from feat/usage-bucket-read to main September 18, 2026 07:55
@vincent-pochet
vincent-pochet force-pushed the feat/usage-precomputed-store branch from 4f0485c to 93de086 Compare September 18, 2026 07:56
@lago-claude-ai-agent

Copy link
Copy Markdown
Contributor

Automated pre-review (advisory, not a required check) — verdict: PASS · CI green

PASS — The bucket reader/store, provider threading, aggregator reuse, and cache-bypass contract are consistent with the existing aggregation boundaries and have focused coverage for totals, grouping, fallbacks, delegation, and cache behavior.

Non-blocking: the new store spec places several allow calls directly in examples; project test conventions require those stubs in before blocks.

@vincent-pochet
vincent-pochet force-pushed the feat/usage-precomputed-store branch 3 times, most recently from e6efaa0 to 68ee734 Compare September 18, 2026 08:27
## Context

A fee computed out of the pre-aggregated ClickHouse buckets is already
fresh, so the fee cache has nothing to add to it: caching it would put
back the staleness the buckets remove. Nothing can express that today,
as neither a store nor the fee cache knows that some answers need no
caching.

## Description

Add `precomputed?` to the event stores, false everywhere but on the new
`UsageBucketStore`, a decorator that answers a covered aggregation from a
`UsageBucketSet` and delegates the rest to the store it wraps. An
aggregation forwards the predicate to its store, and the charge cache
middleware takes a per-filter `bypass` that skips the cache round-trip
entirely.

The charge service now holds one event store provider for the whole
computation, passed by callers that run one of their own, and reuses a
single aggregator per pricing bucket. The zero-units hydration used to
build a second aggregator for the same bucket, so the aggregation factory
is now called once where it was called twice.

Nothing mints a `UsageBucketStore` yet, so `precomputed?` is false and the
bypass is never taken: the routing that does comes next.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vincent-pochet
vincent-pochet force-pushed the feat/usage-precomputed-store branch from 68ee734 to bd343d9 Compare September 18, 2026 08:30
@lago-claude-ai-agent

Copy link
Copy Markdown
Contributor

Automated pre-review (advisory, not a required check) — verdict: PASS · CI green

PASS — The preparatory store decorator, provider reuse, cache bypass, and aggregator memoization are consistent with the existing interfaces, and the added specs cover their substantive behavior.

Non-blocking: the guard-clause modifiers in grouped_count and grouped_sum conflict with the repository guidance to avoid modifiers immediately before a method's final expression.

@vincent-pochet
vincent-pochet merged commit fd86ea2 into main Sep 18, 2026
12 checks passed
@vincent-pochet
vincent-pochet deleted the feat/usage-precomputed-store branch September 18, 2026 09:51
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.

2 participants