Problem
listUsageAuditEvents filters on metadata after Prisma has already truncated the result set. The query asks for take: 100, and only then does JS apply:
return events
.filter((event) => metadataMatchesFilters(event.metadata, filters))
metadataMatchesFilters is what implements the providerId and modelId filters, and neither reaches the where clause — the where only handles createdAt and actorUserId.
So the filter runs over an already-cut window: the admin sees the matching events that happened to fall inside the 100 most recent, not the matching events. There is no truncation indicator in the response either, so the result looks complete.
Location
apps/web/src/lib/services/usage-dashboard.ts:86-106 (listUsageAuditEvents), :30-38 (metadataMatchesFilters)
Impact
Incorrect data on an audit screen, which is precisely where the numbers have to be trustworthy. An admin filtering by provider can conclude an action never happened when it did — it was just older than the 100th most recent event.
Worth noting this is a correctness bug, not a performance one. The take: 100 is fine; applying a filter after it is not.
Suggested fix
Push the metadata predicate into the Prisma where — Postgres JSON path filters are supported (metadata: { path: ['providerId'], equals: filters.providerId }) — so take: 100 cuts the already-filtered set.
If a JSON filter is not viable for some field, the fallback is to paginate until 100 matches are collected, and to return an explicit truncated flag so the UI can say so.
Source: independent verification pass (Claude Opus 5). Not part of the HN-001..HN-063 batch.
Problem
listUsageAuditEventsfilters onmetadataafter Prisma has already truncated the result set. The query asks fortake: 100, and only then does JS apply:metadataMatchesFiltersis what implements theproviderIdandmodelIdfilters, and neither reaches thewhereclause — thewhereonly handlescreatedAtandactorUserId.So the filter runs over an already-cut window: the admin sees the matching events that happened to fall inside the 100 most recent, not the matching events. There is no truncation indicator in the response either, so the result looks complete.
Location
apps/web/src/lib/services/usage-dashboard.ts:86-106(listUsageAuditEvents),:30-38(metadataMatchesFilters)Impact
Incorrect data on an audit screen, which is precisely where the numbers have to be trustworthy. An admin filtering by provider can conclude an action never happened when it did — it was just older than the 100th most recent event.
Worth noting this is a correctness bug, not a performance one. The
take: 100is fine; applying a filter after it is not.Suggested fix
Push the metadata predicate into the Prisma
where— Postgres JSON path filters are supported (metadata: { path: ['providerId'], equals: filters.providerId }) — sotake: 100cuts the already-filtered set.If a JSON filter is not viable for some field, the fallback is to paginate until 100 matches are collected, and to return an explicit
truncatedflag so the UI can say so.Source: independent verification pass (Claude Opus 5). Not part of the HN-001..HN-063 batch.