diff --git a/apps/web/src/app/admin/cloud-billing-skus/UsageRecordsContent.tsx b/apps/web/src/app/admin/cloud-billing-skus/UsageRecordsContent.tsx index 04ddbbb909c..a70dae3b8f9 100644 --- a/apps/web/src/app/admin/cloud-billing-skus/UsageRecordsContent.tsx +++ b/apps/web/src/app/admin/cloud-billing-skus/UsageRecordsContent.tsx @@ -68,6 +68,7 @@ type UsageSummaryRequest = { start: string; end: string; }; +type UsageReconciliationRequest = UsageSummaryRequest & { intervalIds: string[] }; function formatTimestamp(value: string | null): string { return value ? new Date(value).toLocaleString() : '—'; @@ -85,6 +86,8 @@ function assertNever(value: never): never { function reconciliationStatusLabel(status: ReconciliationStatus): string { switch (status) { + case 'compared': + return 'Compared'; case 'missing_from_cloudflare': return 'Missing from Cloudflare'; case 'ambiguous_application': @@ -99,6 +102,8 @@ function reconciliationStatusLabel(status: ReconciliationStatus): string { function reconciliationStatusVariant(status: ReconciliationStatus) { switch (status) { + case 'compared': + return 'new' as const; case 'missing_from_cloudflare': return 'destructive' as const; case 'ambiguous_application': @@ -111,9 +116,9 @@ function reconciliationStatusVariant(status: ReconciliationStatus) { return assertNever(status); } -function sameSummaryRequest( - first: UsageSummaryRequest | null | undefined, - second: UsageSummaryRequest | null | undefined +function sameReconciliationRequest( + first: UsageReconciliationRequest | null | undefined, + second: UsageReconciliationRequest | null | undefined ): boolean { return ( first !== null && @@ -123,7 +128,9 @@ function sameSummaryRequest( first.subjectType === second.subjectType && first.subjectId === second.subjectId && first.start === second.start && - first.end === second.end + first.end === second.end && + first.intervalIds.length === second.intervalIds.length && + first.intervalIds.every((intervalId, index) => intervalId === second.intervalIds[index]) ); } @@ -132,6 +139,15 @@ function formatProvisionedCapacity(memoryBytes: number | null, diskBytes: number return `${formatProviderNumber(memoryBytes / 1024 ** 3)} GiB memory · ${formatProviderNumber(diskBytes / 1_000_000_000)} GB disk`; } +function formatVariance(seconds: number | null, percent: number | null): string { + if (seconds === null) return 'Variance unavailable'; + const secondsSign = seconds > 0 ? '+' : ''; + if (percent === null) + return `${secondsSign}${formatProviderNumber(seconds)}s (no meter baseline)`; + const percentSign = percent > 0 ? '+' : ''; + return `${secondsSign}${formatProviderNumber(seconds)}s (${percentSign}${formatProviderNumber(percent)}%)`; +} + function toDateTimeLocalValue(value: Date): string { const offset = value.getTimezoneOffset() * 60_000; return new Date(value.getTime() - offset).toISOString().slice(0, 16); @@ -307,9 +323,10 @@ export default function UsageRecordsContent() { closeReason: submitted.closeReason, skuId: submitted.skuId, cursor, - limit: submitted.kind === 'recent' ? 10 : 25, + limit: submitted.kind === 'recent' ? 10 : 15, }; const results = useQuery(trpc.admin.cloudBillingSkus.searchUsageIntervals.queryOptions(input)); + const rows = results.data?.items ?? []; const summary = useQuery({ ...trpc.admin.cloudBillingSkus.getUsageSummary.queryOptions( summaryRequest ?? { @@ -326,11 +343,17 @@ export default function UsageRecordsContent() { trpc.admin.cloudBillingSkus.reconcileUsageWithCloudflare.mutationOptions() ); const resetReconciliation = reconciliation.reset; - const reconciliationMatchesSummary = sameSummaryRequest(reconciliation.variables, summaryRequest); + const reconciliationRequest = + summaryRequest && results.isSuccess && rows.length > 0 + ? { ...summaryRequest, intervalIds: rows.map(row => row.id) } + : null; + const reconciliationMatchesScope = sameReconciliationRequest( + reconciliation.variables, + reconciliationRequest + ); const reconciliationErrorCode = reconciliation.error?.data?.code; const reconciliationCanRetry = reconciliationErrorCode !== 'BAD_REQUEST' && reconciliationErrorCode !== 'PRECONDITION_FAILED'; - const rows = results.data?.items ?? []; const resetResultNavigation = () => { setCursor(undefined); @@ -598,7 +621,8 @@ export default function UsageRecordsContent() { aria-describedby={ summaryInputError ? 'usage-summary-window-error' : undefined } - className="w-full sm:w-[9.5rem]" + className="w-full cursor-pointer sm:w-52 [&::-webkit-calendar-picker-indicator]:cursor-pointer" + onClick={event => event.currentTarget.showPicker?.()} onChange={event => setSummaryStart(event.target.value)} /> event.currentTarget.showPicker?.()} onChange={event => setSummaryEnd(event.target.value)} /> @@ -740,25 +765,27 @@ export default function UsageRecordsContent() {

Cloudflare reconciliation

- Query Cloudflare only for physical instance IDs recorded for this applied - subject and window. This is shadow validation and does not change usage or + Query Cloudflare only for physical instance IDs in the usage records currently + displayed below. This is shadow validation and does not change usage or billing.

- {reconciliationMatchesSummary && reconciliation.isError && ( + {reconciliationMatchesScope && reconciliation.isError && ( Cloudflare reconciliation could not be completed @@ -769,7 +796,9 @@ export default function UsageRecordsContent() { variant="outline" size="sm" disabled={reconciliation.isPending} - onClick={() => reconciliation.mutate(summaryRequest)} + onClick={() => { + if (reconciliationRequest) reconciliation.mutate(reconciliationRequest); + }} > Retry reconciliation @@ -778,7 +807,7 @@ export default function UsageRecordsContent() { )} - {reconciliationMatchesSummary && reconciliation.isSuccess && ( + {reconciliationMatchesScope && reconciliation.isSuccess && (
{reconciliation.data.rows.length === 0 ? (

@@ -788,8 +817,7 @@ export default function UsageRecordsContent() { ) : ( <>

- {reconciliation.data.comparison.description} Provider CPU is shown only as - a diagnostic. + {reconciliation.data.comparison.description}

@@ -802,14 +830,15 @@ export default function UsageRecordsContent() {
-
Instances queried
+
Runs queried
- {reconciliation.data.totals.queriedCloudflareInstances.toLocaleString()} + {reconciliation.data.totals.queriedCloudflareRuns.toLocaleString()}

+ {reconciliation.data.counts.compared} compared ·{' '} {reconciliation.data.counts.missing} missing ·{' '} {reconciliation.data.counts.ambiguous} ambiguous ·{' '} {reconciliation.data.counts.partial} partial ·{' '} @@ -840,17 +869,15 @@ export default function UsageRecordsContent() { Instance Application / service SKU(s) - Meter accepted - Provider allocation equivalents - Provider CPU + Meter run + Cloudflare memory / disk + Cloudflare CPU (diagnostic) Status {reconciliation.data.rows.map(row => ( - + {row.instanceId} @@ -883,17 +910,37 @@ export default function UsageRecordsContent() { - {row.meterAcceptedSeconds.toLocaleString()}s + + {row.meterAcceptedSeconds.toLocaleString()}s accepted + + + {formatTimestamp(row.meterStartedAt)} + + + to {formatTimestamp(row.meterEndedAt)} + Memory {formatProviderNumber(row.providerMemorySeconds)} {row.providerMemorySeconds === null ? '' : 's'} - + + {formatVariance( + row.providerMemoryDifferenceSeconds, + row.providerMemoryDifferencePercent + )} + + Disk {formatProviderNumber(row.providerDiskSeconds)} {row.providerDiskSeconds === null ? '' : 's'} + + {formatVariance( + row.providerDiskDifferenceSeconds, + row.providerDiskDifferencePercent + )} + {formatProviderNumber(row.providerCpuTimeSec)} @@ -969,14 +1016,13 @@ export default function UsageRecordsContent() { {reconciliation.data.provider.rawResponses.map((raw, index) => (

- {raw.dataset} · window {raw.windowIndex + 1} · batch{' '} - {raw.batchIndex + 1} - {raw.window - ? ` · ${formatTimestamp(raw.window.start)} to ${formatTimestamp(raw.window.end)}` + {raw.dataset} + {raw.queries.length > 0 + ? ` · batch ${raw.batchIndex} · ${raw.queries.length} window${raw.queries.length === 1 ? '' : 's'}` : ''}

diff --git a/apps/web/src/lib/cloudflare/container-usage-analytics.test.ts b/apps/web/src/lib/cloudflare/container-usage-analytics.test.ts
index 943bf09e379..77413b165cd 100644
--- a/apps/web/src/lib/cloudflare/container-usage-analytics.test.ts
+++ b/apps/web/src/lib/cloudflare/container-usage-analytics.test.ts
@@ -21,9 +21,14 @@ const USAGE_FIELDS = [
   'sum_txBytes',
 ];
 const input = {
-  instanceIds: ['instance-1'],
-  start: '2026-07-01T00:00:00.000Z',
-  end: '2026-07-01T01:00:00.000Z',
+  runs: [
+    {
+      key: 'run-1',
+      instanceId: 'instance-1',
+      start: '2026-07-01T00:00:00.000Z',
+      end: '2026-07-01T01:00:00.000Z',
+    },
+  ],
 };
 const options: ContainerUsageAnalyticsOptions = {
   accountId: ACCOUNT_ID,
@@ -67,21 +72,30 @@ function settingsBody(
   };
 }
 
+type UsageGroup = {
+  dimensions: { applicationId: string; instanceId: string };
+  sum: { cpuTimeSec: number; allocatedMemory: number; allocatedDisk: number; txBytes: number };
+};
+
 function usageBody(
-  groups: Array<{
-    dimensions: { applicationId: string; instanceId: string };
-    sum: { cpuTimeSec: number; allocatedMemory: number; allocatedDisk: number; txBytes: number };
-  }> = [],
+  groups: UsageGroup[] = [],
   errors: Array<{ message: string }> | null = null,
   extra: Record = {}
 ) {
   return {
-    data: { viewer: { accounts: [{ containersUsageAdaptiveGroups: groups }] } },
+    data: { viewer: { accounts: [{ u0: groups }] } },
     errors,
     ...extra,
   };
 }
 
+function usageBatchBody(
+  aliases: Record,
+  errors: Array<{ message: string; path?: Array }> | null = null
+) {
+  return { data: { viewer: { accounts: [aliases] } }, errors };
+}
+
 function response(body: unknown, init: ResponseInit = {}) {
   return new Response(typeof body === 'string' ? body : JSON.stringify(body), {
     status: 200,
@@ -120,16 +134,18 @@ describe('queryContainerUsageAnalytics', () => {
     expect(fetch).toHaveBeenCalledTimes(2);
     expect(requests[0]?.body.variables).toEqual({ accountTag: ACCOUNT_ID });
     expect(requests[1]?.headers.get('authorization')).toBe(`Bearer ${API_TOKEN}`);
-    expect(requests[1]?.body.query).toContain('datetime_lt: $datetimeEnd');
-    expect(requests[1]?.body.query).toContain('instanceId_in: $instanceIds');
+    expect(requests[1]?.body.query).toContain('u0: containersUsageAdaptiveGroups');
+    expect(requests[1]?.body.query).toContain('datetime_lt: $datetimeEnd0');
+    expect(requests[1]?.body.query).toContain('instanceId_in: $instanceIds0');
     expect(requests[1]?.body.variables).toEqual({
       accountTag: ACCOUNT_ID,
-      datetimeStart: input.start,
-      datetimeEnd: input.end,
-      instanceIds: ['instance-1'],
+      datetimeStart0: input.runs[0]?.start,
+      datetimeEnd0: input.runs[0]?.end,
+      instanceIds0: ['instance-1'],
     });
     expect(result.rows).toEqual([
       {
+        runKey: 'run-1',
         applicationId: 'observed-app',
         instanceId: 'instance-1',
         usage: providerRow.sum,
@@ -143,6 +159,93 @@ describe('queryContainerUsageAnalytics', () => {
     expect(JSON.stringify(result)).not.toContain('authorization');
   });
 
+  it('keeps reused instance IDs isolated by alias and marks only the errored run partial', async () => {
+    const runs = [
+      input.runs[0]!,
+      {
+        key: 'run-2',
+        instanceId: 'instance-1',
+        start: '2026-07-01T02:00:00.000Z',
+        end: '2026-07-01T03:00:00.000Z',
+      },
+    ];
+    const { fetch } = requestCapture((_request, index) =>
+      response(
+        index === 0
+          ? settingsBody()
+          : usageBatchBody(
+              {
+                u0: [
+                  {
+                    dimensions: { applicationId: 'app', instanceId: 'instance-1' },
+                    sum: { cpuTimeSec: 1, allocatedMemory: 10, allocatedDisk: 20, txBytes: 30 },
+                  },
+                ],
+                u1: [
+                  {
+                    dimensions: { applicationId: 'app', instanceId: 'instance-1' },
+                    sum: { cpuTimeSec: 2, allocatedMemory: 100, allocatedDisk: 200, txBytes: 300 },
+                  },
+                ],
+              },
+              [{ message: 'run 2 partial', path: ['ContainerUsage', 'u1'] }]
+            )
+      )
+    );
+
+    const result = await queryContainerUsageAnalytics({ runs }, { ...options, fetch });
+
+    expect(result.rows).toEqual([
+      expect.objectContaining({
+        runKey: 'run-1',
+        usage: expect.objectContaining({ allocatedMemory: 10 }),
+      }),
+      expect.objectContaining({
+        runKey: 'run-2',
+        usage: expect.objectContaining({ allocatedMemory: 100 }),
+      }),
+    ]);
+    expect(result.usagePartialRunKeys).toEqual(['run-2']);
+    expect(result.issues).toEqual([
+      expect.stringContaining('run run-2 window 0 returned partial data: run 2 partial'),
+    ]);
+    expect(result.issues.join(' ')).not.toContain('run run-1');
+  });
+
+  it('fails an unscoped batched GraphQL error without retry fan-out', async () => {
+    const runs = [
+      input.runs[0]!,
+      {
+        key: 'run-2',
+        instanceId: 'instance-2',
+        start: '2026-07-01T02:00:00.000Z',
+        end: '2026-07-01T03:00:00.000Z',
+      },
+    ];
+    const providerRows: UsageGroup[] = runs.map((run, index) => ({
+      dimensions: { applicationId: 'app', instanceId: run.instanceId },
+      sum: {
+        cpuTimeSec: index + 1,
+        allocatedMemory: (index + 1) * 10,
+        allocatedDisk: (index + 1) * 20,
+        txBytes: (index + 1) * 30,
+      },
+    }));
+    const { fetch } = requestCapture((_request, index) => {
+      if (index === 0) return response(settingsBody());
+      return response(
+        usageBatchBody({ u0: [providerRows[0]!], u1: [providerRows[1]!] }, [
+          { message: 'batch partial' },
+        ])
+      );
+    });
+
+    await expect(
+      queryContainerUsageAnalytics({ runs }, { ...options, fetch })
+    ).rejects.toMatchObject({ code: 'graphql_error' });
+    expect(fetch).toHaveBeenCalledTimes(2);
+  });
+
   it.each([
     ['HTTP failure', () => response({ error: 'denied' }, { status: 403 }), 'http_error'],
     ['invalid JSON', () => response('bad gateway'), 'invalid_json'],
@@ -178,7 +281,7 @@ describe('queryContainerUsageAnalytics', () => {
     );
     const result = await queryContainerUsageAnalytics(input, { ...options, fetch: partial.fetch });
     expect(result.partial).toBe(true);
-    expect(result.usagePartialInstanceIds).toEqual(['instance-1']);
+    expect(result.usagePartialRunKeys).toEqual(['run-1']);
     expect(result.rows).toHaveLength(1);
   });
 
@@ -207,25 +310,38 @@ describe('queryContainerUsageAnalytics', () => {
     }
   });
 
-  it('chunks by live duration and batches exact IDs below the page limit', async () => {
-    const ids = Array.from({ length: 51 }, (_, index) => `instance-${index}`);
+  it('batches up to 15 independently filtered run windows per usage request', async () => {
+    const runs = Array.from({ length: 16 }, (_, index) => ({
+      key: index === 0 ? 'interval:with:colons' : `run-${index}`,
+      instanceId: `instance-${index}`,
+      start: '2026-07-01T00:00:00.000Z',
+      end: '2026-07-01T01:00:00.000Z',
+    }));
     const { fetch, requests } = requestCapture((_request, index) =>
-      response(index === 0 ? settingsBody({ maxDuration: 3_600, maxPageSize: 100 }) : usageBody())
+      response(
+        index === 0
+          ? settingsBody({ maxDuration: 3_600, maxPageSize: 100 })
+          : usageBatchBody(
+              Object.fromEntries(
+                Array.from({ length: index === 1 ? 15 : 1 }, (_, aliasIndex) => [
+                  `u${aliasIndex}`,
+                  [],
+                ])
+              )
+            )
+      )
     );
 
-    await queryContainerUsageAnalytics(
-      { instanceIds: ids, start: input.start, end: '2026-07-01T02:00:00.000Z' },
-      { ...options, fetch }
-    );
+    const result = await queryContainerUsageAnalytics({ runs }, { ...options, fetch });
 
-    expect(fetch).toHaveBeenCalledTimes(5);
+    expect(fetch).toHaveBeenCalledTimes(3);
     const queries = requests.slice(1);
-    expect(new Set(queries.map(item => item.body.variables.instanceIds.length))).toEqual(
-      new Set([1, 50])
-    );
-    expect(new Set(queries.map(item => item.body.variables.datetimeStart))).toEqual(
-      new Set(['2026-07-01T00:00:00.000Z', '2026-07-01T01:00:00.000Z'])
-    );
+    expect(queries[0]?.body.variables.instanceIds14).toEqual(['instance-14']);
+    expect(queries[1]?.body.variables.instanceIds0).toEqual(['instance-15']);
+    expect(queries[0]?.body.query).not.toContain('interval:with:colons');
+    expect(result.rawResponses).toHaveLength(3);
+    expect(result.rawResponses[1]?.queries).toHaveLength(15);
+    expect(result.rawResponses[1]?.queries[0]?.runKey).toBe('interval:with:colons');
   });
 
   it('marks a full page partial and rejects request plans above the cap', async () => {
@@ -249,7 +365,7 @@ describe('queryContainerUsageAnalytics', () => {
       ...options,
       fetch: fullPage.fetch,
     });
-    expect(partial.usagePartialInstanceIds).toEqual(['instance-1']);
+    expect(partial.usagePartialRunKeys).toEqual(['run-1']);
 
     const requestCap = requestCapture((_request, index) =>
       response(index === 0 ? settingsBody({ maxPageSize: 2, maxDuration: 3_600 }) : usageBody())
@@ -257,9 +373,12 @@ describe('queryContainerUsageAnalytics', () => {
     await expect(
       queryContainerUsageAnalytics(
         {
-          instanceIds: Array.from({ length: 50 }, (_, index) => `instance-${index}`),
-          start: input.start,
-          end: '2026-07-02T00:00:00.000Z',
+          runs: Array.from({ length: 5 }, (_, index) => ({
+            key: `run-${index}`,
+            instanceId: `instance-${index}`,
+            start: '2026-07-01T00:00:00.000Z',
+            end: '2026-07-02T00:00:00.000Z',
+          })),
         },
         { ...options, fetch: requestCap.fetch }
       )
@@ -296,7 +415,7 @@ describe('queryContainerUsageAnalytics', () => {
                 viewer: {
                   accounts: [
                     {
-                      containersUsageAdaptiveGroups: [
+                      u0: [
                         {
                           dimensions: { applicationId: 'app', instanceId: 'instance-1' },
                           sum: { cpuTimeSec: 1, allocatedMemory: 2, txBytes: 3 },
@@ -315,7 +434,7 @@ describe('queryContainerUsageAnalytics', () => {
     });
   });
 
-  it('marks retention clipping partial and rejects fully expired windows', async () => {
+  it('marks retention clipping partial and skips fully expired runs without blocking valid runs', async () => {
     const retained = requestCapture((_request, index) =>
       response(index === 0 ? settingsBody({ notOlderThan: 84_600 }) : usageBody())
     );
@@ -324,11 +443,33 @@ describe('queryContainerUsageAnalytics', () => {
       fetch: retained.fetch,
     });
     expect(partial.partial).toBe(true);
-    expect(partial.usagePartialInstanceIds).toEqual(['instance-1']);
+    expect(partial.usagePartialRunKeys).toEqual(['run-1']);
 
-    const expired = requestCapture(() => response(settingsBody({ notOlderThan: 3_600 })));
-    await expect(
-      queryContainerUsageAnalytics(input, { ...options, fetch: expired.fetch })
-    ).rejects.toMatchObject({ code: 'outside_retention' });
+    const validProviderRow = {
+      dimensions: { applicationId: 'app', instanceId: 'instance-2' },
+      sum: { cpuTimeSec: 1, allocatedMemory: 2, allocatedDisk: 3, txBytes: 4 },
+    };
+    const expired = requestCapture((_request, index) =>
+      response(index === 0 ? settingsBody({ notOlderThan: 3_600 }) : usageBody([validProviderRow]))
+    );
+    const result = await queryContainerUsageAnalytics(
+      {
+        runs: [
+          input.runs[0]!,
+          {
+            key: 'valid-run',
+            instanceId: 'instance-2',
+            start: '2026-07-01T23:30:00.000Z',
+            end: '2026-07-01T23:45:00.000Z',
+          },
+        ],
+      },
+      { ...options, fetch: expired.fetch }
+    );
+    expect(expired.fetch).toHaveBeenCalledTimes(2);
+    expect(result.usageUnavailableRuns).toEqual([{ runKey: 'run-1', reason: 'outside_retention' }]);
+    expect(result.rows).toEqual([
+      expect.objectContaining({ runKey: 'valid-run', instanceId: 'instance-2' }),
+    ]);
   });
 });
diff --git a/apps/web/src/lib/cloudflare/container-usage-analytics.ts b/apps/web/src/lib/cloudflare/container-usage-analytics.ts
index d8d24a1df18..ab948c4ea74 100644
--- a/apps/web/src/lib/cloudflare/container-usage-analytics.ts
+++ b/apps/web/src/lib/cloudflare/container-usage-analytics.ts
@@ -9,13 +9,17 @@ const DATASET = 'containersUsageAdaptiveGroups' as const;
 const DEFAULT_TIMEOUT_MS = 10_000;
 const MAX_RAW_RESPONSE_BYTES = 1024 * 1024;
 const MAX_RETAINED_RAW_BYTES = 4 * 1024 * 1024;
-const MAX_INSTANCE_BATCH_SIZE = 50;
-const MAX_PROVIDER_REQUESTS = 100;
+const MAX_PROVIDER_QUERY_PLANS = 100;
+// Cloudflare applies maxNumberOfFields per aliased dataset selection, not across aliases.
+const MAX_RUN_WINDOWS_PER_REQUEST = 15;
 
 export type ContainerUsageAnalyticsInput = {
-  instanceIds: string[];
-  start: string;
-  end: string;
+  runs: Array<{
+    key: string;
+    instanceId: string;
+    start: string;
+    end: string;
+  }>;
 };
 
 export type ContainerUsageAnalyticsOptions = {
@@ -37,13 +41,18 @@ export type ContainerDatasetSettings = {
 
 export type ContainerUsageAnalyticsRawResponse = {
   dataset: typeof DATASET | 'settings';
-  windowIndex: number;
   batchIndex: number;
-  window: { start: string; end: string } | null;
+  queries: Array<{
+    alias: string;
+    runKey: string;
+    windowIndex: number;
+    window: { start: string; end: string };
+  }>;
   body: unknown;
 };
 
 export type ContainerUsageAnalyticsRow = {
+  runKey: string;
   applicationId: string;
   instanceId: string;
   usage: {
@@ -57,7 +66,8 @@ export type ContainerUsageAnalyticsRow = {
 export type ContainerUsageAnalyticsResult = {
   rows: ContainerUsageAnalyticsRow[];
   partial: boolean;
-  usagePartialInstanceIds: string[];
+  usagePartialRunKeys: string[];
+  usageUnavailableRuns: Array<{ runKey: string; reason: 'outside_retention' }>;
   issues: string[];
   settings: { containersUsageAdaptiveGroups: ContainerDatasetSettings };
   rawResponses: ContainerUsageAnalyticsRawResponse[];
@@ -83,7 +93,14 @@ const DatasetSettingsSchema = z.object({
 });
 
 const GraphqlErrorsSchema = z
-  .array(z.object({ message: z.string().optional() }).passthrough())
+  .array(
+    z
+      .object({
+        message: z.string().optional(),
+        path: z.array(z.union([z.string(), z.number()])).optional(),
+      })
+      .passthrough()
+  )
   .nullish();
 
 const SettingsResponseSchema = z.object({
@@ -123,9 +140,7 @@ const UsageResponseSchema = z.object({
       viewer: z
         .object({
           accounts: z
-            .array(
-              z.object({ containersUsageAdaptiveGroups: z.array(UsageGroupSchema).optional() })
-            )
+            .array(z.record(z.string(), z.array(UsageGroupSchema).nullable()).nullable())
             .optional(),
         })
         .optional(),
@@ -152,27 +167,43 @@ query ContainerUsageAnalyticsSettings($accountTag: String!) {
   }
 }`;
 
-function usageQuery(limit: number): string {
-  return `
-query ContainerUsage(
-  $accountTag: String!
-  $datetimeStart: Time!
-  $datetimeEnd: Time!
-  $instanceIds: [String!]
-) {
-  viewer {
-    accounts(filter: { accountTag: $accountTag }) {
-      containersUsageAdaptiveGroups(
+type QueryPlan = {
+  run: { key: string; instanceId: string };
+  window: { start: string; end: string };
+  windowIndex: number;
+};
+
+function usageQuery(limit: number, plans: QueryPlan[]): string {
+  const variableDefinitions = plans
+    .map(
+      (_plan, index) =>
+        `$datetimeStart${index}: Time!\n  $datetimeEnd${index}: Time!\n  $instanceIds${index}: [String!]`
+    )
+    .join('\n  ');
+  const fields = plans
+    .map(
+      (_plan, index) => `
+      u${index}: containersUsageAdaptiveGroups(
         limit: ${limit}
         filter: {
-          datetime_geq: $datetimeStart
-          datetime_lt: $datetimeEnd
-          instanceId_in: $instanceIds
+          datetime_geq: $datetimeStart${index}
+          datetime_lt: $datetimeEnd${index}
+          instanceId_in: $instanceIds${index}
         }
       ) {
         dimensions { applicationId instanceId }
         sum { cpuTimeSec allocatedMemory allocatedDisk txBytes }
-      }
+      }`
+    )
+    .join('\n');
+  return `
+query ContainerUsage(
+  $accountTag: String!
+  ${variableDefinitions}
+) {
+  viewer {
+    accounts(filter: { accountTag: $accountTag }) {
+      ${fields}
     }
   }
 }`;
@@ -333,18 +364,35 @@ export async function queryContainerUsageAnalytics(
     );
   }
 
-  const startMs = parseTime(input.start, 'start');
-  const endMs = parseTime(input.end, 'end');
-  if (endMs <= startMs) {
-    throw new ContainerUsageAnalyticsError('invalid_input', 'end must be after start.');
-  }
-  const instanceIds = [...new Set(input.instanceIds.filter(id => id.length > 0))];
+  const runKeys = new Set();
+  const runs = input.runs.map(run => {
+    if (!run.key || !run.instanceId) {
+      throw new ContainerUsageAnalyticsError(
+        'invalid_input',
+        'Each run must include a key and instance ID.'
+      );
+    }
+    if (runKeys.has(run.key)) {
+      throw new ContainerUsageAnalyticsError('invalid_input', `Duplicate run key: ${run.key}`);
+    }
+    runKeys.add(run.key);
+    const startMs = parseTime(run.start, `start for ${run.key}`);
+    const endMs = parseTime(run.end, `end for ${run.key}`);
+    if (endMs <= startMs) {
+      throw new ContainerUsageAnalyticsError(
+        'invalid_input',
+        `end must be after start for ${run.key}.`
+      );
+    }
+    return { ...run, startMs, endMs };
+  });
   const fetchImpl = options.fetch ?? fetch;
   const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
   const retainedBytes = { value: 0 };
   const rawResponses: ContainerUsageAnalyticsRawResponse[] = [];
   const issues: string[] = [];
   const partialIds = new Set();
+  const unavailableRuns: ContainerUsageAnalyticsResult['usageUnavailableRuns'] = [];
 
   const settingsBody = await postGraphql({
     fetchImpl,
@@ -363,9 +411,8 @@ export async function queryContainerUsageAnalytics(
   }
   rawResponses.push({
     dataset: 'settings',
-    windowIndex: 0,
     batchIndex: 0,
-    window: null,
+    queries: [],
     body: settingsBody,
   });
   const settingsErrors = graphqlErrors(settingsResponse.data.errors);
@@ -381,99 +428,146 @@ export async function queryContainerUsageAnalytics(
   const settings = validateSettings(account.settings?.containersUsageAdaptiveGroups);
   if (settingsErrors.length > 0) {
     issues.push(`Settings query reported GraphQL errors: ${settingsErrors.join('; ')}`);
-    for (const id of instanceIds) partialIds.add(id);
+    for (const run of runs) partialIds.add(run.key);
   }
 
   const nowMs = (options.now ?? (() => new Date()))().getTime();
   const oldestAllowedMs = nowMs - settings.notOlderThan * 1000;
-  if (endMs <= oldestAllowedMs) {
-    throw new ContainerUsageAnalyticsError(
-      'outside_retention',
-      'The requested window is outside Cloudflare Analytics retention. Choose a more recent window.'
-    );
-  }
-  const effectiveStartMs = Math.max(startMs, oldestAllowedMs);
-  if (effectiveStartMs !== startMs) {
-    issues.push('Results cover only the portion of the window retained by Cloudflare Analytics.');
-    for (const id of instanceIds) partialIds.add(id);
-  }
-
   const settingsSummary = { containersUsageAdaptiveGroups: settings };
-  if (instanceIds.length === 0) {
+  if (runs.length === 0) {
     return {
       rows: [],
       partial: issues.length > 0,
-      usagePartialInstanceIds: [],
+      usagePartialRunKeys: [],
+      usageUnavailableRuns: [],
       issues,
       settings: settingsSummary,
       rawResponses,
     };
   }
 
-  const timeWindows = windows(effectiveStartMs, endMs, settings.maxDuration);
-  // Leave one row of headroom: one row per requested ID is complete, while a full
-  // page means an extra application row may have truncated the response. A complete
-  // multi-application ID can therefore be conservatively marked partial.
-  const idBatches = batches(
-    instanceIds,
-    Math.min(MAX_INSTANCE_BATCH_SIZE, settings.maxPageSize - 1)
-  );
-  const requestCount = 1 + timeWindows.length * idBatches.length;
-  if (requestCount > MAX_PROVIDER_REQUESTS) {
+  const queryPlans = runs.flatMap(run => {
+    if (run.endMs <= oldestAllowedMs) {
+      unavailableRuns.push({ runKey: run.key, reason: 'outside_retention' });
+      issues.push(`Run ${run.key} is outside Cloudflare Analytics retention.`);
+      return [];
+    }
+    const effectiveStartMs = Math.max(run.startMs, oldestAllowedMs);
+    if (effectiveStartMs !== run.startMs) {
+      issues.push(`Run ${run.key} covers only retained Cloudflare Analytics data.`);
+      partialIds.add(run.key);
+    }
+    return windows(effectiveStartMs, run.endMs, settings.maxDuration).map(
+      (window, windowIndex) => ({
+        run,
+        window,
+        windowIndex,
+      })
+    );
+  });
+  if (queryPlans.length > MAX_PROVIDER_QUERY_PLANS) {
     throw new ContainerUsageAnalyticsError(
       'request_limit_exceeded',
-      `Cloudflare Analytics would require ${requestCount} requests (max ${MAX_PROVIDER_REQUESTS}). Narrow the window and retry.`
+      `The selected runs require ${queryPlans.length} Cloudflare Analytics query plans (max ${MAX_PROVIDER_QUERY_PLANS}). Select fewer or shorter runs and retry.`
     );
   }
 
   const rows = new Map();
-  for (let windowIndex = 0; windowIndex < timeWindows.length; windowIndex += 1) {
-    const window = timeWindows[windowIndex];
-    if (!window) continue;
-    for (let batchIndex = 0; batchIndex < idBatches.length; batchIndex += 1) {
-      const batch = idBatches[batchIndex];
-      if (!batch) continue;
-      const body = await postGraphql({
-        fetchImpl,
-        token,
-        timeoutMs,
-        query: usageQuery(settings.maxPageSize),
-        variables: {
-          accountTag: accountId,
-          datetimeStart: window.start,
-          datetimeEnd: window.end,
-          instanceIds: batch,
-        },
-        retainedBytes,
-      });
-      rawResponses.push({ dataset: DATASET, windowIndex, batchIndex, window, body });
-      const response = UsageResponseSchema.safeParse(body);
-      if (!response.success) {
-        throw new ContainerUsageAnalyticsError(
-          'invalid_response_shape',
-          'Cloudflare Analytics usage response had an unexpected shape.'
+  const queryBatches = batches(queryPlans, MAX_RUN_WINDOWS_PER_REQUEST);
+  let responseIndex = 1;
+  const queryBatch = async (batch: QueryPlan[]): Promise => {
+    const variables: Record = { accountTag: accountId };
+    for (let index = 0; index < batch.length; index += 1) {
+      const plan = batch[index];
+      if (!plan) continue;
+      variables[`datetimeStart${index}`] = plan.window.start;
+      variables[`datetimeEnd${index}`] = plan.window.end;
+      variables[`instanceIds${index}`] = [plan.run.instanceId];
+    }
+    const body = await postGraphql({
+      fetchImpl,
+      token,
+      timeoutMs,
+      query: usageQuery(settings.maxPageSize, batch),
+      variables,
+      retainedBytes,
+    });
+    const batchIndex = responseIndex;
+    responseIndex += 1;
+    rawResponses.push({
+      dataset: DATASET,
+      batchIndex,
+      queries: batch.map((plan, index) => ({
+        alias: `u${index}`,
+        runKey: plan.run.key,
+        windowIndex: plan.windowIndex,
+        window: plan.window,
+      })),
+      body,
+    });
+    const response = UsageResponseSchema.safeParse(body);
+    if (!response.success) {
+      throw new ContainerUsageAnalyticsError(
+        'invalid_response_shape',
+        'Cloudflare Analytics usage response had an unexpected shape.'
+      );
+    }
+    const errorDetails = response.data.errors ?? [];
+    const errors = graphqlErrors(errorDetails);
+    const account = response.data.data?.viewer?.accounts?.[0];
+    const unscopedErrors = errorDetails.filter(
+      error => !error.path?.some(part => typeof part === 'string' && /^u\d+$/.test(part))
+    );
+    if (unscopedErrors.length > 0 && batch.length > 1) {
+      throw new ContainerUsageAnalyticsError(
+        'graphql_error',
+        `Cloudflare Analytics returned an unscoped batch error: ${graphqlErrors(unscopedErrors).join('; ')}`
+      );
+    }
+    if (!account) {
+      throw new ContainerUsageAnalyticsError(
+        'graphql_error',
+        errors.length > 0
+          ? `Cloudflare Analytics usage query failed: ${errors.join('; ')}`
+          : 'Cloudflare Analytics usage query returned no account data.'
+      );
+    }
+    for (let index = 0; index < batch.length; index += 1) {
+      const plan = batch[index];
+      if (!plan) continue;
+      const alias = `u${index}`;
+      const groups = account[alias];
+      const aliasErrors = errorDetails.filter(error => {
+        const errorAlias = error.path?.find(
+          part => typeof part === 'string' && /^u\d+$/.test(part)
         );
-      }
-      const errors = graphqlErrors(response.data.errors);
-      const groups = response.data.data?.viewer?.accounts?.[0]?.containersUsageAdaptiveGroups;
-      if (!groups) {
-        throw new ContainerUsageAnalyticsError(
-          'graphql_error',
-          errors.length > 0
-            ? `Cloudflare Analytics usage query failed: ${errors.join('; ')}`
-            : 'Cloudflare Analytics usage query returned no account data.'
+        return errorAlias === alias || errorAlias === undefined;
+      });
+      const aliasErrorMessages = graphqlErrors(aliasErrors);
+      const aliasPartial = aliasErrors.length > 0;
+      if (groups === null || groups === undefined) {
+        if (!aliasPartial) {
+          throw new ContainerUsageAnalyticsError(
+            'invalid_response_shape',
+            `Cloudflare Analytics usage response omitted ${alias}.`
+          );
+        }
+        partialIds.add(plan.run.key);
+        issues.push(
+          `${DATASET} run ${plan.run.key} window ${plan.windowIndex} returned no usable data: ${aliasErrorMessages.join('; ')}`
         );
+        continue;
       }
-      if (errors.length > 0 || groups.length >= settings.maxPageSize) {
-        for (const id of batch) partialIds.add(id);
+      if (aliasPartial || groups.length >= settings.maxPageSize) {
+        partialIds.add(plan.run.key);
         issues.push(
-          errors.length > 0
-            ? `${DATASET} window ${windowIndex} batch ${batchIndex} returned partial data: ${errors.join('; ')}`
-            : `${DATASET} window ${windowIndex} batch ${batchIndex} reached the page limit.`
+          aliasPartial
+            ? `${DATASET} run ${plan.run.key} window ${plan.windowIndex} returned partial data: ${aliasErrorMessages.join('; ')}`
+            : `${DATASET} run ${plan.run.key} window ${plan.windowIndex} reached the page limit.`
         );
       }
       for (const group of groups) {
-        const key = `${group.dimensions.applicationId}\0${group.dimensions.instanceId}`;
+        const key = `${plan.run.key}\0${group.dimensions.applicationId}\0${group.dimensions.instanceId}`;
         const existing = rows.get(key);
         if (existing) {
           existing.usage.cpuTimeSec += group.sum.cpuTimeSec;
@@ -482,6 +576,7 @@ export async function queryContainerUsageAnalytics(
           existing.usage.txBytes += group.sum.txBytes;
         } else {
           rows.set(key, {
+            runKey: plan.run.key,
             applicationId: group.dimensions.applicationId,
             instanceId: group.dimensions.instanceId,
             usage: { ...group.sum },
@@ -489,15 +584,19 @@ export async function queryContainerUsageAnalytics(
         }
       }
     }
-  }
+  };
+  for (const batch of queryBatches) await queryBatch(batch);
 
   return {
     rows: [...rows.values()].sort(
       (a, b) =>
-        a.applicationId.localeCompare(b.applicationId) || a.instanceId.localeCompare(b.instanceId)
+        a.runKey.localeCompare(b.runKey) ||
+        a.applicationId.localeCompare(b.applicationId) ||
+        a.instanceId.localeCompare(b.instanceId)
     ),
-    partial: partialIds.size > 0,
-    usagePartialInstanceIds: [...partialIds].sort(),
+    partial: partialIds.size > 0 || unavailableRuns.length > 0,
+    usagePartialRunKeys: [...partialIds].sort(),
+    usageUnavailableRuns: unavailableRuns.sort((a, b) => a.runKey.localeCompare(b.runKey)),
     issues,
     settings: settingsSummary,
     rawResponses,
diff --git a/apps/web/src/routers/admin/cloud-billing-skus-router.test.ts b/apps/web/src/routers/admin/cloud-billing-skus-router.test.ts
index 7ea403312f4..ab04168888a 100644
--- a/apps/web/src/routers/admin/cloud-billing-skus-router.test.ts
+++ b/apps/web/src/routers/admin/cloud-billing-skus-router.test.ts
@@ -1,6 +1,9 @@
 import { beforeEach, describe, expect, it, jest } from '@jest/globals';
 import { cleanupDbForTest, db } from '@/lib/drizzle';
-import type { ContainerUsageAnalyticsResult } from '@/lib/cloudflare/container-usage-analytics';
+import type {
+  ContainerUsageAnalyticsInput,
+  ContainerUsageAnalyticsResult,
+} from '@/lib/cloudflare/container-usage-analytics';
 import { createCallerForUser } from '@/routers/test-utils';
 import { insertTestUser } from '@/tests/helpers/user.helper';
 import {
@@ -18,13 +21,7 @@ import {
 } from './cloud-billing-skus-router';
 
 const mockQueryContainerUsageAnalytics =
-  jest.fn<
-    (input: {
-      instanceIds: string[];
-      start: string;
-      end: string;
-    }) => Promise
-  >();
+  jest.fn<(input: ContainerUsageAnalyticsInput) => Promise>();
 
 let admin: User;
 let nonAdmin: User;
@@ -50,6 +47,7 @@ async function insertUsageInterval(params: {
   subjectType?: 'user' | 'org';
   subjectId?: string;
   startedAt?: string;
+  lastSeenAt?: string;
   service?: string;
   instanceId?: string;
   skuId?: string;
@@ -69,7 +67,7 @@ async function insertUsageInterval(params: {
     actor_type: 'user',
     actor_id: subjectType === 'user' ? subjectId : admin.id,
     started_at: params.startedAt ?? '2026-07-22T10:00:00.000Z',
-    last_seen_at: params.startedAt ?? '2026-07-22T10:00:00.000Z',
+    last_seen_at: params.lastSeenAt ?? params.startedAt ?? '2026-07-22T10:00:00.000Z',
     metadata: params.metadata,
   });
 }
@@ -87,12 +85,18 @@ function providerSettings() {
 
 function providerResult(
   rows: ContainerUsageAnalyticsResult['rows'],
-  options: { partial?: boolean; issues?: string[]; usagePartialInstanceIds?: string[] } = {}
+  options: {
+    partial?: boolean;
+    issues?: string[];
+    usagePartialRunKeys?: string[];
+    usageUnavailableRuns?: ContainerUsageAnalyticsResult['usageUnavailableRuns'];
+  } = {}
 ) {
   return {
     rows,
     partial: options.partial ?? false,
-    usagePartialInstanceIds: options.usagePartialInstanceIds ?? [],
+    usagePartialRunKeys: options.usagePartialRunKeys ?? [],
+    usageUnavailableRuns: options.usageUnavailableRuns ?? [],
     issues: options.issues ?? [],
     settings: {
       containersUsageAdaptiveGroups: providerSettings(),
@@ -100,12 +104,8 @@ function providerResult(
     rawResponses: [
       {
         dataset: 'containersUsageAdaptiveGroups' as const,
-        windowIndex: 0,
         batchIndex: 0,
-        window: {
-          start: '2026-07-22T09:00:00.000Z',
-          end: '2026-07-22T11:00:00.000Z',
-        },
+        queries: [],
         body: { data: { viewer: { accounts: [] } }, errors: null },
       },
     ],
@@ -438,7 +438,7 @@ describe('admin.cloudBillingSkus usage records', () => {
     ).rejects.toMatchObject({ code: 'BAD_REQUEST' });
   });
 
-  it('reconciles only exact subject activity, resolves provider identities, and deduplicates generations', async () => {
+  it('reconciles each selected meter generation in its exact run window', async () => {
     await db.insert(cloud_billing_sku).values({
       ...validInput('usage-reconciliation-sku'),
       created_by_user_id: admin.id,
@@ -465,14 +465,25 @@ describe('admin.cloudBillingSkus usage records', () => {
       service: 'cloud-agent-next-sandbox',
       instanceId: 'sandbox-name',
       skuId: 'usage-reconciliation-sku',
+      startedAt: '2026-07-22T10:30:00.000Z',
       metadata: { durable_object_id: 'cloud-physical-id' },
     });
+    await db
+      .update(container_usage_interval)
+      .set({
+        status: 'closed',
+        close_reason: 'exit',
+        stopped_at: '2026-07-22T11:00:00.000Z',
+        last_seen_at: '2026-07-22T11:00:00.000Z',
+      })
+      .where(eq(container_usage_interval.id, 'cloud-generation-2'));
     await insertUsageInterval({
       id: 'gastown-generation',
       subjectType: 'org',
       subjectId: 'reconcile-org',
       service: 'gastown',
       instanceId: 'gastown-physical-id',
+      lastSeenAt: '2026-07-22T11:00:00.000Z',
     });
     await insertUsageInterval({
       id: 'other-subject-generation',
@@ -480,6 +491,12 @@ describe('admin.cloudBillingSkus usage records', () => {
       service: 'gastown',
       instanceId: 'unrelated-physical-id',
     });
+    await insertUsageInterval({
+      id: 'unselected-generation',
+      subjectId: 'reconcile-subject',
+      service: 'gastown',
+      instanceId: 'unselected-physical-id',
+    });
     await db.insert(container_usage_segment).values([
       {
         interval_id: 'cloud-generation-1',
@@ -487,7 +504,7 @@ describe('admin.cloudBillingSkus usage records', () => {
         idempotency_key: 'cloud-generation-1-start',
         reported_seconds: 10,
         usage_seconds: 10,
-        received_at: '2026-07-22T09:00:00.000Z',
+        received_at: '2026-07-22T10:10:00.000Z',
       },
       {
         interval_id: 'cloud-generation-2',
@@ -495,7 +512,7 @@ describe('admin.cloudBillingSkus usage records', () => {
         idempotency_key: 'cloud-generation-2-middle',
         reported_seconds: 20,
         usage_seconds: 20,
-        received_at: '2026-07-22T10:00:00.000Z',
+        received_at: '2026-07-22T10:40:00.000Z',
       },
       {
         interval_id: 'cloud-generation-2',
@@ -503,7 +520,7 @@ describe('admin.cloudBillingSkus usage records', () => {
         idempotency_key: 'cloud-generation-2-end',
         reported_seconds: 200,
         usage_seconds: 200,
-        received_at: '2026-07-22T11:00:00.000Z',
+        received_at: '2026-07-22T10:59:00.000Z',
       },
       {
         interval_id: 'gastown-generation',
@@ -521,20 +538,38 @@ describe('admin.cloudBillingSkus usage records', () => {
         usage_seconds: 999,
         received_at: '2026-07-22T10:00:00.000Z',
       },
+      {
+        interval_id: 'unselected-generation',
+        seq: 1,
+        idempotency_key: 'unselected-middle',
+        reported_seconds: 500,
+        usage_seconds: 500,
+        received_at: '2026-07-22T10:00:00.000Z',
+      },
     ]);
     mockQueryContainerUsageAnalytics.mockImplementation(async input =>
       providerResult(
-        input.instanceIds.map(instanceId => ({
-          applicationId:
-            instanceId === 'cloud-physical-id' ? 'observed-cloud-app' : 'observed-gastown-app',
-          instanceId,
-          usage: {
-            cpuTimeSec: instanceId === 'cloud-physical-id' ? 3 : 4,
-            allocatedMemory: 12 * 1024 ** 3 * 30,
-            allocatedDisk: 20_000_000_000 * 30,
-            txBytes: 3_000,
-          },
-        }))
+        input.runs.map(run => {
+          const seconds = run.key.endsWith('cloud-generation-1')
+            ? 10
+            : run.key.endsWith('cloud-generation-2')
+              ? 220
+              : 30;
+          return {
+            runKey: run.key,
+            applicationId:
+              run.instanceId === 'cloud-physical-id'
+                ? 'observed-cloud-app'
+                : 'observed-gastown-app',
+            instanceId: run.instanceId,
+            usage: {
+              cpuTimeSec: run.instanceId === 'cloud-physical-id' ? 3 : 4,
+              allocatedMemory: 12 * 1024 ** 3 * seconds,
+              allocatedDisk: 20_000_000_000 * seconds,
+              txBytes: 3_000,
+            },
+          };
+        })
       )
     );
 
@@ -544,33 +579,56 @@ describe('admin.cloudBillingSkus usage records', () => {
         subjectId: 'reconcile-subject',
         start: '2026-07-22T09:00:00.000Z',
         end: '2026-07-22T11:00:00.000Z',
+        intervalIds: ['cloud-generation-1', 'cloud-generation-2'],
       },
       mockQueryContainerUsageAnalytics
     );
     expect(mockQueryContainerUsageAnalytics).toHaveBeenLastCalledWith({
-      instanceIds: ['cloud-physical-id'],
-      start: '2026-07-22T09:00:00.000Z',
-      end: '2026-07-22T11:00:00.000Z',
+      runs: [
+        {
+          key: 'cloud-generation-1',
+          instanceId: 'cloud-physical-id',
+          start: '2026-07-22T09:59:55.000Z',
+          end: '2026-07-22T10:30:05.000Z',
+        },
+        {
+          key: 'cloud-generation-2',
+          instanceId: 'cloud-physical-id',
+          start: '2026-07-22T10:29:55.000Z',
+          end: '2026-07-22T11:00:05.000Z',
+        },
+      ],
     });
     expect(userResult.totals).toMatchObject({
-      meterAcceptedSeconds: 30,
+      meterAcceptedSeconds: 230,
       intervalCount: 2,
-      uniqueMeterInstances: 1,
-      queriedCloudflareInstances: 1,
+      meterRuns: 2,
+      queriedCloudflareRuns: 2,
     });
     expect(userResult.rows).toEqual([
       expect.objectContaining({
         providerInstanceId: 'cloud-physical-id',
-        meterAcceptedSeconds: 30,
-        intervalCount: 2,
+        meterAcceptedSeconds: 10,
+        intervalCount: 1,
         services: ['cloud-agent-next-sandbox'],
-        skuIds: ['usage-reconciliation-sku', 'usage-search-sku'],
+        skuIds: ['usage-search-sku'],
         providerCpuTimeSec: 3,
-        providerMemorySeconds: 30,
-        providerDiskSeconds: 30,
+        providerMemorySeconds: 10,
+        providerDiskSeconds: 10,
+        providerMemoryDifferencePercent: 0,
+        providerDiskDifferencePercent: 0,
         provisionedMemoryBytes: 12 * 1024 ** 3,
         provisionedDiskBytes: 20_000_000_000,
-        status: 'comparison_unavailable',
+        status: 'compared',
+      }),
+      expect.objectContaining({
+        providerInstanceId: 'cloud-physical-id',
+        meterAcceptedSeconds: 220,
+        intervalCount: 1,
+        skuIds: ['usage-reconciliation-sku'],
+        providerMemorySeconds: 220,
+        providerDiskSeconds: 220,
+        status: 'compared',
       }),
     ]);
     expect(userResult.provider.rawResponses).toHaveLength(1);
@@ -581,13 +639,19 @@ describe('admin.cloudBillingSkus usage records', () => {
         subjectId: 'reconcile-org',
         start: '2026-07-22T09:00:00.000Z',
         end: '2026-07-22T11:00:00.000Z',
+        intervalIds: ['gastown-generation'],
       },
       mockQueryContainerUsageAnalytics
     );
     expect(mockQueryContainerUsageAnalytics).toHaveBeenLastCalledWith({
-      instanceIds: ['gastown-physical-id'],
-      start: '2026-07-22T09:00:00.000Z',
-      end: '2026-07-22T11:00:00.000Z',
+      runs: [
+        {
+          key: 'gastown-generation',
+          instanceId: 'gastown-physical-id',
+          start: '2026-07-22T09:59:55.000Z',
+          end: '2026-07-22T11:00:05.000Z',
+        },
+      ],
     });
     expect(orgResult.rows[0]).toMatchObject({
       providerInstanceId: 'gastown-physical-id',
@@ -595,7 +659,7 @@ describe('admin.cloudBillingSkus usage records', () => {
       meterAcceptedSeconds: 30,
       providerMemorySeconds: 30,
       providerDiskSeconds: 30,
-      status: 'comparison_unavailable',
+      status: 'compared',
     });
   });
 
@@ -619,6 +683,12 @@ describe('admin.cloudBillingSkus usage records', () => {
         service: 'gastown',
         instanceId: 'partial-id',
       }),
+      insertUsageInterval({
+        id: 'expired-provider',
+        subjectId: 'status-subject',
+        service: 'gastown',
+        instanceId: 'expired-id',
+      }),
       insertUsageInterval({
         id: 'cloud-without-provider-id',
         subjectId: 'status-subject',
@@ -631,6 +701,7 @@ describe('admin.cloudBillingSkus usage records', () => {
         'missing-provider',
         'ambiguous-provider',
         'partial-provider',
+        'expired-provider',
         'cloud-without-provider-id',
       ].map((intervalId, index) => ({
         interval_id: intervalId,
@@ -645,16 +716,19 @@ describe('admin.cloudBillingSkus usage records', () => {
       providerResult(
         [
           {
+            runKey: 'ambiguous-provider',
             applicationId: 'app-gastown',
             instanceId: 'ambiguous-id',
             usage: { cpuTimeSec: 1, allocatedMemory: 2, allocatedDisk: 3, txBytes: 4 },
           },
           {
+            runKey: 'ambiguous-provider',
             applicationId: 'app-other',
             instanceId: 'ambiguous-id',
             usage: { cpuTimeSec: 10, allocatedMemory: 20, allocatedDisk: 30, txBytes: 40 },
           },
           {
+            runKey: 'partial-provider',
             applicationId: 'app-gastown',
             instanceId: 'partial-id',
             usage: { cpuTimeSec: 0, allocatedMemory: 0, allocatedDisk: 0, txBytes: 0 },
@@ -662,8 +736,12 @@ describe('admin.cloudBillingSkus usage records', () => {
         ],
         {
           partial: true,
-          issues: ['Provider usage response was partial.'],
-          usagePartialInstanceIds: ['partial-id'],
+          issues: [
+            'Provider usage response was partial.',
+            'Run expired-provider is outside Cloudflare Analytics retention.',
+          ],
+          usagePartialRunKeys: ['partial-provider'],
+          usageUnavailableRuns: [{ runKey: 'expired-provider', reason: 'outside_retention' }],
         }
       )
     );
@@ -674,20 +752,31 @@ describe('admin.cloudBillingSkus usage records', () => {
         subjectId: 'status-subject',
         start: '2026-07-22T09:00:00.000Z',
         end: '2026-07-22T11:00:00.000Z',
+        intervalIds: [
+          'missing-provider',
+          'ambiguous-provider',
+          'partial-provider',
+          'expired-provider',
+          'cloud-without-provider-id',
+        ],
       },
       mockQueryContainerUsageAnalytics
     );
     expect(mockQueryContainerUsageAnalytics).toHaveBeenCalledWith({
-      instanceIds: expect.arrayContaining(['missing-id', 'ambiguous-id', 'partial-id']),
-      start: '2026-07-22T09:00:00.000Z',
-      end: '2026-07-22T11:00:00.000Z',
+      runs: expect.arrayContaining([
+        expect.objectContaining({ key: 'missing-provider', instanceId: 'missing-id' }),
+        expect.objectContaining({ key: 'ambiguous-provider', instanceId: 'ambiguous-id' }),
+        expect.objectContaining({ key: 'partial-provider', instanceId: 'partial-id' }),
+        expect.objectContaining({ key: 'expired-provider', instanceId: 'expired-id' }),
+      ]),
     });
-    expect(mockQueryContainerUsageAnalytics.mock.calls[0]?.[0].instanceIds).toHaveLength(3);
+    expect(mockQueryContainerUsageAnalytics.mock.calls[0]?.[0].runs).toHaveLength(4);
     expect(result.counts).toEqual({
+      compared: 0,
       missing: 1,
       ambiguous: 1,
       partial: 1,
-      comparisonUnavailable: 1,
+      comparisonUnavailable: 2,
     });
     expect(result.rows.find(row => row.instanceId === 'missing-id')).toMatchObject({
       status: 'missing_from_cloudflare',
@@ -702,6 +791,11 @@ describe('admin.cloudBillingSkus usage records', () => {
       status: 'provider_partial',
       providerCpuTimeSec: null,
     });
+    expect(result.rows.find(row => row.instanceId === 'expired-id')).toMatchObject({
+      status: 'comparison_unavailable',
+      statusDetail: 'This run is outside Cloudflare Analytics retention.',
+      providerCpuTimeSec: null,
+    });
     expect(result.rows.find(row => row.instanceId === 'sandbox-without-metadata')).toMatchObject({
       status: 'comparison_unavailable',
       providerInstanceId: null,
@@ -715,6 +809,7 @@ describe('admin.cloudBillingSkus usage records', () => {
       subjectId: 'no-usage-subject',
       start: '2026-07-22T09:00:00.000Z',
       end: '2026-07-22T11:00:00.000Z',
+      intervalIds: ['not-present'],
     });
     expect(result.rows).toEqual([]);
     expect(result.provider).toEqual({
@@ -732,11 +827,69 @@ describe('admin.cloudBillingSkus usage records', () => {
         subjectId: 'no-usage-subject',
         start: '2026-07-22T09:00:00.000Z',
         end: '2026-07-22T11:00:00.000Z',
+        intervalIds: ['not-present'],
       })
     ).rejects.toMatchObject({ code: 'FORBIDDEN' });
   });
 
-  it('does not normalize provider seconds when memory and disk durations disagree', async () => {
+  it('uses an open run last-seen boundary and retains absolute variance without a meter baseline', async () => {
+    await insertUsageInterval({
+      id: 'open-zero-meter-run',
+      subjectId: 'open-run-subject',
+      service: 'gastown',
+      instanceId: 'open-run-instance',
+      startedAt: '2026-07-22T10:00:00.000Z',
+      lastSeenAt: '2026-07-22T12:00:00.000Z',
+    });
+    mockQueryContainerUsageAnalytics.mockResolvedValue(
+      providerResult([
+        {
+          runKey: 'open-zero-meter-run',
+          applicationId: 'app-gastown',
+          instanceId: 'open-run-instance',
+          usage: {
+            cpuTimeSec: 1,
+            allocatedMemory: 12 * 1024 ** 3 * 10,
+            allocatedDisk: 20_000_000_000 * 10,
+            txBytes: 0,
+          },
+        },
+      ])
+    );
+
+    const result = await reconcileUsageWithCloudflare(
+      {
+        subjectType: 'user',
+        subjectId: 'open-run-subject',
+        start: '2026-07-22T09:00:00.000Z',
+        end: '2026-07-22T11:00:00.000Z',
+        intervalIds: ['open-zero-meter-run'],
+      },
+      mockQueryContainerUsageAnalytics
+    );
+
+    expect(mockQueryContainerUsageAnalytics).toHaveBeenCalledWith({
+      runs: [
+        {
+          key: 'open-zero-meter-run',
+          instanceId: 'open-run-instance',
+          start: '2026-07-22T09:59:55.000Z',
+          end: '2026-07-22T12:00:05.000Z',
+        },
+      ],
+    });
+    expect(result.rows[0]).toMatchObject({
+      meterAcceptedSeconds: 0,
+      meterEndedAt: '2026-07-22T12:00:00.000Z',
+      providerMemoryDifferenceSeconds: 10,
+      providerMemoryDifferencePercent: null,
+      providerDiskDifferenceSeconds: 10,
+      providerDiskDifferencePercent: null,
+      status: 'compared',
+    });
+  });
+
+  it('reports both normalized variances when memory and disk equivalents disagree', async () => {
     await insertUsageInterval({
       id: 'capacity-mismatch',
       subjectId: 'capacity-subject',
@@ -754,6 +907,7 @@ describe('admin.cloudBillingSkus usage records', () => {
     mockQueryContainerUsageAnalytics.mockResolvedValue(
       providerResult([
         {
+          runKey: 'capacity-mismatch',
           applicationId: 'app-gastown',
           instanceId: 'capacity-instance',
           usage: {
@@ -772,6 +926,7 @@ describe('admin.cloudBillingSkus usage records', () => {
         subjectId: 'capacity-subject',
         start: '2026-07-22T09:00:00.000Z',
         end: '2026-07-22T11:00:00.000Z',
+        intervalIds: ['capacity-mismatch'],
       },
       mockQueryContainerUsageAnalytics
     );
@@ -779,13 +934,15 @@ describe('admin.cloudBillingSkus usage records', () => {
     expect(result.rows[0]).toMatchObject({
       providerMemorySeconds: 10,
       providerDiskSeconds: 11,
-      status: 'comparison_unavailable',
-      statusDetail: expect.stringContaining('imply different active durations'),
+      providerMemoryDifferencePercent: 0,
+      providerDiskDifferencePercent: 10,
+      status: 'compared',
+      statusDetail: expect.stringContaining('differ'),
     });
   });
 
-  it('rejects reconciliation above the unique physical instance cap', async () => {
-    const intervalIds = Array.from({ length: 101 }, (_, index) => `capped-instance-${index}`);
+  it('rejects reconciliation above the selected run cap', async () => {
+    const intervalIds = Array.from({ length: 16 }, (_, index) => `capped-instance-${index}`);
     await db.insert(container_usage_interval).values(
       intervalIds.map((id, index) => ({
         id,
@@ -820,12 +977,13 @@ describe('admin.cloudBillingSkus usage records', () => {
           subjectId: 'capped-subject',
           start: '2026-07-22T09:00:00.000Z',
           end: '2026-07-22T11:00:00.000Z',
+          intervalIds,
         },
         mockQueryContainerUsageAnalytics
       )
     ).rejects.toMatchObject({
       code: 'BAD_REQUEST',
-      message: expect.stringContaining('maximum 100'),
+      message: expect.stringContaining('maximum 15'),
     });
     expect(mockQueryContainerUsageAnalytics).not.toHaveBeenCalled();
   });
diff --git a/apps/web/src/routers/admin/cloud-billing-skus-router.ts b/apps/web/src/routers/admin/cloud-billing-skus-router.ts
index 5c603ee4306..69dda541f78 100644
--- a/apps/web/src/routers/admin/cloud-billing-skus-router.ts
+++ b/apps/web/src/routers/admin/cloud-billing-skus-router.ts
@@ -19,7 +19,7 @@ import {
   type ContainerUsageSegment,
 } from '@kilocode/db/schema';
 import { TRPCError } from '@trpc/server';
-import { and, desc, eq, gt, lt, or, sql, type SQL } from 'drizzle-orm';
+import { and, asc, desc, eq, gt, inArray, lt, or, sql, type SQL } from 'drizzle-orm';
 import * as z from 'zod';
 
 export type SerializedCloudBillingSku = Omit & {
@@ -79,6 +79,8 @@ const segmentSearchSchema = z
   })
   .strict();
 
+const MAX_RECONCILIATION_RUNS = 15;
+
 const usageSummarySchema = z
   .object({
     subjectType: z.enum(['user', 'org']),
@@ -91,14 +93,27 @@ const usageSummarySchema = z
     validateUsageWindow(input.start, input.end, context);
   });
 
+const usageReconciliationSchema = z
+  .object({
+    subjectType: z.enum(['user', 'org']),
+    subjectId: z.string().trim().min(1).max(256),
+    start: z.iso.datetime(),
+    end: z.iso.datetime(),
+    intervalIds: z.array(z.string().trim().min(1).max(512)).min(1).max(MAX_RECONCILIATION_RUNS),
+  })
+  .strict()
+  .superRefine((input, context) => {
+    validateUsageWindow(input.start, input.end, context);
+  });
+
 const BILLING_HEALTH_WINDOW_MS = 24 * 60 * 60 * 1_000;
 const STALE_OPEN_INTERVAL_MS = 15 * 60 * 1_000;
-const MAX_RECONCILIATION_INSTANCES = 100;
+const PROVIDER_BOUNDARY_PADDING_MS = 5_000;
 const MEBIBYTE_BYTES = 1024 ** 2;
 const MEGABYTE_BYTES = 1_000_000;
 const CAPACITY_CROSS_CHECK_RELATIVE_TOLERANCE = 1e-6;
 const COMPARISON_METHOD =
-  'Cloudflare allocated resource sums include overlapping container and micro-VM records, so they cannot be normalized to awake wall-clock seconds. Capacity-equivalent memory and disk seconds are diagnostic only.';
+  'Cloudflare memory and disk byte-seconds are queried with five seconds of boundary tolerance, normalized by configured instance capacity, and compared with accepted meter seconds for each exact meter run. CPU time is included as a secondary usage diagnostic.';
 const usageMetadataSchema = z
   .record(z.string().min(1).max(64), z.string().max(512))
   .refine(
@@ -204,6 +219,7 @@ function postgresErrorCode(error: unknown): string | undefined {
 }
 
 export type ReconciliationStatus =
+  | 'compared'
   | 'missing_from_cloudflare'
   | 'ambiguous_application'
   | 'provider_partial'
@@ -217,6 +233,8 @@ type MeterReconciliationRow = {
   skuIds: Set;
   intervalIds: Set;
   acceptedSeconds: number;
+  startedAt: string;
+  endedAt: string;
   identityIssue: string | null;
 };
 
@@ -298,12 +316,12 @@ function addMeterReconciliationRow(
     skuId: string;
     metadata: unknown;
     acceptedSeconds: number;
+    startedAt: string;
+    endedAt: string;
   }
 ): void {
   const providerIdentity = providerIdentityForMeterRow(meter);
-  const key = providerIdentity.instanceId
-    ? `provider\0${providerIdentity.instanceId}`
-    : `meter\0${meter.service}\0${meter.instanceId}`;
+  const key = meter.intervalId;
   let row = rows.get(key);
   if (!row) {
     row = {
@@ -314,6 +332,8 @@ function addMeterReconciliationRow(
       skuIds: new Set(),
       intervalIds: new Set(),
       acceptedSeconds: 0,
+      startedAt: meter.startedAt,
+      endedAt: meter.endedAt,
       identityIssue: providerIdentity.issue,
     };
     rows.set(key, row);
@@ -343,17 +363,22 @@ function normalizedReconciliationRows(
   meterRows: MeterReconciliationRow[],
   provider: ContainerUsageAnalyticsResult | null
 ) {
-  const providerByInstance = new Map();
-  const partialUsageInstanceIds = new Set(provider?.usagePartialInstanceIds ?? []);
+  const providerByRun = new Map();
+  const partialUsageRunKeys = new Set(provider?.usagePartialRunKeys ?? []);
+  const unavailableRuns = new Map(
+    provider?.usageUnavailableRuns.map(run => [run.runKey, run.reason] as const) ?? []
+  );
   for (const row of provider?.rows ?? []) {
-    const existing = providerByInstance.get(row.instanceId);
+    const existing = providerByRun.get(row.runKey);
     if (existing) existing.push(row);
-    else providerByInstance.set(row.instanceId, [row]);
+    else providerByRun.set(row.runKey, [row]);
   }
 
   return meterRows.map(meter => {
     const candidates = meter.providerInstanceId
-      ? (providerByInstance.get(meter.providerInstanceId) ?? [])
+      ? (providerByRun.get(meter.key) ?? []).filter(
+          candidate => candidate.instanceId === meter.providerInstanceId
+        )
       : [];
     const providerApplicationIds = candidates.map(candidate => candidate.applicationId).sort();
     let status: ReconciliationStatus;
@@ -361,14 +386,20 @@ function normalizedReconciliationRows(
     let matchedProvider: ContainerUsageAnalyticsResult['rows'][number] | null = null;
     let providerMemorySeconds: number | null = null;
     let providerDiskSeconds: number | null = null;
+    let providerMemoryDifferenceSeconds: number | null = null;
+    let providerMemoryDifferencePercent: number | null = null;
+    let providerDiskDifferenceSeconds: number | null = null;
+    let providerDiskDifferencePercent: number | null = null;
     let provisionedMemoryBytes: number | null = null;
     let provisionedDiskBytes: number | null = null;
     if (meter.identityIssue) {
       status = 'comparison_unavailable';
       statusDetail = meter.identityIssue;
+    } else if (unavailableRuns.get(meter.key) === 'outside_retention') {
+      status = 'comparison_unavailable';
+      statusDetail = 'This run is outside Cloudflare Analytics retention.';
     } else if (candidates.length === 0) {
-      const usagePartial =
-        meter.providerInstanceId !== null && partialUsageInstanceIds.has(meter.providerInstanceId);
+      const usagePartial = partialUsageRunKeys.has(meter.key);
       status = usagePartial ? 'provider_partial' : 'missing_from_cloudflare';
       statusDetail = usagePartial
         ? 'Cloudflare returned partial data, so this instance cannot be classified as missing.'
@@ -376,10 +407,7 @@ function normalizedReconciliationRows(
     } else if (candidates.length !== 1) {
       status = 'ambiguous_application';
       statusDetail = 'Multiple Cloudflare applications returned this physical instance ID.';
-    } else if (
-      meter.providerInstanceId !== null &&
-      partialUsageInstanceIds.has(meter.providerInstanceId)
-    ) {
+    } else if (partialUsageRunKeys.has(meter.key)) {
       status = 'provider_partial';
       statusDetail = 'Cloudflare returned only part of the required provider data.';
     } else {
@@ -394,19 +422,26 @@ function normalizedReconciliationRows(
         providerMemorySeconds =
           matchedProvider.usage.allocatedMemory / provisionedCapacity.memoryBytes;
         providerDiskSeconds = matchedProvider.usage.allocatedDisk / provisionedCapacity.diskBytes;
+        providerMemoryDifferenceSeconds = providerMemorySeconds - meter.acceptedSeconds;
+        providerDiskDifferenceSeconds = providerDiskSeconds - meter.acceptedSeconds;
+        if (meter.acceptedSeconds > 0) {
+          providerMemoryDifferencePercent =
+            (providerMemoryDifferenceSeconds / meter.acceptedSeconds) * 100;
+          providerDiskDifferencePercent =
+            (providerDiskDifferenceSeconds / meter.acceptedSeconds) * 100;
+        }
         const capacityCrossCheckDifference = Math.abs(providerMemorySeconds - providerDiskSeconds);
         const capacityCrossCheckScale = Math.max(1, providerMemorySeconds, providerDiskSeconds);
         if (
           capacityCrossCheckDifference / capacityCrossCheckScale >
           CAPACITY_CROSS_CHECK_RELATIVE_TOLERANCE
         ) {
-          status = 'comparison_unavailable';
+          status = 'compared';
           statusDetail =
-            'Provider memory and disk byte-seconds imply different active durations for this service capacity.';
+            'Provider memory and disk allocation equivalents differ; review both variances.';
         } else {
-          status = 'comparison_unavailable';
-          statusDetail =
-            'Cloudflare memory and disk allocation equivalents agree, but overlapping billing records prevent an awake-time comparison.';
+          status = 'compared';
+          statusDetail = 'Provider memory and disk allocation equivalents agree.';
         }
       }
     }
@@ -418,10 +453,17 @@ function normalizedReconciliationRows(
       services: [...meter.services].sort(),
       providerApplicationIds,
       skuIds: [...meter.skuIds].sort(),
+      intervalIds: [...meter.intervalIds].sort(),
       intervalCount: meter.intervalIds.size,
       meterAcceptedSeconds: meter.acceptedSeconds,
+      meterStartedAt: meter.startedAt,
+      meterEndedAt: meter.endedAt,
       providerMemorySeconds,
       providerDiskSeconds,
+      providerMemoryDifferenceSeconds,
+      providerMemoryDifferencePercent,
+      providerDiskDifferenceSeconds,
+      providerDiskDifferencePercent,
       provisionedMemoryBytes,
       provisionedDiskBytes,
       providerCpuTimeSec: matchedProvider?.usage.cpuTimeSec ?? null,
@@ -434,11 +476,11 @@ function normalizedReconciliationRows(
   });
 }
 
-type UsageSummaryInput = z.infer;
+type UsageReconciliationInput = z.infer;
 type QueryContainerUsageAnalytics = typeof queryContainerUsageAnalytics;
 
 export async function reconcileUsageWithCloudflare(
-  input: UsageSummaryInput,
+  input: UsageReconciliationInput,
   queryProvider: QueryContainerUsageAnalytics = queryContainerUsageAnalytics
 ) {
   const meterSegments = await db
@@ -448,20 +490,24 @@ export async function reconcileUsageWithCloudflare(
       instanceId: container_usage_interval.instance_id,
       skuId: container_usage_interval.cloud_billing_sku_id,
       metadata: container_usage_interval.metadata,
+      startedAt: container_usage_interval.started_at,
+      lastSeenAt: container_usage_interval.last_seen_at,
+      stoppedAt: container_usage_interval.stopped_at,
       acceptedSeconds:
         sql`coalesce(sum(${container_usage_segment.usage_seconds}), 0)`.mapWith(Number),
     })
-    .from(container_usage_segment)
-    .innerJoin(
-      container_usage_interval,
-      eq(container_usage_segment.interval_id, container_usage_interval.id)
+    .from(container_usage_interval)
+    .leftJoin(
+      container_usage_segment,
+      eq(container_usage_interval.id, container_usage_segment.interval_id)
     )
     .where(
       and(
         eq(container_usage_interval.subject_type, input.subjectType),
         eq(container_usage_interval.subject_id, input.subjectId),
-        sql`${container_usage_segment.received_at} >= ${input.start}`,
-        lt(container_usage_segment.received_at, input.end)
+        inArray(container_usage_interval.id, input.intervalIds),
+        lt(container_usage_interval.started_at, input.end),
+        gt(container_usage_interval.last_seen_at, input.start)
       )
     )
     .groupBy(
@@ -469,30 +515,45 @@ export async function reconcileUsageWithCloudflare(
       container_usage_interval.service,
       container_usage_interval.instance_id,
       container_usage_interval.cloud_billing_sku_id,
-      container_usage_interval.metadata
-    );
+      container_usage_interval.metadata,
+      container_usage_interval.started_at,
+      container_usage_interval.last_seen_at,
+      container_usage_interval.stopped_at
+    )
+    .orderBy(asc(container_usage_interval.started_at), asc(container_usage_interval.id));
 
   const grouped = new Map();
-  for (const meterSegment of meterSegments) addMeterReconciliationRow(grouped, meterSegment);
+  for (const meterSegment of meterSegments) {
+    addMeterReconciliationRow(grouped, {
+      ...meterSegment,
+      startedAt: new Date(meterSegment.startedAt).toISOString(),
+      endedAt: new Date(meterSegment.stoppedAt ?? meterSegment.lastSeenAt).toISOString(),
+    });
+  }
   const meterRows = [...grouped.values()];
-  const providerInstanceIds = [
-    ...new Set(meterRows.flatMap(row => (row.providerInstanceId ? [row.providerInstanceId] : []))),
-  ];
-  if (providerInstanceIds.length > MAX_RECONCILIATION_INSTANCES) {
+  const providerRuns = meterRows.flatMap(row =>
+    row.providerInstanceId
+      ? [
+          {
+            key: row.key,
+            instanceId: row.providerInstanceId,
+            start: new Date(Date.parse(row.startedAt) - PROVIDER_BOUNDARY_PADDING_MS).toISOString(),
+            end: new Date(Date.parse(row.endedAt) + PROVIDER_BOUNDARY_PADDING_MS).toISOString(),
+          },
+        ]
+      : []
+  );
+  if (providerRuns.length > MAX_RECONCILIATION_RUNS) {
     throw new TRPCError({
       code: 'BAD_REQUEST',
-      message: `This window contains ${providerInstanceIds.length} unique Cloudflare instances (maximum ${MAX_RECONCILIATION_INSTANCES}). Narrow the window and retry.`,
+      message: `The selected records contain ${providerRuns.length} Cloudflare runs (maximum ${MAX_RECONCILIATION_RUNS}).`,
     });
   }
 
   let provider: ContainerUsageAnalyticsResult | null = null;
-  if (providerInstanceIds.length > 0) {
+  if (providerRuns.length > 0) {
     try {
-      provider = await queryProvider({
-        instanceIds: providerInstanceIds,
-        start: input.start,
-        end: input.end,
-      });
+      provider = await queryProvider({ runs: providerRuns });
     } catch (error) {
       if (error instanceof ContainerUsageAnalyticsError) {
         throw new TRPCError({
@@ -516,17 +577,18 @@ export async function reconcileUsageWithCloudflare(
     end: input.end,
     generatedAt: new Date().toISOString(),
     comparison: {
-      available: false as const,
-      method: 'unavailable' as const,
+      available: true as const,
+      method: 'capacity_equivalent' as const,
       description: COMPARISON_METHOD,
     },
     totals: {
       meterAcceptedSeconds: totalMeterSeconds,
       intervalCount: new Set(meterSegments.map(row => row.intervalId)).size,
-      uniqueMeterInstances: rows.length,
-      queriedCloudflareInstances: providerInstanceIds.length,
+      meterRuns: rows.length,
+      queriedCloudflareRuns: providerRuns.length,
     },
     counts: {
+      compared: countStatus('compared'),
       missing: countStatus('missing_from_cloudflare'),
       ambiguous: countStatus('ambiguous_application'),
       partial: countStatus('provider_partial'),
@@ -732,7 +794,7 @@ export const cloudBillingSkusRouter = createTRPCRouter({
   }),
 
   reconcileUsageWithCloudflare: adminProcedure
-    .input(usageSummarySchema)
+    .input(usageReconciliationSchema)
     .mutation(async ({ input }) => reconcileUsageWithCloudflare(input)),
 
   usageHealth: adminProcedure.query(async () => {