Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
00b244e
docs: plan provider usage and account quota parity stack
invalid-email-address Sep 5, 2026
9a9ad98
fix(usage): distinguish unresolved fallback selectors and reject miss…
invalid-email-address Sep 5, 2026
9792498
feat(quota): expose credential-scoped account and key readings
invalid-email-address Sep 5, 2026
b02ecc4
fix(quota): bound stale readings and contain async refresh failures
invalid-email-address Sep 5, 2026
768e5a0
fix(quota): honor default key auth for Kimi readings
invalid-email-address Sep 5, 2026
ac5311b
Merge branch 'codex/provider-usage-attribution' into codex/provider-a…
invalid-email-address Sep 5, 2026
f0cad26
fix(usage): retain rejected selectors and handle legacy provider IDs
invalid-email-address Sep 5, 2026
a4fb9e1
test(quota): assert secure transport for account readers
invalid-email-address Sep 5, 2026
b621a71
Merge remote-tracking branch 'origin/dev' into codex/provider-usage-a…
invalid-email-address Sep 5, 2026
140c49a
merge: preserve current dev quota readers in account quota layer
invalid-email-address Sep 5, 2026
63510ff
fix(quota): reconcile reset integration contracts
invalid-email-address Sep 5, 2026
7126993
Merge branch 'codex/provider-usage-attribution' into codex/provider-a…
invalid-email-address Sep 5, 2026
6ba4093
Merge remote-tracking branch 'origin/dev' into codex/provider-usage-a…
invalid-email-address Sep 5, 2026
7e5c264
Merge branch 'codex/provider-usage-attribution' into codex/provider-a…
invalid-email-address Sep 5, 2026
cc6bd7c
Merge remote-tracking branch 'origin/dev' into codex/provider-usage-a…
invalid-email-address Sep 5, 2026
6c70347
Merge branch 'codex/provider-usage-attribution' into codex/provider-a…
invalid-email-address Sep 5, 2026
4a97027
docs(quota): clarify webhook fixture evidence
invalid-email-address Sep 5, 2026
e76e09a
Merge branch 'codex/provider-usage-attribution' into codex/provider-a…
invalid-email-address Sep 5, 2026
30faf65
test(lab): isolate output byte limit from timeout fixtures
invalid-email-address Sep 5, 2026
772ed02
Merge branch 'codex/provider-usage-attribution' into codex/provider-a…
invalid-email-address Sep 5, 2026
908815c
Merge remote-tracking branch 'origin/dev' into codex/provider-usage-a…
invalid-email-address Sep 5, 2026
3d1b5f5
Merge branch 'codex/provider-usage-attribution' into codex/provider-a…
invalid-email-address Sep 5, 2026
2ea9ba7
fix(diagnostics): preserve bounded launcher failure evidence
invalid-email-address Sep 5, 2026
ae07a49
Merge branch 'codex/provider-usage-attribution' into codex/provider-a…
invalid-email-address Sep 5, 2026
0efd0c1
test(update): use explicit synthetic redaction paths
invalid-email-address Sep 5, 2026
b76390b
Merge branch 'codex/provider-usage-attribution' into codex/provider-a…
invalid-email-address Sep 5, 2026
263fba9
docs: finalize independent provider stack integration plan
invalid-email-address Sep 5, 2026
e0aadb6
Merge commit '45f3bed84be10a7e045a20aae1db46ab822bf7d0' into codex/pr…
invalid-email-address Sep 5, 2026
947e8bd
Merge branch 'codex/provider-usage-attribution' into codex/provider-a…
invalid-email-address Sep 5, 2026
e7517bb
docs: record final dev freshness requirement
invalid-email-address Sep 5, 2026
f58260a
Merge commit '09335d7d451335a74ad1c02e88ee37ef89f5a007' into codex/pr…
invalid-email-address Sep 5, 2026
616e5b5
Merge branch 'codex/provider-usage-attribution' into codex/provider-a…
invalid-email-address Sep 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions devlog/_plan/260905_provider_usage_quota_parity/000_plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Provider usage and account quota parity

## Loop contract

- Archetype: spec-satisfaction repair; class C3, management contract changes receive C4 review.
- Trigger: provider detail shows foreign-looking selectors and inconsistent account quotas.
- Goal: truthful serving-provider/model accounting and consistent current/all-account quota views.
- Non-goals: rewriting user history, guessing the actual historical model, broad router strictness for custom aggregators, new providers, authentication changes, deployment or release.
- Verifier: existing remote CI for regression tests; local static type checks, GUI build/lint, privacy scan and isolated browser/API smoke. **No local tests or suites**, including git hooks. Commit/push with `--no-verify`.
- Stop: audited slices, screenshots and exact-head CI, then bottom-up admin merges and fetched-dev ancestry.
- Memory: this unit and the session-bound goalplan/ledger.
- Outcomes: DONE with evidence; external BLOCKED, authority UNSAFE/NEEDS_HUMAN, or stated-bound BUDGET_EXHAUSTED only.
- Delegation: read-only inventory/audit, bounded disjoint implementation only by P amendment; no model/effort overrides. Main reclaims after two distinct failed dispatches.
- Scope/resources: current managed checkout only; existing GitHub PR/CI credentials; sanitized read-only runtime evidence; no inference or reset-credit spending; no new paid services. 90 minutes active work per phase, 6 hours total; no explicit token budget requested.

