From 0dfc289e67762e14f4a3f27326e7a53e1e6cd971 Mon Sep 17 00:00:00 2001 From: Adrian Webb Date: Sat, 19 Sep 2026 20:22:53 -0400 Subject: [PATCH 1/2] Use settled capacity usage in terminal assignment performance --- .../lifecycle/assignment-lifecycle-service.ts | 7 ++++++- .../assignment-terminal-performance.ts | 9 ++++---- .../assignments/terminal-performance.test.ts | 21 +++++++++++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 tests/unit/control-plane/capacity/assignments/terminal-performance.test.ts diff --git a/src/api/capacity/services/capacity/assignments/lifecycle/assignment-lifecycle-service.ts b/src/api/capacity/services/capacity/assignments/lifecycle/assignment-lifecycle-service.ts index 4559e696..ce9ff0d0 100644 --- a/src/api/capacity/services/capacity/assignments/lifecycle/assignment-lifecycle-service.ts +++ b/src/api/capacity/services/capacity/assignments/lifecycle/assignment-lifecycle-service.ts @@ -429,7 +429,12 @@ export class ProviderAssignmentLifecycleService { ? { ...record(assignment.metadata), operationalState: options.status } : null); const metadataWrite = transitionMetadata ? ', metadata_json = ?' : ''; - const performance = options.status === 'returned' ? input.performance ?? null : terminalPerformance(assignment, input, options.status==='completed'?'completed':'failed', now); + const settledUsage = assignment.reservationId && options.status !== 'returned' + ? await this.store.first(`SELECT active_seconds, elapsed_seconds, input_tokens, cached_input_tokens, reasoning_tokens, output_tokens, actual_usd + FROM capacity_usage_actuals WHERE id = ? AND assignment_id = ? AND accounting_mode = 'aggregate' LIMIT 1`, + [`usage:${assignment.id}:${assignment.attemptCount}:aggregate`, assignment.id]) + : null; + const performance = options.status === 'returned' ? input.performance ?? null : terminalPerformance(assignment, input, options.status==='completed'?'completed':'failed', now, record(settledUsage)); const lifecycleOutput = composeAssignmentLifecycleOutput(record(input), performance); const params: unknown[] = [ input.runnerId ?? null, diff --git a/src/api/capacity/services/capacity/assignments/lifecycle/completion/assignment-terminal-performance.ts b/src/api/capacity/services/capacity/assignments/lifecycle/completion/assignment-terminal-performance.ts index fffc5ec8..26e176dc 100644 --- a/src/api/capacity/services/capacity/assignments/lifecycle/completion/assignment-terminal-performance.ts +++ b/src/api/capacity/services/capacity/assignments/lifecycle/completion/assignment-terminal-performance.ts @@ -29,6 +29,7 @@ export function terminalPerformance( input: ExtendedProviderAssignmentLifecycleRequest, status: 'completed' | 'failed', now: string, + settledUsage: JsonRecord = {}, ) { if (input.performance) return input.performance; const metadata = record(assignment.metadata); @@ -59,10 +60,10 @@ export function terminalPerformance( disposition, reason: String(input.reason ?? input.message ?? (status === 'completed' ? 'Assignment completed.' : 'Assignment failed.')), acceptanceChecks: Array.isArray(completion.acceptanceChecks) ? completion.acceptanceChecks : [], completedScope: [], remainingScope: [], artifactRefs: Array.isArray(completion.durableArtifactRefs) ? completion.durableArtifactRefs.map(String) : [], budget, - actual: { activeSeconds: Math.max(0, Number(input.activeSeconds ?? 0)), elapsedSeconds: Math.max(0, Number(input.elapsedSeconds ?? 0)), - inputTokens: Math.max(0, Number(usage.inputTokens ?? 0)), cachedInputTokens: Math.max(0, Number(usage.cachedInputTokens ?? 0)), - reasoningTokens: Math.max(0, Number(usage.reasoningTokens ?? 0)), outputTokens: Math.max(0, Number(usage.outputTokens ?? 0)), costAmount: input.actualUsd == null ? null : Number(input.actualUsd), - costCurrency: input.actualUsd == null ? null : 'USD', native: [], attempts: Number(assignment.attemptCount ?? 0) + 1 }, + actual: { activeSeconds: Math.max(0, Number(settledUsage.active_seconds ?? input.activeSeconds ?? 0)), elapsedSeconds: Math.max(0, Number(settledUsage.elapsed_seconds ?? input.elapsedSeconds ?? 0)), + inputTokens: Math.max(0, Number(settledUsage.input_tokens ?? usage.inputTokens ?? 0)), cachedInputTokens: Math.max(0, Number(settledUsage.cached_input_tokens ?? usage.cachedInputTokens ?? 0)), + reasoningTokens: Math.max(0, Number(settledUsage.reasoning_tokens ?? usage.reasoningTokens ?? 0)), outputTokens: Math.max(0, Number(settledUsage.output_tokens ?? usage.outputTokens ?? 0)), costAmount: settledUsage.actual_usd == null && input.actualUsd == null ? null : Number(settledUsage.actual_usd ?? input.actualUsd), + costCurrency: settledUsage.actual_usd == null && input.actualUsd == null ? null : 'USD', native: [], attempts: Number(assignment.attemptCount ?? 0) + 1 }, noUsefulScopedWorkRemaining: completion.noUsefulScopedWorkRemaining === true, agentAssessment: null, systemAssessment: { generatedBy: 'api-recovery', measuredAt: now, enforcementConfidence: record(budget).enforcementConfidence }, downstreamOutcomes: [], }; diff --git a/tests/unit/control-plane/capacity/assignments/terminal-performance.test.ts b/tests/unit/control-plane/capacity/assignments/terminal-performance.test.ts new file mode 100644 index 00000000..57494a06 --- /dev/null +++ b/tests/unit/control-plane/capacity/assignments/terminal-performance.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, it } from 'vitest'; +import type { DurableProviderAssignment } from '../../../../../src/api/capacity/repositories/capacity/assignments/assignment.ts'; +import { terminalPerformance } from '../../../../../src/api/capacity/services/capacity/assignments/lifecycle/completion/assignment-terminal-performance.ts'; + +describe('terminal assignment performance', () => { + it('uses the committed aggregate usage rather than an empty completion payload', () => { + const assignment = { + id: 'assignment-1', workDayId: 'workday-1', teamId: 'team-1', projectId: 'project-1', + projectAgentClassId: 'project-1:architect', agentId: 'sdk/architect', mode: 'planning', + handlerId: 'writer', capacityProviderId: 'provider-1', executionProviderId: 'codex-implementation', + attemptCount: 0, metadata: {}, capacityEnvelope: {}, + } as unknown as DurableProviderAssignment; + const performance = terminalPerformance(assignment, { completion: { disposition: 'completed' } }, + 'completed', '2026-09-20T00:00:00.000Z', { + active_seconds: 50, elapsed_seconds: 54, input_tokens: 455633, + cached_input_tokens: 396544, reasoning_tokens: 292, output_tokens: 1785, + }); + expect(performance.actual).toMatchObject({ activeSeconds: 50, elapsedSeconds: 54, + inputTokens: 455633, cachedInputTokens: 396544, reasoningTokens: 292, outputTokens: 1785 }); + }); +}); From 8b61fb45c0f271f36da5c4894bedeb9ad7333c64 Mon Sep 17 00:00:00 2001 From: Adrian Webb Date: Sat, 19 Sep 2026 20:25:25 -0400 Subject: [PATCH 2/2] Keep terminal transition within repository file limit --- .../assignments/lifecycle/assignment-lifecycle-service.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/api/capacity/services/capacity/assignments/lifecycle/assignment-lifecycle-service.ts b/src/api/capacity/services/capacity/assignments/lifecycle/assignment-lifecycle-service.ts index ce9ff0d0..3ad51863 100644 --- a/src/api/capacity/services/capacity/assignments/lifecycle/assignment-lifecycle-service.ts +++ b/src/api/capacity/services/capacity/assignments/lifecycle/assignment-lifecycle-service.ts @@ -430,10 +430,7 @@ export class ProviderAssignmentLifecycleService { : null); const metadataWrite = transitionMetadata ? ', metadata_json = ?' : ''; const settledUsage = assignment.reservationId && options.status !== 'returned' - ? await this.store.first(`SELECT active_seconds, elapsed_seconds, input_tokens, cached_input_tokens, reasoning_tokens, output_tokens, actual_usd - FROM capacity_usage_actuals WHERE id = ? AND assignment_id = ? AND accounting_mode = 'aggregate' LIMIT 1`, - [`usage:${assignment.id}:${assignment.attemptCount}:aggregate`, assignment.id]) - : null; + ? await this.store.first(`SELECT active_seconds, elapsed_seconds, input_tokens, cached_input_tokens, reasoning_tokens, output_tokens, actual_usd FROM capacity_usage_actuals WHERE id = ? AND assignment_id = ? AND accounting_mode = 'aggregate' LIMIT 1`, [`usage:${assignment.id}:${assignment.attemptCount}:aggregate`, assignment.id]) : null; const performance = options.status === 'returned' ? input.performance ?? null : terminalPerformance(assignment, input, options.status==='completed'?'completed':'failed', now, record(settledUsage)); const lifecycleOutput = composeAssignmentLifecycleOutput(record(input), performance); const params: unknown[] = [