Skip to content

chore: recover upstream v0.2.6 codex ticket integration - #184

Merged
HTExplicit merged 62 commits into
mainfrom
codex/v0.2.6-integration
Sep 18, 2026
Merged

HTExplicit merged 62 commits into
mainfrom
codex/v0.2.6-integration

Conversation

@HTExplicit

Copy link
Copy Markdown
Owner

Summary

Recover the withdrawn upstream Sub2API v0.2.6 merge commit 49a39b6dc1abed30fd227611e8af1108bc427610 into the codexrip downstream tree.

The merge includes the upstream changes after v0.2.5 plus the Codex x-codex-turn-state ticket implementation. Ticket collection and injection remain disabled by default; the harvest proxy and live switch are available through the admin settings surface for a later, explicit activation.

Integration decisions

  • Preserve downstream Cindy/API-key, continuation, account-job, system-prompt, Remote Skill, Image Studio, traffic telemetry, identity and deployment contracts.
  • Apply ticket gating only to OpenAI OAuth/Setup Token accounts and use the actual outbound model for compact requests.
  • Preserve the existing downstream OAuth runtime-breaker, probe ownership, cooldown and sticky continuation protections.
  • Keep private ticket material out of DTOs, exports and ordinary account edits.
  • Record the withdrawn upstream source in .downstream/upstream-risk.json and .downstream/upstream-review-v0.2.6.md using the exact commit and tree rather than a missing remote tag.

Validation

  • Wire regenerated from the combined provider set.
  • git diff --check and conflict-marker checks passed.
  • Backend full compile (go test -run '^$' ./...) passed.
  • go vet ./... and go mod verify passed.
  • Focused backend ticket, account Extra, DTO, OAuth runtime, continuation, Cindy and handler tests passed.
  • Focused frontend settings/account/dialog/manifest tests passed (182 tests).
  • Frontend production build and focused ESLint passed.

Production deployment, if this PR is merged and released, will use the existing immutable-digest deploy-preserve path. No harvest proxy will be written and no ticket switch will be enabled by this change.

HuntercodeT and others added 30 commits September 15, 2026 16:50
Paused (schedulable=false) active accounts were excluded from the
background token refresh candidates, so their stored access_token
silently expired. The admin usage-window quota probe uses the stored
token verbatim (no token provider / no refresh), so the probe then gets
HTTP 401 UNAUTHENTICATED and the dashboard reports a false "needs
re-auth" for a perfectly healthy account, while Test Connection and live
traffic (which refresh on demand via the token provider) keep working.

Pause is not permanent rejection: error accounts are already excluded by
the status = 'active' filter, and accounts whose refresh genuinely fails
are rate-limited by the retry-cooldown exclusion (10-minute retry-
exhausted cooldown). Refresh success only persists credentials and never
touches schedulable, so a paused account cannot be silently un-paused.

Drop the schedulable filter and update the SQL-filter test, the
integration pagination test, and the service-level candidate fake.
GET /api/v1/admin/groups/usage-summary 在有一定数据量的库上会退化成
usage_logs 全表扫。根因是 getAllGroupUsageSummaryFromRollups 里,tail CTE
的 created_at 下界 state.tail_start 由同一条 SQL 的 state CTE 算出、再用
CROSS JOIN 交给 tail:这个值对 planner 来说要到运行期才知道,既进不了
index cond,也估不准选择性,于是只能顺序扫全表再逐行过滤。

生产实测(1721 万行 usage_logs / PostgreSQL 17):

    Nested Loop  (actual time=28161..48334 rows=34788)
      Join Filter: (ul.created_at >= state_1.tail_start)
      Rows Removed by Join Filter: 17178082
      ->  Seq Scan on usage_logs  (actual time=0.030..47567 rows=17212870)
          Buffers: shared hit=12863 read=951875
    Execution Time: 48720 ms

改成先读一次水位行、在 Go 侧算出 tail_start / closed_before / retained
日期,再把它们当查询参数传进来。同一套数据上:

    Index Scan using idx_usage_logs_created_at on usage_logs
      Index Cond: (created_at >= $7)
    Execution Time: 34 ms

水位有效性的判定(恰好一行、时区名与配置一致、水位不在未来)和无效时
退化成从 epoch 全量重算的行为,与原先 SQL 里 state_values / CASE WHEN
valid 的分支逐条对应,结果口径不变。

另外读取水位的语句不加锁,不参与 Wei-Shaw#6976 那条 FOR UPDATE / FOR KEY SHARE
的阻塞链。
DeepSeek native Responses rejects Codex view_image results when function_call_output.output contains input_image parts. Move media into a following user message and keep the tool output as a string so call_id pairing remains valid.
Security Scan / backend-security 自 2026-09-16 起在所有 PR 上失败,govulncheck 对
google.golang.org/grpc v1.82.1 报:
- GO-2026-6443 Server panic via missing authority or Host headers(修复于 v1.83.2)
- GO-2026-6348 Heap Memory Exhaustion via HTTP/2 DATA Frame Fragmentation(修复于 v1.83.1)
调用链在 pkg/pluginapi/v1/runtime.go 与 internal/service/plugin_runtime.go。