## Dependency map

1. `roadmap`: docs-only cycle; lock all decade plans.
2. `attribution` / `010_attribution.md`: routing and accounting foundation, regression coverage; bottom stack branch `codex/provider-usage-attribution` targets `dev`.
3. `quota-api` / `020_account_quota_api.md`: credential-scoped readers and capability DTOs; `codex/provider-account-quota-api` targets the bottom branch.
4. `quota` / `030_quota_views.md`: current-account and all-account presentation consumes the account API; `codex/provider-quota-parity` targets the API branch.
5. `landing` / `040_stack_landing.md`: independently audit final stack and land bottom-up after exact-head CI.

## Existing ownership

```text
src/router.ts route resolution
src/usage/{log,summary,cost}.ts append-only rows and aggregation
src/providers/quota*.ts quota capability and reports
gui/src/provider-workspace/ pure report adapters
gui/src/components/provider-workspace/ provider tabs
structure/05_gui-and-management-api.md current contract
tests/{routing,usage,providers}/ existing regression domains
gui/tests/ rendered component contracts
```

Reuse the existing report adapters, QuotaBars and account panels. Doing nothing keeps misleading model labels; deleting rows loses real usage; configuration alone cannot clarify historical rows. No new quota client or history database is justified.

## Baseline and verification constraints

Base HEAD `526d4bf64` matched fetched `origin/dev`; initial tree clean.
`bun run typecheck` could not run before dependencies existed (TS2688); after frozen-lock install with scripts disabled the bundled Bun wrapper requires its postinstall. `node node_modules/typescript/bin/tsc --noEmit` exited 0 and reads repository `tsconfig.json`. Use that equivalent direct checker without enabling lifecycle scripts. Remote CI owns test execution, explicitly overriding the local-suite recommendations in repo/skills.

## Design read

Keep the supplied developer-dashboard layout, existing CSS tokens, font and icon set. Variance 2, motion 1, density D8. No visual concept generation: this is a utility dashboard repair, not a redesign. Current quota must sit below usage statistics; provider-wide capacity and current-account quota are different concepts. Unknown is not zero, observed is not freshly probed, and an unsupported API is not a failed account.

## Continuity

Roadmap locked after Kant's independent audit and two repair rounds, final VERDICT: PASS.
Docs-only delivery: 000, 001, 002 and all four decade docs; no production changes.
Static source checker and GUI build passed; existing chunk-size warning only. No local tests.
Next work-phase: attribution. Open risk: unseen historical upstream model identity cannot be
recovered; we qualify only saved fallback provenance instead of guessing or rewriting rows.

Attribution D: `9a9ad98b8`, PR #3582, CI run33938837845 all four backend test shards,
GUI gates (1371 pass / 0 fail), API usage succeeded; independent Volta PASS. Remaining macOS
jobs are still mandatory at landing, not claimed green. Next quota-api P reverified 020 against
the unchanged quota/management baseline; attribution changes do not alter its signatures.
API layer branch `codex/provider-account-quota-api` starts at the verified attribution head.

## Delegation write map (locked before Build)

User reiterated no local suites during quota-api A. No local test suite has been run;
reported regression results came from GitHub Actions. From this point no further local
typecheck/build/lint/scan commands either: command-based validation is remote CI only.
Source inspection and browser observation remain scoped QA; receipts may only wrap remote
CI result checks. This supersedes the earlier local-static/build verification allowance.

- Attribution cycle: Harvey owns `src/usage`, `src/router.ts`, the identified Chat/Messages error catches, `src/server/management/shared.ts`, and corresponding existing backend regression files. Main owns the provider model annotation/share/caching UI, its GUI regressions, docs, commits and CI. No overlapping writes.
- Quota API cycle: Euclid owns quota readers/key-cache/types and relevant provider regression files. Main owns management route joins, API-route regressions and docs; clarify exact exported signatures before either writes.
- Quota UI cycle: main owns report projection/current section; a bounded worker may own account hook/panel refresh and regression changes only after an explicit P amendment gives disjoint paths.
- Independent Kant audits plans read-only; fresh independent final implementation review remains required. No worker changes FSM, goals, branches, commits or remote state, and no worker runs local tests.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Attribution investigation

