Skip to content

chore: integrate codex-lb v1.24.0 - #15

Draft
nikhilshinday wants to merge 555 commits into
aneym:mainfrom
nikhilshinday:chore/sync-codex-lb-v1.24.0
Draft

nikhilshinday wants to merge 555 commits into
aneym:mainfrom
nikhilshinday:chore/sync-codex-lb-v1.24.0

Conversation

@nikhilshinday

Copy link
Copy Markdown

Integrate codex-lb v1.24.0 into agent-lb, bringing its durable bridge and recovery paths, model sources and embeddings, account coordination, usage rollups and retention, and dashboard contracts into the fork. Preserve agent-lb’s Claude routing and billing guards, credential custody, member and machine attribution, spend limits, cockpit, client entry points, and deployment workflow.

Join the upstream and fork migration histories and add compatibility migrations for durable OAuth provider identity and provider cache accounting. Include focused regressions for provider dispatch, forwarded identity, source pricing, reset-credit serialization, usage retention, and scheduling, plus the maintainer’s current main changes. This is a draft pending the documented CI, review, and inherited size-policy gates; the integration evidence and remaining requirements are in openspec/changes/sync-codex-lb-v1-24-0/verification.md.

mereyabdenbekuly-ctrl and others added 30 commits July 22, 2026 18:05
Co-authored-by: SSY <234955825+mereyabdenbekuly-ctrl@users.noreply.github.com>
* fix(proxy): recover verified responses after owner loss

Classify required continuity-owner misses without degrading the wider account pool.

Permit cross-account recovery only for durable, account-neutral full resends and fence the recovered lane across aliases, restarts, and model transitions.

* fix(proxy): preserve typed sticky selection errors

* fix(proxy): project owner-bound response history
…ju06#1458)

* fix(useragent): fixing the unexpected output for Codex Desktop/... to show Codex Desktop

* update ruff