go get google.golang.org/grpc@v1.83.2 && go mod tidy。最小版本选择连带抬升了
golang.org/x/{crypto,mod,net,sync,term,sys,text,tools}、genproto/googleapis/rpc 与
go.opentelemetry.io/otel* 的间接依赖,均为补丁级别。
…ump-number

fix(pagination): handle numeric jump input
…ta-negative

fix(admin): reject negative platform quota limits before saving
Wei-Shaw and others added 28 commits September 17, 2026 16:38
…-ids

fix(ui): keep dialog title IDs unique across instances
…nput-sync

fix(auth): keep TOTP setup digits in sync with state
…llback-error

fix(clipboard): report errors thrown by the copy fallback
…-read-results

fix(announcements): preserve successful bulk read results
…edup

fix(proxies): reuse in-flight test guards during batch testing
…r-page

fix(payment): reset the order page when changing status
…essages

fix(totp): display normalized API error messages
…b-navigation

fix(channels): allow tabbing out of an empty model input
…nt-input

fix(payment): restore accepted text after invalid amount input
…-loading-reset

fix(subscriptions): reset loading when clearing state
…ce-warning

fix(payment): base refund balance warnings on the requested amount
fix(openai): parse Codex models manifest envelope once
…-flicker

fix: prevent promo code field flash on registration
…-accounts

fix(account): keep refreshing OAuth tokens for paused accounts
…nse-binding-context

fix(openai): 客户端断开后仍持久化 Responses 续聊绑定
…chat-role-compat

fix(gateway): normalize developer roles for strict native Chat upstreams
…ion-pagination

feat(redeem): paginate user redemption history
…ttribution-429

fix(antigravity): 过滤 Claude attribution 元数据,修复特定请求的 429
…ive-responses-tool-output-media

fix(deepseek): lift Responses tool output images
…ne hour

ChatGPT OAuth accounts can mint a 292-length x-codex-turn-state via a
dedicated harvest proxy and reuse that header on residential production
requests for ttl_seconds (default 3600). The feature stays off until
gateway.openai_codex_ticket is enabled.
Add the admin harvest-proxy field with masked responses, URL validation, five-second runtime caching and escaped i18n examples. Protect tickets from account edits and concurrent model probes, respect configured status policy, and remove unused burst-harvest code.

Validated focused Go tests and race checks, API contracts, 44 frontend tests, server compilation and the production frontend build.
When the switch is off, the gateway does not harvest or inject
x-codex-turn-state and forwards traffic as usual. When on, it harvests
292 tickets in the background and overwrites the header on production
requests. The setting is live and does not require a restart.
Route synthetic probes directly through the harvest transport and propagate cancellation through settings, account reads, HTTP probes and persistence. Make start/stop idempotent and avoid mutating shared startup config for the live toggle.

Scrub private ticket data from account exports and legacy extras, consistently exempt credential shadows, and display setup-token ticket status. Add lifecycle, concurrency, export, policy and UI regression tests.
The scheduling gate resolved the ticket model with requireCompact forced
to false, while Forward rewrites the outbound model of a
/responses/compact request to the compact mapping or
gateway.openai_compact_model, which is non-empty by default. A compact
request for a gated model therefore blocked every ticketless account
under fail_closed even though the request actually leaves as a non-gated
model and needs no ticket at all.

Predict the outbound model with the same chain Forward uses and thread
the compact flag, which both sides derive from
IsOpenAIResponsesCompactPath, through the runtime block gate. Every other
selection entry point passes false, so their behavior is unchanged.
Ticket extras are not part of filterSchedulerExtra's projection, so the
bucket rebuild event that every ticket refresh enqueued could never carry
ticket state anywhere. Mark the key prefix scheduler-neutral: UpdateExtra
still syncs the single-account snapshot, so nothing loses freshness, but a
refresh no longer opens a transaction or enqueues a rebuild.

lockAndMergeAccountProbeExtra now reads the current extra on every account
update across all platforms. A row whose extra is not a JSON object made
that unmarshal fail the entire edit. Degrade to skipping ticket
preservation instead, which self-heals on the next harvest, while still
stripping administrator-supplied ticket keys.
…n-state-ticket

feat(openai): add one-hour Codex tickets with live harvest proxy settings
@HTExplicit
HTExplicit merged commit 4bb9eab into main Sep 18, 2026
16 checks passed
@HTExplicit
HTExplicit deleted the codex/v0.2.6-integration branch September 18, 2026 14:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.