feat(usage): Settings → Usage page + DB-rate/write-stamp contract (#291)#300
feat(usage): Settings → Usage page + DB-rate/write-stamp contract (#291)#300axewilledge wants to merge 15 commits into
Conversation
…#291) - /usage/projects (list-project-usage): one card per project with any recorded usage, deleted projects included; lifetime token totals with write-time-stamped costUsd (null when unstamped) - remove /projects/{p}/usage + ProjectUsage (per-phase shape, #245) - Usage schema: costUsd is now a capture-time stamp, never repriced - aep-api: projectusage slice placeholder swapped to empty-list list-project-usage; ledger + README rows follow Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Builds page loses the build UsageChip + per-task cost captions; Spec view loses the draft-cycle chip. features/usage api swaps to the org-wide /usage/projects read; mocks/fixtures follow (org cards incl. deleted + unstamped projects, per-phase rollup gone). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Project cards with a folded USD cost chip (click to expand the token breakdown), greyed cards for deleted projects, empty/error states. Wired into SettingsLayout nav as a third tab. Backed by useProjectUsageList / GET /usage/projects; typed MSW mocks cover live, deleted, and pre-stamping (null-cost) projects. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…#291) ADR-0011 reversed: USD is stamped at capture time from DB-backed model rates (immutable history) instead of derived at read from env-config rates; original read-time rationale kept as re-proposable History. PRD In-flight #245 line replaced by the #291 Settings → Usage line. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
launch.json holds a local dev launch config with hardcoded absolute paths and never belonged in version control. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eakdown (#291) - contract: ProjectUsageCard gains phases (PhaseUsage: spec/build/validation) - UsageChip no longer hides zero usage — an idle project shows $0; a null unpriced cost still degrades to tokens - UsageBreakdown adds a small 'Cost by phase' section (spec/design, build, validation) under the token totals - mock fixture: idle project + ~20/70/10 phase split; tests cover both Amends #291 grilling decision #3: per-phase returns as secondary detail only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…#299) Backend for Usage & cost v2 (#291), built on the contract in #300. Resurrects the token-capture pipeline (from the closed #269) and stamps USD at write time. - model_rates table (platform/modelcost.ModelRate) + idempotent seed of claude-sonnet-5 at today's intro rates; boot-loaded immutable Stamper - cost_usd stamped on agent_turns + executions at capture; never re-derived - GET /usage/projects (projects.UsageService): every live project carded (idle → $0), since-deleted projects with spend greyed, ordered stamped-cost desc; SUM(cost_usd) NULL = no-backfill semantic; zero-token rows filtered - per-phase split: delivery SumUsageByProjectPhase (validation kind vs build); card carries spec/build/validation - agents + agent-stream emit per-turn TurnUsage on the terminal manifest Tests: stamp math, fold/order/deleted/idle labelling, phase split, migrate step-order. Gates: build, vet, edge/arch, deadcode, license, 149 agents. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e-page-291 # Conflicts: # apps/console/src/features/builds/components/BuildsPage.tsx # apps/console/src/features/settings/components/SettingsLayout.tsx # apps/console/src/features/spec/components/SpecView.tsx # apps/console/src/features/tasks/components/TasksList.tsx # services/aep-api/internal/gen/server_gen.go
…ep-api/usage-capture-291 # Conflicts: # services/aep-api/internal/app/app.go # services/aep-api/internal/gen/server_gen.go # services/aep-api/internal/migrate/run_all.go # services/aep-api/internal/projects/httpapi/aggregate.go # services/aep-api/internal/projects/module.go
…e-page-291 # Conflicts: # apps/console/src/features/settings/components/SettingsLayout.tsx # apps/console/src/features/spec/components/SpecView.test.tsx # apps/console/src/features/spec/components/SpecView.tsx # services/aep-api/internal/gen/server_gen.go # services/aep-api/internal/spec/repository_turn.go # services/aep-api/internal/spec/turn_runner.go
No content change — nudges GitHub to re-sync the PR head + recompute mergeability after the aep-rewrite merge (branch was verified clean: git compare shows 11 ahead, 0 behind aep-rewrite). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR implements Usage & cost v2 across the contract, agents runtime, console UI, and aep-api to support a new Settings → Usage experience and a new org-wide usage endpoint. It shifts cost semantics to write-time USD stamping backed by DB model rates, and removes the previous scattered v1 cost surfaces.
Changes:
- Introduces
GET /usage/projects+ newProjectUsageList/ProjectUsageCard/PhaseUsagecontract shapes; removesGET /projects/{projectName}/usage. - Captures/threads per-turn usage + model id in the agents terminal manifest and persists/stamps usage + cost in aep-api (turns + executions) with
model_ratesseeding + an in-memory stamper. - Adds the console Settings → Usage page (cards, deleted projects, null-cost/token-only degradation, per-phase breakdown) and removes v1 cost chips/captions from Builds/Spec/Tasks views.
Reviewed changes
Copilot reviewed 68 out of 68 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| services/agents/test/run-conversation-turn.test.ts | Adds tests asserting manifest usage totals and model id threading. |
| services/agents/src/shared/model.ts | Adds resolveModelId and reuses it in createModel for consistent model attribution. |
| services/agents/src/server.ts | Threads optional modelId from app deps into turns for usage attribution. |
| services/agents/src/main.ts | Provides modelId to createApp using resolveModelId(). |
| services/agents/src/conversation/run-conversation-turn.ts | Projects whole-turn usage onto manifest and emits it with the terminal manifest. |
| services/agents/src/conversation/manifest.ts | Adds toTurnUsage and extends manifest part to optionally include usage. |
| services/aep-api/internal/spec/turn_runner.go | Folds manifest usage onto turn terminals (including parity-rejected terminals). |
| services/aep-api/internal/spec/repository_turn.go | Adds usage persistence/stamping on turns and adds per-project usage rollup. |
| services/aep-api/internal/spec/repository_turn_dbtest_test.go | Updates repo construction for new stamper dependency. |
| services/aep-api/internal/spec/genai_component_test.go | Updates in-memory repo stub with new usage rollup method. |
| services/aep-api/internal/spec/agent_turn.go | Adds persisted token/model/cost columns to agent_turns. |
| services/aep-api/internal/projects/usage_service.go | Implements org-wide per-project usage card assembly + sorting + deleted handling. |
| services/aep-api/internal/projects/usage_service_test.go | Adds tests for folding, ordering, deleted labeling, idle projects, and empty org behavior. |
| services/aep-api/internal/projects/README.md | Updates method-origin ledger/docs for new list-project-usage slice behavior. |
| services/aep-api/internal/projects/projectusage/handler.go | Replaces placeholder handler with UsageService delegation for /usage/projects. |
| services/aep-api/internal/projects/projectusage/doc.go | Updates slice documentation for org-wide usage endpoint. |
| services/aep-api/internal/projects/project_service_test.go | Extends fake delivery exec repo surface to include usage methods. |
| services/aep-api/internal/projects/project_dbtest_test.go | Updates execution repository constructor signature. |
| services/aep-api/internal/projects/module.go | Adds UsageSvc to projects module deps. |
| services/aep-api/internal/projects/httpapi/aggregate.go | Wires projectusage handler with UsageSvc. |
| services/aep-api/internal/platform/modelcost/modelcost.go | Introduces DB-backed model rate entity + immutable in-memory stamper. |
| services/aep-api/internal/platform/modelcost/modelcost_test.go | Tests stamping math, rounding, and nil/zero behavior. |
| services/aep-api/internal/platform/agentfold/sse.go | Extends stream part with manifest usage payload type. |
| services/aep-api/internal/platform/agentfold/manifest.go | Carries usage through manifest extraction. |
| services/aep-api/internal/organization/org_disconnect_dbtest_test.go | Updates execution repository constructor signature. |
| services/aep-api/internal/migrate/step_order_test.go | Adds model_rates_seed to pinned migration step order. |
| services/aep-api/internal/migrate/run_all.go | Adds model_rates table to base models and seeds it via a new migration step. |
| services/aep-api/internal/migrate/model_rates.go | Adds seed + load helpers for model rates (gorm-based). |
| services/aep-api/internal/gen/server_gen.go | Regenerates server interfaces/routes to remove old usage op and add /usage/projects. |
| services/aep-api/internal/gen/models_gen.go | Regenerates models for ProjectUsageList/ProjectUsageCard/PhaseUsage; updates Usage.costUsd docs. |
| services/aep-api/internal/edge/method_origin_test.go | Updates op owner map to replace GetProjectUsage with ListProjectUsage. |
| services/aep-api/internal/delivery/repository_execution.go | Adds execution usage persistence + stamping + per-project phase rollup; updates constructor for stamper. |
| services/aep-api/internal/delivery/repository_execution_dbtest_test.go | Updates repo construction for new stamper dependency. |
| services/aep-api/internal/delivery/execution/funnel.go | Threads SpecTag into execution rows for lineage/rollups. |
| services/aep-api/internal/delivery/execution/funnel_dbtest_test.go | Updates execution repository constructor signature. |
| services/aep-api/internal/delivery/execution/events.go | Threads SpecTag into execution rows created by events path. |
| services/aep-api/internal/delivery/execution.go | Adds SpecTag plus persisted token/model/cost columns and Usage() accessor. |
| services/aep-api/internal/delivery/codingagent/watcher.go | Records captured token usage from final logs onto execution rows. |
| services/aep-api/internal/delivery/codingagent/usage_capture.go | Adds log parsing helper to extract the terminal result.usage. |
| services/aep-api/internal/delivery/codingagent/usage_capture_test.go | Tests usage extraction from logs and last-result-wins behavior. |
| services/aep-api/internal/delivery/codingagent/fakes_test.go | Extends fake exec repo surface to include usage methods. |
| services/aep-api/internal/contracts/usage.go | Adds shared token usage + stamped aggregate types for cross-domain rollups. |
| services/aep-api/internal/contracts/progress.go | Adds usage field to progress events for runner result reporting. |
| services/aep-api/internal/app/infra.go | Loads model rates after migration and builds RateStamper for injection. |
| services/aep-api/internal/app/app.go | Injects RateStamper into repositories and wires UsageService into projects handlers. |
| packages/contracts/api/v1/openapi.yaml | Updates contract: new /usage/projects, new schemas, updated Usage.costUsd semantics. |
| packages/agent-stream/src/stream-types.ts | Extends stream part typing to include manifest usage. |
| packages/agent-stream/src/index.ts | Re-exports TurnUsage. |
| packages/agent-stream/src/contracts/sse-events.ts | Defines TurnUsage and adds optional usage on terminal manifest. |
| apps/console/src/routes/settings.usage.tsx | Adds Settings → Usage route. |
| apps/console/src/mocks/handlers/usage.ts | Adds MSW handler for /usage/projects with scenario selection. |
| apps/console/src/mocks/handlers/project.ts | Removes v1 per-project usage mock handler. |
| apps/console/src/mocks/fixtures/usage.ts | Reworks fixtures for org-wide usage cards, deleted/null-cost/idle scenarios. |
| apps/console/src/mocks/browser.ts | Registers usage handlers in the MSW worker. |
| apps/console/src/features/usage/lib/format.ts | Exposes PhaseUsage typing for UI rendering. |
| apps/console/src/features/usage/components/UsageSection.tsx | Implements Settings → Usage page UI (loading/error/empty/cards/deleted). |
| apps/console/src/features/usage/components/UsageSection.test.tsx | Adds comprehensive component tests for all primary UI states. |
| apps/console/src/features/usage/components/UsageChip.tsx | Updates chip behavior for the usage page and passes per-phase split to breakdown. |
| apps/console/src/features/usage/components/UsageBreakdown.tsx | Adds per-phase cost split section and updated null-cost copy. |
| apps/console/src/features/usage/api/queries.ts | Switches data hook from per-project usage to org-wide list query. |
| apps/console/src/features/usage/api/keys.ts | Updates query key to org-wide usage list. |
| apps/console/src/features/tasks/components/TasksList.tsx | Removes per-task cost caption + tooltip breakdown. |
| apps/console/src/features/spec/components/SpecView.tsx | Removes draft-cycle usage chip integration. |
| apps/console/src/features/spec/components/SpecView.test.tsx | Removes now-unused usage hook mock. |
| apps/console/src/features/settings/components/SettingsLayout.tsx | Adds “Usage” tab and updates subtitle copy. |
| apps/console/src/features/builds/components/BuildsPage.tsx | Removes build usage chip from builds UI. |
| apps/console/PRD.md | Updates in-flight PRD line to reflect Usage & cost v2 scope. |
| apps/console/design/decisions/ADR-0011-usage-stored-as-tokens-usd-derived.md | Amends ADR-0011 to reflect write-time stamping + DB-backed rates; preserves prior history. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- aggregation model degrade: count DISTINCT model_id INCLUDING '' in the per-project (turn) and per-(project,phase) (execution) rolls-ups, so a mix of known + unknown-model rows reports model '' (matches TokenUsage.Add), instead of surfacing the one known model - usageFromLog: raise the scanner buffer to 16 MiB and check scanner.Err() so a token-too-long line can't silently drop the terminal result usage - agentfold TurnUsage.model: drop omitempty — '' (unknown/mixed) is meaningful and the TS @aep/agent-stream contract marks model required - contract: list-project-usage + ProjectUsageList descriptions now match the real semantics (every live project carded incl. idle $0; tiered ordering) - contracts.TokenUsage doc: USD is stamped at capture, not derived at read Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Addressed all six review comments in
Verified: |
The coding-agent runner's terminal `result` event carried no token usage, so aep-api's usageFromLog found nothing to stamp and the Usage page's Build phase stayed empty even after a coding + build run completed. Extract usage from the SDK result message (`usage` snake_case tokens + `modelUsage` for the model id) and attach it as a camelCase `usage` object on the success result, matching contracts.TokenUsage byte-for-byte so the Go parse path (contracts.ProgressEvent.Usage) reads it and stamps cost_usd onto the execution row. Model is "" when the run spanned multiple models. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e-page-291 # Conflicts: # services/aep-api/internal/gen/server_gen.go
Closes #291. Frontend + contract for Usage & cost v2. Supersedes the per-phase cost surfaces shipped in #267 and reverses ADR-0011's read-time pricing.
What changed
Contract (
packages/contracts/api/v1/openapi.yaml)GET /usage/projects(list-project-usage) →ProjectUsageListofProjectUsageCard(per-project lifetime totals;deletedflag;Usagewith a stamped, nullablecostUsd).GET /projects/{p}/usage+ theProjectUsageper-phase schema.Usage.costUsdre-documented as a write-time stamp (never repriced), null when unstamped.Console
features/usageapi swapped fromuseProjectUsage(project)touseProjectUsageList(); typed MSW mocks + fixtures cover live, deleted, and pre-stamping (null-cost) projects, plus empty/error scenarios.aep-api
projectusageslice placeholder now serveslist-project-usageas an empty list until the capture backend (aep-api: DB model rates + write-time USD stamping + org usage endpoint (BE for #291) #299) lands. Method-origin ledger + domain README follow.Docs
Why (the reversal)
Read-time USD derivation reprices all historical usage whenever a rate changes — a completed cycle silently shows dollars never actually spent. v2 stamps
cost_usdat capture from a DBmodel_ratestable, so history is immutable and rates become data, not env config. Full decision trail: #291 (grilling comment).Backend handshake
Real capture + stamping + the non-empty
/usage/projectsresponse is #299 (open, not in this PR). Until it lands, the endpoint correctly returns{"projects":[]}and the page shows its empty state. Verified against the live devaep-api:Verification
tsc,eslint,knip --production, 163 console tests, Goedge/arch/projectsgates,license-check— all green.