* update test
Bumps [actions/checkout](https://github.com/actions/checkout) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@9c091bb...3d3c42e)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…#1427)

* chore(deps): bump typescript from 6.0.3 to 7.0.2 in /frontend

Bumps [typescript](https://github.com/microsoft/TypeScript) from 6.0.3 to 7.0.2.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Commits](https://github.com/microsoft/TypeScript/commits)

---
updated-dependencies:
- dependency-name: typescript
  dependency-version: 7.0.2
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(frontend): isolate TypeScript 7 compiler

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Darafei Praliaskouski <me@komzpa.net>
* feat(helm): support Gateway API rule filters

* fix(helm): bypass auth for all API paths

* fix(helm): keep file uploads on direct route

* fix(helm): keep Codex usage API direct

* fix(helm): keep WHAM identity API direct

---------

Co-authored-by: Darafei Praliaskouski <me@komzpa.net>
Retry only pre-dispatch or provably replay-safe stream failures. Once an upstream POST may have been accepted, terminal SSE errors and empty upstream EOF are surfaced exactly once instead of resubmitting. Updates OpenSpec (openspec/changes/retry-model-capacity-errors) to describe the terminal no-replay contract; regression tests cover visible-output, pinned-owner, post-dispatch, and selection-exhaustion boundaries.
Harden compact and HTTP-bridge continuity recovery so previous-response, turn-state, and session-header owners remain fail-closed across reconnects, replicas, and blue/green handoff.

- keep ownerless or ambiguous durable recovery fail-closed
- retain same-account durable handoff and explicit previous-response owner preference
- route durable claim/turn-state clearing through the session_registry owner
- preserve hard-owner retry constraints while allowing soft non-file affinity reallocation

OpenSpec: fail-closed-http-bridge-security-retry
Keep complete historical side-effect call/output pairs during Responses compaction without making the tool tail permanently untrimmable.

- Use the canonical downstream side-effect classifier shared with tool-call safety and dedupe (covers code-mode names like exec/collaboration, including nested parallel tool_uses).
- Reserve budget for complete side-effect pairs before optional ordinary context, preferring newest pairs; fail closed when required state alone exceeds the compact budget.
- Cover the real /backend-api/codex/responses/compact product path in integration tests.
- Record the retention and fail-closed contract in OpenSpec (openspec/changes/preserve-historical-compact-side-effects).
Extend the scheduled Codex label synchronizer to own the 'needs rebase' label: add it for confirmed DIRTY/CONFLICTING merge states, remove it for known mergeable or non-conflict states (BEHIND, BLOCKED, HAS_HOOKS, UNSTABLE), and preserve the current value only while GitHub reports UNKNOWN. Includes the sync-needs-rebase-label OpenSpec change and unit coverage for label decisions and exact GitHub API writes.
Add a Playwright Chromium smoke test that drives the built dashboard against a real local uvicorn/FastAPI backend with no /api/** interception, catching frontend/backend contract drift pre-merge. The harness isolates dotenv and CODEX_LB_* env, uses a temp data dir and ephemeral loopback socket, validates session/overview/request-log/projections responses (projections parsed with DashboardProjectionsSchema), and fails on API, page, console, or schema errors. Wired into CI Required for backend or frontend changes; local entrypoint is make test-dashboard-browser-smoke.
CI lint broke on every main commit since 2026-07-24 because `make lint`
invokes ruff via unpinned `uvx`, which resolved to the freshly released
ruff 0.16.0. Its `format --check` newly flags
.agents/skills/project-conventions/conventions.md, while the locked
toolchain (uv.lock pins ruff 0.15.22) passes all 837 files.

Switch the two lint invocations to `uv run ruff` so lint uses the same
locked version as ty/pytest, and future ruff upgrades land explicitly
through lockfile bumps with CI visibility.

Failing run: https://github.com/Soju06/codex-lb/actions/runs/30064365055
* chore(main): release 1.22.0

* chore(release): sync uv.lock to 1.22.0
* ci(release): sync uv.lock on release-please branches

release-please bumps pyproject.toml and the other version files but cannot
regenerate uv.lock, so every release PR fails the stable/beta release guards
(version files must agree) until someone pushes a manual 'uv lock' commit —
this happened again on the v1.22.0 release PR (Soju06#1330).

Add a follow-up step to the Release Please workflow: when a release PR
exists, check out its branch, run 'uv lock', and push the sync commit with
the same RELEASE_PLEASE_TOKEN (PAT, so CI still triggers on the new head).
No-op when the lockfile is already in sync.

* fix(ci): resolve release branch from the canonical open PR

Reruns must repair release branches even when release-please's update-only
'pr' output is absent (codex review P2).
…1469)

* docs(contributing): require beta soak before stable releases

Codify the release channel convention: stable versions are promoted from a
beta that has soaked on a production-scale deployment for at least 48 hours.
Documents the maintainer exception path (docs/CI-only deltas, urgent security
or outage hotfixes) and adds a pre-merge reminder to estimate data-backfill
migration duration, since backfills run at startup and block serving.

* docs(openspec): add require-beta-soak-before-stable change

Spec delta for the stable-promotion soak requirement + exception path +
Alembic-revision backfill review; CONTRIBUTING now points at the normative
spec and inspects revisions instead of the changelog (codex review P2s).

* docs(openspec): scope the hotfix exception to hotfix-only deltas

A train carrying unrelated unsoaked changes cannot ride a hotfix exception
(codex review P2); spec and CONTRIBUTING now state it identically.

* docs(openspec): apply the safe-delta rule to post-soak changes too

Changes landing after the soaked prerelease are part of the unsoaked delta
and either restart the soak or must qualify for the safe-delta exception
(codex review P2).

* docs(openspec): track the CI follow-up as a note, not a task

Keeps the change archivable at full task completion (codex review P2);
follow-up lives in issue Soju06#1471.

* docs(openspec): make beta coverage conditional on the safe-delta exception

The soak requirement and the exception no longer contradict (codex P2).

* docs(openspec): feature changes after the soak require a new prerelease

The post-soak scenario no longer offers the exception to an ineligible
change (codex P2).
Soju06#1478)

* docs(openspec): add request-log usage rollups change proposal

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(rollups): add time-axis usage rollup schema, migration, and repository

Schema layer for hourly usage rollups: three permanent aggregate tables
(request_usage_hourly_rollups, request_usage_hourly_error_rollups,
request_demand_quarter_rollups) with BIGINT epoch bucket keys, ''
sentinels for nullable PK dimensions, and no secondary indexes, plus a
separate hourly_folded_through watermark column on the shared fold-state
row so the hourly backfill never touches the lifetime rollups.

The alembic revision is guarded, idempotent, and DDL-only (tables are
created empty; backfill is owned by the runtime fold pass), with a
guarded downgrade. RequestUsageTimeRollupRepository provides merge-add
upserts (pre-merging duplicate keys per batch) and half-open range reads
that return rows and the hourly watermark from one statement/snapshot.

Verified on SQLite and PostgreSQL 18 (drift contract, empty-db upgrade,
migration round-trip, repository tests); new test file registered in
POSTGRES_PYTEST_TARGETS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(rollups): fold request logs into hourly time-axis rollups incrementally

Implement the incremental hourly fold pass and everything that must ship
atomically with it:

- run_hourly_fold_pass: hour-aligned half-open slices (48h, max 20 per
  pass), fold-state row lock shared with the lifetime fold, bounded
  min(requested_at) pre-scan that jumps empty prefixes and mid-history
  gaps, defensive DELETE then three INSERT..SELECTs (hourly usage, error
  satellite with the exact top-error filter, quarter demand), watermark
  advance in the same transaction. Crash-safe and convergent: a rewound
  watermark re-folds to identical contents, no double counting possible.
- Scheduler wiring: hourly pass runs after the lifetime pass in the
  existing AccountUsageRollupScheduler tick under the same leader gate,
  in its own try-block so one family's failure never stops the other.
- Account lifecycle mirrors: soft delete moves folded buckets to the
  ('', is_deleted=true) dimension (merge-add), hard delete removes them,
  duplicate-account consolidation re-keys them onto the canonical
  account — all inside the fold-state-locked transactions, mirroring the
  raw request_logs mutation exactly (folded buckets are never recomputed
  from raw, which retention may already have pruned).
- Retention min-gate: request-log pruning now gates on
  min(folded_through, hourly_folded_through) including the currency
  check, so raw rows can never be pruned before the hourly backfill has
  captured them (pruning pauses entirely during backfill).

Tests (SQLite + PostgreSQL 18): dimension/measure fold correctness
(warmup, soft-deleted, NULL dims, duplicates, reasoning-only, NULL cost,
cached>input clamp, error codes), idempotency, crash-resume, capped
backfill pacing, boundary attribution and FOLD_LAG, empty-history and
gap jumps, watermark rewind self-heal, lifecycle mirrors incl. a
delete-vs-fold race, and the three retention min-gate branches.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(rollups): switch time-series reads to hourly rollups with raw live tail

Serve dashboard bucket/activity/top-error, quota-planner demand bins, and
api-key trends from the time-axis rollup tables below the hourly watermark,
scanning raw request_logs only for the un-folded complement. One shared
partition helper owns the boundary arithmetic (hour/quarter-aligned rollup
segment, partial leading window + tail always raw); the watermark and rollup
rows come from a single statement so a concurrently committing fold slice can
never drop or double-count a window. Distinct-conversation metrics stay
raw-only (documented non-goal), earliest-activity falls back to the earliest
folded bucket at hour precision once raw is pruned, and an epoch watermark
degrades every reader to the exact legacy raw query (escape hatch, no kill
switch). Parity harness asserts field-level equality against the legacy
readers across watermark states, under concurrent folds, after an escape-
hatch reset, and after retention physically pruned the folded raw rows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(rollups): preserve planner demand grain, guard model rewrites, match reader clamp

Local codex review round (1 P1, 2 P2), all fixed:

- [P1] Quarter demand rollup regains the full legacy grain (api_key_id,
  model, reasoning_effort, status join the PK): the planner's
  _bin_demand_units applies max(token, cost, request units) PER BIN before
  summing, so the coarser (slot, account, kind) fold systematically shrank
  folded-history forecasts wherever a slot mixed groups with different
  dominant components. Fold, read path, models, and migration updated; the
  migration rebuilds a pre-merge-shape quarter table and resets the hourly
  watermark (unreleased revision, raw intact). Parity now asserts demand
  bins at the exact legacy grain instead of additive projections.

- [P2] update_model_for_request now takes the fold-state lock and rewrites
  only rows at/above min(folded_through, hourly_folded_through): the rewrite
  matches by client-controlled request_id, so a reused id could mutate
  model/cost of folded history unmirrored (permanent divergence once
  retention prunes raw). Pre-watermark collision rows are skipped — they
  were never the rewrite's target. Early-return path releases the lock.

- [P2] cached_input_tokens_clamped fold now mirrors
  cached_input_tokens_from_log exactly: NULL input keeps the non-negative
  cached value instead of clamping it to zero (the column is permanent data
  for the future usage-summary switch; the undercount was unrepairable
  after retention).

OpenSpec deltas updated to match (quarter grain requirement, clamp
scenario, model-rewrite scenario, mirror-or-skip discipline).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(rollups): gate rewrites on max watermark, keep exact earliest pre-retention

Local codex review round 2 (3 P2): two fixed, one rebutted.

- [P2] update_model_for_request gates on max(folded_through,
  hourly_folded_through), not min: a row is un-folded by EVERY rollup only
  at/above the most advanced watermark (min is the retention gate's
  direction). With diverged watermarks a reused request id could rewrite a
  row already captured by the more advanced rollup. Test now diverges the
  watermarks and asserts the in-between row is skipped.

- [P2] earliest_activity_at no longer rounds down while raw survives: the
  hour-precision rollup fallback applies only when the earliest folded
  bucket is STRICTLY below the surviving raw row's own bucket (i.e. earlier
  raw was actually pruned). Previously an unaligned earliest row was
  reported as its floored bucket the moment it was folded, breaking
  pre-retention parity. Parity corpus gains an unaligned earliest row.

- [P2, rebutted — docs only] partial unaligned edge buckets over
  retention-pruned history remain raw-served by design (documented D7
  decision: sub-bucket boundary contributions cannot be represented in an
  hourly grid; serving the whole edge bucket would over-count). Deterministic
  <=1-bucket undercount per edge, only for windows older than retention;
  read-module docstring now spells out the trailing edge too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(rollups): match the lifetime fold's inclusive bound in the rewrite gate

Local codex review round 3 (1 P2, fixed): the lifetime fold interval is
(start, end] (after_exclusive/until_inclusive), so a row exactly AT
folded_through is already folded — the round-2 max()-with->= gate still let
a reused request id rewrite that row's cost unmirrored. The gate now applies
each watermark with its own fold's convention: requested_at > folded_through
AND requested_at >= hourly_folded_through. Test adds the exact-boundary row.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(rollups): chunk lifecycle upserts, coerce falsy top-error winner to None

Local codex review round 4 (2 P1, 1 P2): two fixed, one accepted as a
documented bounded risk.

- [P1] Merge-add upserts now chunk at 1,000 rows per statement: lifecycle
  mirrors rekey an account's ENTIRE folded hourly history in one
  transaction, and asyncpg rejects statements over 32,767 bind parameters
  (~1,900 unchunked 17-column rows) — soft-deleting or consolidating a
  long-lived account would have aborted the whole lifecycle transaction on
  PostgreSQL. Regression test seeds 2,500 rows and mirrors them (runs in
  the PG suite).

- [P2] _top_error coerces a falsy winner to None: the nullable error_code
  column permits '' on non-success rows and the legacy single-statement
  reader returned None when the top row's code was falsy; the merged
  folded+raw counting returned ''. Covered on both the folded satellite
  and the raw tail.

- [P1, accepted — docs only] Rolling-upgrade mixed-version window (old
  retention leader pruning on the lifetime gate; old lifecycle/rewrite
  handlers not mirroring): documented in design Risks with the blast-radius
  analysis — the retention leg only prunes history already past the
  retention period (pre-upgrade semantics), the lifecycle leg is confined
  to the minutes-long deploy window and fully recoverable via the
  documented escape hatch while raw retention holds. Two-release staged
  activation rejected as disproportionate for dashboard statistics.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(retention): lock the fold state while deciding a prune batch

Local codex review round 5 (2 P2): one fixed, one rebutted.

- [P2] Retention's per-batch watermark read now takes the fold-state row
  lock (FOR UPDATE; SQLite drops it — the writer section already
  serializes there): an unlocked read racing the operator escape hatch
  (rollup truncate + watermark rewind, one transaction) could capture the
  pre-reset watermark and prune raw rows whose folded statistics were just
  truncated — recoverable from neither side. With the lock, the reset
  either commits first (the batch sees the epoch watermark and pruning
  pauses) or waits for the batch.

- [P2, rebutted — docs only] "clear rollup ranges the fold's min()-jump
  skips on a rewound watermark": convergence is guaranteed under the
  escape hatch's documented precondition (raw still present, or the
  atomic truncate+rewind; rewind-only is the spec's documented forbidden
  state), and clearing skipped hours would delete the ONLY surviving copy
  of retention-pruned statistics after an operator mistake — preserving
  them is the safer failure mode. Fold comment now spells this out.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(rollups): make the NULL-dimension sentinel collision-free

The '' sentinel conflated SQL NULL with the legitimate empty-string
value the request models accept for service_tier/reasoning_effort,
merging two distinct legacy GROUP BY groups into one rollup PK and
reporting the merged group as NULL (and shifting planner demand bins,
whose max() per bin is nonlinear).

- Encode NULL as U+001F and escape sentinel-prefixed raw values with
  one more sentinel character (injective; '' round-trips); the fold
  INSERT..SELECTs mirror the codec via a dialect-portable CASE.
- Encode raw ids at every stored-dimension comparison boundary
  (lifecycle mirrors, api-key trends filter).
- Drop the misleading DEFAULT '' from the dimension columns; the
  migration detects the pre-merge ''-encoding by that lingering
  default and rebuilds the (unreleased) rollup tables + resets the
  hourly watermark so the fold re-encodes from raw.
- Parity corpus gains NULL / '' / sentinel-prefixed dimension rows in
  one folded and one raw-tail cluster; codec round-trip and migration
  rebuild legs added.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(rollups): unpack model rows explicitly for the type checker

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(proxy): sequence synthetic Responses failures

* test(proxy): cover non-integer failure sequences

* fix(proxy): sequence synthesized failure envelope

* fix(proxy): sequence generated failure envelopes

* fix(proxy): separate sequenced failure envelope

---------

Co-authored-by: Maxim Feofilov <maxim.feofilov@exilion.com>
…1462)

* feat(helm): support creating an application-specific Gateway

Add gatewayApi.gateway.create to render a release-scoped Gateway API
Gateway (required GatewayClass name, default HTTP :80 listener,
operator-defined listener override) and attach the chart-managed
HTTPRoute to it automatically, so installs no longer depend on a
pre-existing shared Gateway. Defaults are unchanged.

Also reformat six Markdown files whose fenced code blocks ruff 0.16.0
now formats, keeping the unpinned uvx ruff lint step green.

* docs(helm): point Gateway setup to canonical docs

* docs(helm): remove unavailable TLS example reference
* feat(proxy): support Codex Live Voice sideband

* fix(proxy): harden Codex Live Voice sideband

* test(proxy): harden Voice sideband regressions

* fix(proxy): route duplicated Live sideband aliases

* fix(proxy): redact private account selection logs

* style(proxy): format private selection logging

* fix(proxy): redact Live sideband account selection

* fix(proxy): redact private Live admission and failover

* fix(proxy): bound repeated Live close cleanup

* fix(proxy): redact private stale lease cleanup

* fix(proxy): suppress private Live setup details

* fix(proxy): scope reserved sticky keys to the Live-call namespace, instrument factory apps

Two review findings: the reserved-key check matched every LF-prefixed key,
hiding pre-existing selection-affinity rows from operator list/delete; and
a factory-created app after global OTEL init skipped per-app FastAPI
instrumentation. Reserve only "\ncodex_live_call:", extract per-app
instrumentation from init_tracing, and pin the affinity regression in the
reserved-bindings test.

---------

Co-authored-by: Soju06 <qlskssk@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(proxy): extend websocket stream budget

* fix(proxy): route native websocket relay through stream budget

* fix(proxy): use stream budget for websocket reconnects

---------

Co-authored-by: Soju06 <qlskssk@gmail.com>
* fix(proxy): preserve fresh bridge full resends

* fix(proxy): prove fresh tool-loop resends

* fix(proxy): reject malformed tool lifecycles

* fix(proxy): fail closed on partial bridge manifests

* docs: add @mhooooo as a contributor

* fix(proxy): preserve anchors after owner forwarding fails

* fix(proxy): rebind takeover to refreshed owner

* fix(proxy): record unsupported prefix call ids in replay collision check

A call-like prefix item outside the supported direct tool-call vocabulary
(e.g. computer_call) was silently skipped by _direct_tool_call_prefix_state,
so a pending call reusing its call_id passed the freshness collision check
and could be resent without the durable anchor. Record fall-through call
ids so the collision check fails closed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Maxim Feofilov <maxim.feofilov@exilion.com>
Co-authored-by: mhooooo <n.tanyawit@gmail.com>
Co-authored-by: Soju06 <qlskssk@gmail.com>
Co-authored-by: Soju06 <11311479+mastertyko@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…#1515)

Bumps the python-minor-patch group with 8 updates: aiohttp 3.14.2 to 3.14.3, certifi 2026.6.17 to 2026.7.22, greenlet 3.5.3 to 3.5.4, prometheus-client 0.25.0 to 0.26.0, pre-commit 4.6.0 to 4.6.1, ruff 0.15.22 to 0.16.0, ty 0.0.61 to 0.0.64, openai 2.46.0 to 2.48.0.

Maintenance gate alignment for the new toolchain versions:

- Exclude Markdown from Ruff so the formatter keeps its prior Python-only scope after Ruff 0.16 enabled Markdown code-block formatting by default.
- Pin ruff-pre-commit to v0.16.0 so local hooks match the locked CI formatter.
- Drop the now-stale ty unknown-argument suppression for the documented pydantic-settings _env_file keyword.
Upgrade astral-sh/setup-uv to v9.0.0 using its immutable release SHA

Preserve the existing cache-pruning policy explicitly across every cache-enabled workflow so v9's changed default cannot silently increase cache storage
… updates (Soju06#1513)

Dependabot update. See Soju06#1513 for the full changelog.
HulianBuligon and others added 27 commits August 20, 2026 14:07
* fix(warmup): warm paid-to-free transitions

* fix(warmup): reject exhausted transition samples

---------

Co-authored-by: Hulian Felipe Muller Buligon <hulian@MacBook-Pro-de-Hulian.local>
Add POST /v1/embeddings routed to OpenAI-compatible model sources, mirroring
the audio-transcriptions capability shape (Soju06#261):

- model_sources.supports_embeddings column (additive migration) + schema,
  service, repository finder, and dashboard capability toggle/badge
- forwarding: forward_embeddings posts the client payload to the source's
  /embeddings, passes the response through, and reads usage from
  prompt/total tokens (embeddings report no completion tokens)
- proxy: /v1/embeddings validates model+input, passes other OpenAI params
  (encoding_format, dimensions, user, ...) through verbatim, enforces the
  same API-key model access/limits, settles usage, and writes the same
  model_source request_logs row as chat/audio (previously /v1/embeddings
  returned 405 and nothing was ever logged)
- unknown model returns OpenAI-shaped model_not_found (embeddings have no
  subscription-backed fallback); upstream errors pass through and log;
  usage-less responses fail closed for limited keys

Integration tests cover the happy path (payload passthrough + ledger row),
unknown model, upstream error logging, and the limited-key fail-closed path.
…6#1814)

* fix(reports): group full Cost values

* test(reports): cover grouped Cost axis ticks

* docs: add hanseo0507 as contributor

---------

Co-authored-by: Soju06 <qlskssk@gmail.com>
Co-authored-by: Soju06 <qlskssk@gmail.com>
…lities at startup and in CI (Soju06#1622)

Rebased onto current main; squashed the branch's review-iteration commits.

Co-authored-by: Soju06 <qlskssk@gmail.com>
…owlist budget (Soju06#1837)

Removes root agent-debris files (SUMMARY.md deleted; DECISIONS.md ADR relocated to openspec/specs/proxy-architecture/context.md as a git rename) and adds a [root_files] allowlist to the simplicity-budget checker so unlisted tracked root entries fail CI with the standard label escape hatch.

OpenSpec change: add-root-file-allowlist-budget (contribution-simplicity delta).
…ds (Soju06#1808)

* fix(models): apply context-window overrides to /v1 input context fields

An operator `model_context_window_overrides` entry only reached
`metadata.context_window`. The generic OpenAI-compatible fields that most
clients actually read — `context_length`, `contextLength`,
`capabilities.context_length` and `metadata.input_context_window` — kept
reporting the un-overridden upstream window, so those clients capped
themselves at 272k while Codex-native clients used the wider window from
`/backend-api/codex/models`.

Report the override on those fields too, clamped to the upstream-declared
`max_context_window` so an override can never advertise more input than the
backend sanctions. This is the same clamp the Codex client applies to
`model_context_window` in config.toml. Behavior is unchanged when no override
is configured.

* fix(models): resolve context-window override once and clamp it everywhere

Address the three review blockers on the override fix:

- Collapse _effective_context_window / _v1_full_context_window /
  _v1_input_context_window into a single _resolved_context_window and
  resolve it once per list item, so metadata.context_window, the
  context_length-family input-budget fields, and the Codex-native
  context_window/max_context_window rewrite all report one clamped
  value. Previously an override above the backend ceiling produced
  metadata.context_window=1000000 next to context_length=872000 — a new
  dual-budget split — and each list item called get_settings() four
  times.

- Restore the pre-existing scenario heading "Explicit reported-context
  overrides do not hide the backend input budget" in the MODIFIED
  requirement (a MODIFIED block replaces the whole requirement, so the
  renamed heading would have silently dropped the original scenario at
  archive time); keep the updated assertions under it. openspec strict
  validation now passes for the change.

- Correct the proposal's false "/backend-api/codex/models is untouched"
  claim: the endpoint's OpenAI-compatible data alias shares the
  /v1/models list-item shape, so its context_length-family fields do
  pick up the override (the native models list semantics are the
  pre-existing override behavior, now clamped). Pin both behaviors with
  tests, and extend the clamp test to assert all fields agree at 872000.

Co-authored-by: yeongjun-cigro <enlit.dev.1@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(models): do not treat synthesized max_context_window as a clamp ceiling

Local codex review caught a P2: bootstrap subscription models
(_bootstrap_model) and source-catalog models
(source_models_to_upstream_models) synthesize
max_context_window == context_window purely so Codex clients can parse
the entry. Clamping operator overrides to that parseability default
silently disabled every raise override for those models — a regression
against the pre-existing override behavior on metadata.context_window
and the Codex-native catalog. Clamp only when upstream declares a
ceiling strictly above the backend context_window, update the openspec
delta accordingly, and pin the behavior with a route-level source-model
regression test.

Co-authored-by: yeongjun-cigro <enlit.dev.1@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(openspec): specify codex-native catalog override behavior

CodeRabbit correctly flagged that the delta only covered GET /v1/models
while the implementation also changes /backend-api/codex/models. Add a
MODIFIED block for "Codex-native model catalog keeps backend catalog
fields" stating that an operator override reports the single resolved
(clamped) value on the native context_window and the max_context_window
rewrite, that the synthesized parseability ceiling never clamps, and
that the data alias reports the same resolved value on its
context_length-family and metadata fields. Both new scenarios are
already pinned by tests
(test_model_context_window_override_clamped_to_max_context_window and
test_model_context_window_override_applies_to_codex_models_data_alias).

Co-authored-by: yeongjun-cigro <enlit.dev.1@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: yeongjun-cigro <enlit.dev.1@gmail.com>
Co-authored-by: Soju06 <qlskssk@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ared OAuth store (Soju06#1839)

tests/integration/test_oauth_flow.py was order-dependent within the file
with a different victim per run (issue Soju06#1794): tests only reset the
module-global oauth_module._OAUTH_STORE at their START, and
_OAUTH_STORE.reset() cancels poll tasks without awaiting them, so a
device poller leaked by one test kept running on the shared session loop
through the next test's entire fixture setup and body.

Three concrete leaks fixed:

- Add an autouse _isolate_global_oauth_store fixture that resets the
  store at BOTH edges of every test and cancels AND awaits every task the
  store owns (poll tasks + callback-server stop task), so nothing crosses
  a test boundary (same treatment as the live-usage ingestor fence from
  issue Soju06#1755). The per-test reset() calls are replaced by the fixture.

- test_oauth_start_falls_back_to_device_on_os_error never patched
  exchange_device_token, so its leaked poller performed a REAL network
  token exchange and then slot/status DB writes against a later test's
  freshly reset database. Park the exchange on an Event; the fence
  cancels it at teardown.

- The multi-flow device tests polled /api/oauth/status without flowId,
  which reads the store's "latest flow" pointer; a finishing neighbor
  poller's cleanup re-latches that pointer to its own already-successful
  flow, so the poll reported success before the current flow's poller
  persisted (observed as planType 'plus' != 'team' even in isolation).
  Pin the status polls to each flow's own flowId.

Evidence (unmodified main): the pair
  test_oauth_start_falls_back_to_device_on_os_error +
  test_device_oauth_reauth_reuses_existing_row_for_same_chatgpt_identity
fails ~10-20% of runs, and the reauth test alone failed 4/20 runs on the
latest-pointer race. With the fix: pair 0/20, alone 0/20, full file 5x
green, 3 shuffled whole-file orderings green, tests/unit green.

Fixes Soju06#1794

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…or eventless failures (Soju06#1841)

* fix(http-bridge): classify recovery error frames and poison same-anchor eventless failures

The HTTP responses session bridge could wedge a session permanently
(issue Soju06#1830): after one genuine mid-turn interruption the bridge
rebinds to its stored durable anchor and re-injects it on every
attempt, and when upstream rejects that anchor the failure loops
forever behind the retry circuit ("cooling down" 503).

Two gaps combined into the wedge:

- The bridge-local previous-response recovery gate read raw error
  codes without the normalization the WebSocket path gained in Soju06#1818,
  so a frame carrying its classifiable code only in `type` (or the
  terse parameterless "Invalid `previous_response_id`." shape) fell
  through to the ambiguous-transport class instead of recovery.
- Anchor poisoning only counted `stream_idle_timeout`, and only on
  the reader path when admission waiters exist. The observed wedge
  fails eventlessly with `stream_incomplete` (the bridge's masked
  form of an upstream previous-response rejection), so
  `http_responses_session_bridge_anchor_poison_failure_threshold`
  never fired and operators had to wipe the http_bridge_* tables.

Fix: normalize the error code (falling back to `type`) in the
recovery gate before classification; count both ambiguous eventless
transport classes toward anchor poison (clean_close still never
poisons); and evaluate the poison threshold at the shared retirement
boundary too, clearing the poisoned durable anchor while the session
still owns its durable lease so waiterless wedges self-heal.

Consecutive eventless failures on one bridge key are same-anchor
failures: the durable anchor only advances on a completed response,
which resets the circuit.

Fixes Soju06#1830

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(http-bridge): emit poison-clear failure telemetry on the waiterless path

A failed durable-anchor clear at the shared retirement boundary was only
an unstructured warning, absent from the durable_anchor_poison_clear_failed
telemetry the admission-waiter path emits. Emit the same event (gated on
the session actually holding durable continuity) so failed waiterless
clears stay observable while the next threshold failure re-attempts them.

Addresses CodeRabbit review on Soju06#1841.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…dog (Soju06#1842)

* fix(proxy): O(1) shared-future admission waits + event-loop lag watchdog

Replace wait_for(shield(shared)) on many-waiter shared futures (http-bridge
inflight/capacity registries, token-refresh singleflight) with a fan-out
helper that keeps exactly one callback on the shared future and gives each
waiter a private O(1)-detach proxy. Python 3.14's shield attaches three
callbacks per waiter, leaks one on waiter cancellation, and pays O(n)
remove_done_callback scans — mass timeouts and disconnect storms degraded to
O(n^2) and livelocked the event loop in the 2026-08-20 production incident
(98% of GIL samples inside remove_done_callback with zero client sessions).

Add an event-loop lag watchdog (1s sleep-drift sampler) exporting
codex_lb_event_loop_lag_seconds / codex_lb_event_loop_lag_warnings_total with
a rate-limited warning log, so loop starvation is an explicit operator signal
instead of mysterious global slowness. Configurable via
event_loop_lag_warn_threshold_seconds (default 0.5s, 0 disables).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore(settings): regenerate settings reference and bump field ratchet to 131

event_loop_lag_warn_threshold_seconds justification lives in the PR body and
openspec/changes/harden-shared-future-admission-waits (zero-config default,
0 disables; threshold scales with host CPU class so a constant does not fit).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(openspec): scope timeout invariant to the wait mechanism; link settings page to proxy-runtime-observability

Addresses CodeRabbit review threads on Soju06#1842.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…t signal (Soju06#1835)

Telemetry went silent when an operator disabled it, so the collector could not
tell an explicit rejection apart from an instance that simply stopped running.

- Snapshots now carry the effective consent state (`undecided` | `enabled`).
- One signed opt-out notification is sent per dashboard-driven active-to-inactive
  transition, then the instance goes silent as before.
- The `CODEX_LB_TELEMETRY_ENABLED` kill-switch path stays absolutely silent:
  effective consent never transitions there, so the notification is unreachable.
- Opt-out transmission reuses the snapshot sender's failure isolation (5s bounded
  timeout, one retry, DEBUG-only logs) and runs as a background task, so the
  settings API response is never blocked or failed by it.
- The sender re-checks consent and identity immediately before the snapshot POST.

Known gaps are tracked in Soju06#1844: the residual TOCTOU between that re-check and the
network write, the settings preview under the env kill switch, `occurred_at`
typing, and opt-out observability.

Spec: openspec/changes/add-telemetry-optout-signal/
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat(frontend): add model-source reasoning effort controls

* ci: rerun cancelled frontend checks

* Preserve case when normalizing model-source reasoning efforts

* style(frontend): remove trailing test whitespace
* fix(compact): absorb active recovery replay semantics

* fix(proxy): reject mixed post-compact tool suffix replays
* fix(db): repair retired identity/warmup stamp

* fix(db): repair partial file-account-pin migration
A reattach that proved silent/wedged quarantines its session key, but the
quarantine gate only cleared two booleans. `bridge_session_key` was still
re-adopted from `durable_lookup.canonical_kind/canonical_key`, and the
session was still created under that same poisoned key, so for the whole
600s `_HTTP_BRIDGE_QUARANTINE_TTL_SECONDS` window every request rebuilt a
fresh wedged bridge on the key that was already known to be dead.

Demote the key instead of only dropping the anchor. When a quarantined key
carries a sealed durable full-resend proof that matches the payload, the
request dispatches on a soft account-neutral replay key with the client's
own full conversation, and the original key's continuity is advanced only
after that recovery actually completes.

- `quarantine.py`: entries carry a `generation`, and clearing takes a key
  plus an expected generation, so a late recovery cannot clear a quarantine
  that was re-armed underneath it.
- `upstream_events.py`: on a completed response, rebind and renew the
  original durable row before clearing its quarantine, so continuity is not
  stranded on the throwaway recovery key.
- `streaming.py`: the quarantine gate demotes the key; the recovery key is
  named after the body this dispatch actually sends.

`durable_recovery_attempt_fingerprint` deliberately keeps hashing the
unprojected body. It is the key of persisted `http_bridge_recovery_attempts`
rows, so hashing the projected body instead would mint a different
fingerprint, a row journalled before a restart would stop matching, and the
one-shot replay fence would silently open once. Covered by
`test_quarantined_full_resend_recovery_fence_survives_restart_fingerprint`.
An HTTP bridge model transition could return `continuity_owner_conflict`
indefinitely when a durable model owner and a stale hard alias pointed at
different accounts, even though the request was safe to start on a fresh child
bridge.

Add a narrowly gated account-neutral model-transition fork, limited to the exact
`continuity_owner_conflict` error, local requests and an account-neutral
effective Responses payload. Forwarded requests, previous-response
continuations, resolved file owners, account-scoped hosted references, and
post-compaction payloads whose compacted context is not carried in the request
remain fail-closed.

The forked child key is pinned `hard`, and the child request state drops the
parent affinity policy, hard continuity anchor and reused parent turn state so
the submit and clean-close paths do not classify it as the parent's owner-bound
turn.
…Soju06#1897)

Production re-starved its event loop after ~91h on 1.24.0-beta.3 (py-spy: GIL dominated by asyncio shield callback cleanup) because the usage-refresh singleflight still awaited shared tasks via asyncio.shield — the one many-waiter site Soju06#1842 did not convert.

Route both _UsageRefreshSingleflight wait paths through wait_on_shared_future so waiter attach/cancel/timeout is O(1) on the shared task, preserving result/cancellation/exception and join_existing=False sequencing semantics. Add regression coverage for concurrent joins, cancellation isolation, bounded callback fan-out (sabotage-proven: shield yields 201 callbacks for 100 waiters vs bounded 2), and successor sequencing. OpenSpec: fix-usage-refresh-shared-future-waiters extends the proxy-admission-control shared-future contract to usage-refresh waiters.

Fixes Soju06#1896
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…#1915)

Bumps the python-minor-patch group with 7 updates: pygments 2.21.0, python-dotenv 1.2.3, uvicorn 0.52.4, ruff 0.16.4, ty 0.0.73, openai 3.3.1, hypothesis 6.165.10.

Includes source-contract fixes for ty 0.0.73 (new implicit-return diagnostics on shielded cancellation-deferral helpers, plus restored isinstance narrowing for the service_tier lookup).

Verified: ty 0.0.73/0.0.72 both clean, ruff check/format clean, targeted pytest (unit + proxy integration + SDK e2e) 6486 passed, CI green at 5599da0, current-head Codex review clean.
## [1.24.0](Soju06/codex-lb@v1.23.0...v1.24.0) (2026-08-26)


### Features

* **api-keys:** allow per-key reasoning effort policies ([Soju06#1642](Soju06#1642)) ([ed31b7d](Soju06@ed31b7d))
* **config:** timeout-invariant linter — validate deadline/TTL inequalities at startup and in CI ([Soju06#1622](Soju06#1622)) ([d148dd9](Soju06@d148dd9))
* **db:** report SQLite write transactions that outlive the busy timeout ([Soju06#1752](Soju06#1752)) ([6464e96](Soju06@6464e96))
* **frontend:** configure model-source reasoning efforts ([Soju06#1848](Soju06#1848)) ([eab7155](Soju06@eab7155))
* **model-sources:** advertise operator-declared reasoning efforts ([Soju06#1661](Soju06#1661)) ([f1c8d5c](Soju06@f1c8d5c))
* **model-sources:** embeddings source capability ([Soju06#1776](Soju06#1776)) ([4d0f0ff](Soju06@4d0f0ff))
* **proxy:** report websocket cleanup phase ([Soju06#1726](Soju06#1726)) ([0c8d921](Soju06@0c8d921))
* **proxy:** support Ultrafast service tier ([Soju06#1734](Soju06#1734)) ([d522a4d](Soju06@d522a4d))
* **reports:** Add API Key Filtering to Reports Dashboard ([Soju06#1728](Soju06#1728)) ([1f65f80](Soju06@1f65f80))
* **reset-credits:** add refresh scheduler enable toggle ([Soju06#1701](Soju06#1701)) ([6509dd0](Soju06@6509dd0))
* **telemetry:** anonymous usage telemetry with informed opt-out consent ([Soju06#1618](Soju06#1618)) ([debd7cf](Soju06@debd7cf))
* **telemetry:** report consent state and send a decision-time opt-out signal ([Soju06#1835](Soju06#1835)) ([1541ee8](Soju06@1541ee8))
* **ui:** customize dashboard request-log columns ([Soju06#1503](Soju06#1503)) ([138aa9f](Soju06@138aa9f))
* **ui:** surface reasoning token usage ([Soju06#1801](Soju06#1801)) ([8e7589e](Soju06@8e7589e))


### Bug Fixes

* **accounts:** recover Free accounts after reset ([Soju06#1700](Soju06#1700)) ([b43d0c8](Soju06@b43d0c8))
* **auth:** guard the refresh singleflight negative cache by successor ownership ([Soju06#1652](Soju06#1652)) ([4ace71e](Soju06@4ace71e))
* **cache:** keep an aborted invalidation bump queued ([Soju06#1748](Soju06#1748)) ([7148810](Soju06@7148810))
* **chat:** omit unset tools on mapped Responses payloads ([Soju06#1725](Soju06#1725)) ([db5776c](Soju06@db5776c))
* **compact:** omit oversized non-state tool tail ([Soju06#1235](Soju06#1235)) ([edb3734](Soju06@edb3734))
* **compact:** recover previous-response-pinned compaction from quota-excluded owners ([Soju06#1780](Soju06#1780)) ([120af75](Soju06@120af75))
* **dashboard:** distinguish first-run empty states from filter mismatch ([Soju06#1729](Soju06#1729)) ([e439043](Soju06@e439043))
* **dashboard:** exclude cancelled/client_disconnected from error rate ([Soju06#1696](Soju06#1696)) ([8a7d956](Soju06@8a7d956))
* **dashboard:** pin web asset MIME types against poisoned OS registries ([Soju06#1709](Soju06#1709)) ([2164b8c](Soju06@2164b8c)), closes [Soju06#1698](Soju06#1698)
* **dashboard:** preserve cancelled request count ([Soju06#1766](Soju06#1766)) ([ef9c68e](Soju06@ef9c68e))
* **dashboard:** separate quota and purchased credits ([Soju06#1670](Soju06#1670)) ([4a08d96](Soju06@4a08d96))
* **dashboard:** show cancellation totals in reports ([Soju06#1772](Soju06#1772)) ([5d27f7f](Soju06@5d27f7f))
* **dashboard:** show cancelled request logs ([Soju06#1769](Soju06#1769)) ([5f2f726](Soju06@5f2f726))
* **dashboard:** surface upstream route metadata ([Soju06#1767](Soju06#1767)) ([e359d49](Soju06@e359d49))
* **db:** add postgres shm_size and raise default pool headroom ([Soju06#1791](Soju06#1791)) ([539cf93](Soju06@539cf93))
* **db:** bound wedged SQLite session teardown and reclaim the connection ([Soju06#1778](Soju06#1778)) ([9eedb2c](Soju06@9eedb2c))
* **db:** repair retired identity/warmup migration stamp ([Soju06#1847](Soju06#1847)) ([b6c217f](Soju06@b6c217f))
* **docker:** upgrade util-linux family in runtime image for CVE-2026-53615 ([Soju06#1796](Soju06#1796)) ([0a4c0a1](Soju06@0a4c0a1))
* **helm:** bind TTFT dashboard SQL datasource ([Soju06#1827](Soju06#1827)) ([8abd507](Soju06@8abd507))
* **http-bridge:** classify recovery error frames and poison same-anchor eventless failures ([Soju06#1841](Soju06#1841)) ([01f089c](Soju06@01f089c))
* **http-bridge:** dedupe retry circuit failures per send ([Soju06#1743](Soju06#1743)) ([5780a27](Soju06@5780a27))
* **http-bridge:** keep idle retirements out of retry circuit ([Soju06#1677](Soju06#1677)) ([7c46719](Soju06@7c46719))
* **http-bridge:** preserve goal-restart recovery across reconnects ([Soju06#1680](Soju06#1680)) ([5dc6081](Soju06@5dc6081))
* **http-bridge:** refuse foreign claims on live DRAINING leases ([Soju06#1722](Soju06#1722)) ([b50cb86](Soju06@b50cb86))
* **models:** apply context-window overrides to /v1 input context fields ([Soju06#1808](Soju06#1808)) ([c750dcf](Soju06@c750dcf))
* **models:** correct GPT-5.6 context windows ([Soju06#1691](Soju06#1691)) ([8488bc4](Soju06@8488bc4))
* **models:** raise GPT-5.6 bootstrap max_context_window to 872k ([Soju06#1813](Soju06#1813)) ([1add104](Soju06@1add104))
* **proxy:** abandon unavailable owner on thread-scoped goal restart ([Soju06#1764](Soju06#1764)) ([17ae866](Soju06@17ae866))
* **proxy:** absorb replay-safe compaction recovery ([Soju06#1849](Soju06#1849)) ([c597226](Soju06@c597226))
* **proxy:** add explicit Daybreak capability routing ([Soju06#1742](Soju06#1742)) ([0031e3d](Soju06@0031e3d))
* **proxy:** bind account-bound retries to dispatch owner ([Soju06#1829](Soju06#1829)) ([3381938](Soju06@3381938))
* **proxy:** classify parameterless previous response errors ([Soju06#1818](Soju06#1818)) ([eeab46a](Soju06@eeab46a))
* **proxy:** close non-stream chat collect and map error status ([Soju06#1712](Soju06#1712)) ([a85f71d](Soju06@a85f71d))
* **proxy:** compact transport switch + trigger canonicalization (supersedes [Soju06#1749](Soju06#1749)) ([Soju06#1809](Soju06#1809)) ([0481ed9](Soju06@0481ed9))
* **proxy:** complete disconnect cleanup — pool leak, charged reservation, mutable terminal reason ([Soju06#1645](Soju06#1645)) ([6cf7e61](Soju06@6cf7e61))
* **proxy:** demote quarantined bridge reattach keys ([Soju06#1730](Soju06#1730)) ([5e1f568](Soju06@5e1f568))
* **proxy:** do not rewrite thread locality for a file-pin owner ([Soju06#1765](Soju06#1765)) ([34ef7b2](Soju06@34ef7b2))
* **proxy:** drop malformed compact item ids ([Soju06#1815](Soju06#1815)) ([812265d](Soju06@812265d))
* **proxy:** durably recover hard HTTP bridge operations ([Soju06#1657](Soju06#1657)) ([7a0b671](Soju06@7a0b671))
* **proxy:** fence successor bridge claims against the retiring predecessor ([Soju06#1751](Soju06#1751)) ([2c0dc5b](Soju06@2c0dc5b))
* **proxy:** guard model-transition owner-conflict fork ([Soju06#1619](Soju06#1619)) ([52092bc](Soju06@52092bc))
* **proxy:** hold fenced hard turns through cooldown ([Soju06#1739](Soju06#1739)) ([6ff51cd](Soju06@6ff51cd))
* **proxy:** keep abrupt eventless websocket drops account-neutral ([Soju06#1777](Soju06#1777)) ([6c97ad6](Soju06@6c97ad6))
* **proxy:** keep file-pin owner on soft 1011 reconnect ([Soju06#1761](Soju06#1761)) ([f694c44](Soju06@f694c44))
* **proxy:** keep stream idle timeouts account-neutral ([Soju06#1718](Soju06#1718)) ([64da340](Soju06@64da340))
* **proxy:** normalize single-account warmup failures ([Soju06#1774](Soju06#1774)) ([f92bc90](Soju06@f92bc90))
* **proxy:** O(1) shared-future admission waits + event-loop lag watchdog ([Soju06#1842](Soju06#1842)) ([ed2c94d](Soju06@ed2c94d))
* **proxy:** persist file ownership across replicas ([Soju06#1521](Soju06#1521)) ([2cd52e4](Soju06@2cd52e4))
* **proxy:** preserve compact terminal error type ([Soju06#1824](Soju06#1824)) ([78d63e5](Soju06@78d63e5))
* **proxy:** reject truncated chat completion streams ([Soju06#1833](Soju06#1833)) ([6ba083d](Soju06@6ba083d))
* **proxy:** release the API-key reservation on all exits of the models endpoints ([Soju06#1653](Soju06#1653)) ([7007885](Soju06@7007885))
* **proxy:** report suppressed duplicate tool-call terminals ([Soju06#1706](Soju06#1706)) ([25d6374](Soju06@25d6374))
* **proxy:** retain image reservation recovery ownership ([Soju06#1822](Soju06#1822)) ([bd67c64](Soju06@bd67c64))
* **proxy:** route source-owned models off the WebSocket transport ([Soju06#1659](Soju06#1659)) ([08b84a9](Soju06@08b84a9))
* **proxy:** scope backend Codex affinity by thread identity ([Soju06#1703](Soju06#1703)) ([35bbb00](Soju06@35bbb00))
* **proxy:** separate websocket scope cleanup budget ([Soju06#1723](Soju06#1723)) ([fd97cb8](Soju06@fd97cb8))
* **proxy:** settle compact failover before account health ([Soju06#1717](Soju06#1717)) ([3093203](Soju06@3093203))
* **proxy:** settle terminal spool append failures ([Soju06#1775](Soju06#1775)) ([4e48f35](Soju06@4e48f35))
* **proxy:** stop abandoning an unresolved inflight session-creation future ([Soju06#1644](Soju06#1644)) ([57618c8](Soju06@57618c8))
* **proxy:** sweep idle bridge sessions without request traffic ([Soju06#1747](Soju06#1747)) ([3159ebe](Soju06@3159ebe))
* **proxy:** wait on usage-refresh singleflight without asyncio.shield ([Soju06#1897](Soju06#1897)) ([798203f](Soju06@798203f)), closes [Soju06#1896](Soju06#1896)
* **quota-planner:** compare warmup reset epochs in UTC ([Soju06#1623](Soju06#1623)) ([e4fa3f2](Soju06@e4fa3f2))
* **reports:** format full Cost values with grouping separators ([Soju06#1814](Soju06#1814)) ([028a75c](Soju06@028a75c))
* **review:** keep Codex review sessions resumable ([Soju06#1678](Soju06#1678)) ([e34db2d](Soju06@e34db2d))
* **server:** serve h2c upgrade offers as plain HTTP/1.1 instead of rejecting them ([Soju06#1782](Soju06#1782)) ([8d265c3](Soju06@8d265c3))
* **usage:** fence leaked live-usage-ingestor tasks and settle their failures deterministically ([Soju06#1783](Soju06#1783)) ([66fd103](Soju06@66fd103))
* **usage:** settle live snapshots after account consolidation ([Soju06#1773](Soju06#1773)) ([3f66c28](Soju06@3f66c28))
* **warmup:** warm paid-to-free transitions ([Soju06#1825](Soju06#1825)) ([68892e7](Soju06@68892e7))


### Performance Improvements

* **accounts:** bound the account-listing live tail with a 2h fold lag and a 30s summary cache ([Soju06#1792](Soju06#1792)) ([c1caa44](Soju06@c1caa44))
* **accounts:** make account deletion a fast mark + background batch drain ([Soju06#1795](Soju06#1795)) ([d4f9e23](Soju06@d4f9e23))
* **api-keys,proxy:** shape ORM hot-path queries ([Soju06#1788](Soju06#1788)) ([7dacb04](Soju06@7dacb04))
* **api-keys:** skip usage reservations when no limit applies ([Soju06#1789](Soju06#1789)) ([8a2d066](Soju06@8a2d066))
* coalesce same-owner sticky session TTL refresh upserts ([Soju06#1790](Soju06#1790)) ([076aab8](Soju06@076aab8))
* **dashboard:** cap projections bulk usage-history read per account ([Soju06#1779](Soju06#1779)) ([d4c43ef](Soju06@d4c43ef))
* **middleware:** convert BaseHTTPMiddleware layers to pure ASGI ([Soju06#1787](Soju06#1787)) ([94057cc](Soju06@94057cc))
* **proxy:** disable permessage-deflate on direct-egress upstream websockets ([Soju06#1786](Soju06#1786)) ([2e4a580](Soju06@2e4a580))
* **proxy:** relay unmodified SSE frames verbatim ([Soju06#1785](Soju06#1785)) ([980572e](Soju06@980572e))
* **proxy:** validate stream payloads only for lifecycle events ([Soju06#1784](Soju06#1784)) ([9d9f099](Soju06@9d9f099))


### Documentation

* **dashboard:** clarify routing, sticky affinity, quota thresholds, warm-up, and eligibility copy ([Soju06#1781](Soju06#1781)) ([6ff22e0](Soju06@6ff22e0))
* **openspec:** archive 90 landed changes and sync their specs ([Soju06#1713](Soju06#1713)) ([c3f0c56](Soju06@c3f0c56))
* **openspec:** archive landed performance and reliability changes ([Soju06#1694](Soju06#1694)) ([6b3db74](Soju06@6b3db74))
* **proxy:** document cluster-wide account cap partitioning ([Soju06#1750](Soju06#1750)) ([560fb50](Soju06@560fb50))

---
This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
…vior

Bring the stable upstream bridge, model sources, account coordination, usage rollups and dashboard into agent-lb. Reconcile both database histories and preserve Claude routing, credential custody, billing guards, attribution and spend limits.

check: .venv/bin/python -m pytest tests/e2e -q
check: .venv/bin/ruff check app scripts/run_dashboard_browser_smoke.py
check: .venv/bin/python scripts/check_proxy_architecture.py

Seat: gpt-implementer (openai)
Verify-override: Draft integration only. Cross-vendor custody/spend-cap verifier infrastructure is unavailable on this host; required review and exact-SHA coordinator CI remain open before readiness or merge. See openspec/changes/sync-codex-lb-v1-24-0/verification.md.
Keep the slow-redemption regression valid for both database dialects and always drain its request task, including after a failed assertion. Record final candidate checks and the refreshed maintainer baseline.

check: .venv/bin/python -m pytest tests/floor/test_reset_credits_replica_safety.py -q

Seat: gpt-implementer (openai)
Patch the slot repository used by token rotation and assert both competing moves reach the lock. Record final PostgreSQL verification and preserve the remaining draft gates.

check: .venv/bin/python -m pytest tests/floor/test_live_usage_ingest.py -q

Seat: gpt-implementer (openai)
@nikhilshinday

Copy link
Copy Markdown
Author

Updated the draft to b719cc83229ff66c4ca9f318adaca3c5407bfc5c (previous published tip: f39e646ddfb8edc0fe67eb7b2b52a0a2df8f128f). This update repairs the PostgreSQL identity-swap regression's monkeypatch target after repository extraction, asserts both competing moves reach the real locking seam, and records final database evidence. It changes tests and integration evidence only.

The latest stable upstream release was rechecked as v1.24.0, pinned at 84fde5a1ed5e0d5a58ccb3ec4b82938b059bf8c5. The PR includes maintainer main cac869035fd36c31247086ce7fac890afb3586d2.

Local verification results for the integration candidate (these are individual suite results, with overlapping coverage, rather than a complete exact-SHA CI receipt):

Selection Result
Consolidated floor run, excluding the eight test_hook_dispatcher* files and two original-fork policy failures 1,817 passed, 19 skipped, 3 xfailed
Frontend bun run test 1,152 passed across 147 files
Frontend frozen install, bun run typecheck, bun run build Passed
tests/e2e 27 passed, 1 skipped (installed-Codex profile requires explicit opt-in)
Built dashboard against a real isolated FastAPI instance Passed browser smoke
PostgreSQL deletion, refresh claims, rollup parity/time rollups, reset-credit replica safety, provider summary 126 passed
PostgreSQL durability, UTC sessions, live usage/identity membership, migration serialization 39 passed
Latest SQLite tests/floor/test_live_usage_ingest.py 11 passed, 4 PostgreSQL-only skips
SQLite reset-credit replica safety 16 passed
Empty and existing-fork upgrades on SQLite and PostgreSQL Single migration head; migration policy passed; no schema drift; synthetic fork fixtures preserved
Pinned-release bridge cases adapted to the fork layout All 640 cases passed across suite and harness retry
Capability routes / forwarded-identity regressions 152 / 4 passed
Ruff application checks, compile, architecture ratchets, strict OpenSpec change validation Passed
Wheel and sdist, isolated wheel install, CLI/migration help, packaged static asset comparison Passed as 1.24.0

The two PostgreSQL commands below used AGENT_LB_TEST_DATABASE_URL pointing only to the task-owned disposable Postgres database, with no operator data or credentials:

.venv/bin/python -m pytest tests/floor/test_account_deletion_background.py tests/floor/test_token_refresh_claims.py tests/floor/test_request_usage_rollup_parity.py tests/floor/test_request_usage_time_rollup.py tests/floor/test_reset_credits_replica_safety.py tests/floor/test_usage_provider_summary.py -v --tb=short --timeout=60
.venv/bin/python -m pytest tests/floor/test_db_commit_durability.py tests/floor/test_db_session_timezone.py tests/floor/test_live_usage_ingest.py tests/floor/test_migration_serialization.py -v --tb=short --timeout=60
.venv/bin/python -m pytest tests/floor/test_live_usage_ingest.py -q --tb=short --timeout=60
bunx @fission-ai/openspec validate sync-codex-lb-v1-24-0 --strict

The third pytest command above used SQLite. Both PostgreSQL identity swaps now complete within the concurrency bound, preserve their distinct rows, and demonstrably enter the shared lock helper.

The draft still has these readiness gates:

  • No complete exact-SHA local CI receipt: scripts/local_ci.py status b719cc83229ff66c4ca9f318adaca3c5407bfc5c reports no local receipt. factory-lint and trivy are unavailable, and inherited frontend ESLint configuration is absent. Hosted CI currently reports only the successful PR labeler; it has not validated the integration.
  • Eight hook-dispatcher files were omitted after an earlier installer/parity attempt spawned excessive child processes. They require an isolated equipped runner.
  • The original fork's two policy failures were reproduced at 21582308. The maintainer main update fixes the installer import failure. test_policy_core.py::test_core_keeps_every_obligation still expects missing rails merge path text; the post-merge policy/route batch has 35 passed, 1 failed.
  • Required cross-vendor credential-custody/spend-cap review is unavailable on this host (seat-run, the verifier role and its launcher are absent). The integration records an explicit draft-publication verification override; no reviewer PASS is claimed.
  • size-overages.tsv records 98 source-file overages, including 61 application and 22 frontend files, with both parent sizes. Size-cap compliance needs review.
  • Real disposable-provider acceptance journeys remain unavailable. Synthetic HTTP/SQL coverage and browser smoke do not establish real subscription compatibility.

Durable evidence and remaining tasks are in openspec/changes/sync-codex-lb-v1-24-0/verification.md and tasks.md. No serving service was restarted or deployed. The task-owned PostgreSQL container was removed after testing, and no owned test or smoke processes remain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.