## Competing hypotheses and falsifiers

- H1: UI groups rows using the selected provider rather than each row's provider. Falsifier: shell groups by `m.provider` and original ledger has those same provider/model pairs.
- H2: persistence keeps a stale provider after a real cross-provider route. Falsifier: persisted route decision and physical attempts both select Kimi via `default-provider`.
- H3: unmatched request selectors fall through to the default provider and remain displayed/priced as if they were confirmed served model identities. Falsifier: router rejects unknown policy selectors, or source/ledger records a distinct resolved physical model.

## Observed facts

`ProviderWorkspaceShell.tsx:214-220` groups API model rows by `m.provider`; it does not copy global rows into every provider. `src/router.ts:603-609` explicitly documents missing `policy/<id>` falling through; `:794-798` forwards the unmatched identifier unchanged to the default provider. `src/server/responses/core.ts:2069-2072` writes the actual chosen route provider/model into log context.

A read-only streaming scan of the real ledger, emitting no credentials, request bodies or account identities, found foreign-looking selectors under Kimi with `routeKind=default-provider` and Kimi physical attempts. The historical nonexistent-policy row also has a successful terminal response and measured tokens. This rejects H1 and the simple stale-provider form of H2. It proves the fallback mechanism in H3, not the identity of the actual model behind the remote endpoint. An echoed `response.model` alone is not such proof.

Historical usage must stay attributed to the recorded serving provider, not transferred to whichever provider name appears before a slash. Unknown native slash IDs must remain supported for genuine aggregators. Missing reserved policy names can be rejected without globally banning unknown model IDs.

`src/usage/cost.ts:317-329` falls back to model-level vendor price regardless of serving provider; `vendorPrefixedCost` validates the prefix against the vendor but does not prove that a default-fallback request actually ran that model. A fallback selector needs an honest distinction from confirmed model identity, not a fabricated Kimi price.

## Unresolved before audit

Choose a compact backward-compatible fallback presentation which preserves counts, tokens and requested identifiers without mispricing them. Inventory quota capability owners before finalizing 020. No user ledger mutation is authorized or planned.

## Deterministic local diagnostic (not a test suite)

Direct `routeModel` invocation with an in-memory config containing only Kimi and model `k3`, no credential or network execution: `policy/does-not-exist`, empty `policy/`, and `anthropic/claude-opus-5` all returned provider `kimi` with routeKind `default-provider`; `k3` returned `explicit-provider`. Process exited 0. This independently reproduces the saved route trace and establishes a negative-case before-state for the later HTTP/CI regressions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Roadmap audit synthesis

Reviewer Kant, first partial round: FAIL (one High, two Medium); 020 not yet reviewed.

1. Accepted missing attempt DTO cost propagation. Root cause: Logs computes parent and attempt metrics separately. 010 now forwards parent routeDecision into each attempt projection and adds DTO regression coverage.
2. Accepted refresh waiter ownership gap. Root cause: global unversioned success settles newer callers. 030 now binds waiters and callback to captured epoch, supersedes older tickets with false, and tests the actual page coordinator.
3. Accepted enrichment HTTP failure state gap. Root cause: cheap rows overwrite last-good quota, while asynchronous failure is swallowed. 030 now merges by surviving credential ID and uses generation-fenced pending/unavailable transitions.
4. Scope clarification accepted: all unchanged default-provider selectors receive the provenance annotation; only slash-containing unresolved selectors restrict vendor-only pricing. Bare prices remain unchanged. This covers the screenshot's bare Gemini/Qwen selectors without a catalog/history guess.

No production code changed during this round. Re-audit required.

Second round: first three blockers closed; two further blockers accepted. Internal key
results now keep a private `isCurrent` closure carrying captured identity/clear epoch through
the final safe DTO projection, with same-ID env/keychain replacement regression. 020's GUI
signature now uses the same boolean refresh argument as 030 (force and await together).
Corrected the Logs projection owner name to `requestLogDto`. Scope-lock also removes the
unnecessary global scheduler/forced-successor design; bounded per-roster workers retain the
required capability without changing global report scheduling. Re-audit only these deltas.

Final delta re-audit by Kant completed before roadmap B: both remaining blockers closed,
private identity guard and boolean refresh arguments confirmed, `requestLogDto` anchor corrected.
Recorded verdict: "Blocking issues: none. Design-only approval; no tests or mutations performed.
VERDICT: PASS". The session ledger's roadmap A→B attestation records that verdict; roadmap
commit00b244e7a closes the docs-only delivery. Repository integration and runtime deployment
remain separate, as040 requires; no service restart is implied by any roadmap or merge result.
Loading
Loading