Skip to content

fix(proxy): prioritize TTFB when stream gate is not enforced - #1467

Merged
ding113 merged 1 commit into
devfrom
fix/gateway-streaming-first-char-delay
Sep 3, 2026
Merged

fix(proxy): prioritize TTFB when stream gate is not enforced#1467
ding113 merged 1 commit into
devfrom
fix/gateway-streaming-first-char-delay

Conversation

@ding113

@ding113 ding113 commented Sep 3, 2026

Copy link
Copy Markdown
Owner

Summary

Users could still see delayed first-byte delivery after disabling the streaming output gate, selecting shadow mode, or enabling high-concurrency mode. The delay came from precommit content gating in multiple forwarder paths, including forced headerless Codex Responses handling and Discovery validity parsing.

This change makes precommit buffering active only for STREAM_GATE_MODE=enforce when high-concurrency mode is disabled. Off, shadow, replay-owner, high-concurrency, and headerless Codex streams now hand the first upstream byte to the client immediately. Discovery remains enabled, but uses first-byte readiness when precommit gating is inactive. Enforce mode keeps the existing error/malformed/empty-stream failover behavior.

Problem

forceCodexResponsesStream and replay-owner state independently enabled runStreamContentGate, so off and shadow were not actually TTFB-first. Discovery ran before the legacy serial/hedge paths and always waited for DiscoveryValidityParser to observe valid content, bypassing the configured gate policy.

Related Issues / PRs:

Solution

Precommit gate activation is centralized in a single predicate, isStreamGatePrecommitActive(highConcurrencyMode): active only when STREAM_GATE_MODE=enforce and high-concurrency mode is disabled. The serial SSE, legacy hedge, and Discovery paths in the forwarder all consult this predicate instead of independently enabling the gate via replay-owner or headerless-Codex conditions.

For off/shadow modes, bad streams are no longer traded for zero-byte failover: the response-handler's StreamProtocolObserver aborts the stream after the fact and the replay entry is not published.

Changes

Core Changes

  • src/app/v1/_lib/proxy/stream-gate/stream-content-gate.ts: new isStreamGatePrecommitActive() helper
  • src/app/v1/_lib/proxy/forwarder.ts:
    • Serial SSE path: precommit gate runs only for enforce and non-high-concurrency
    • Legacy hedge path: same predicate governs winner selection
    • Discovery path: DiscoveryValidityParser.push() only runs when precommit is active; otherwise the first upstream byte marks the attempt ready (validity checks become null-safe)

Supporting Changes

  • streamGateModeDesc settings text updated in all 5 locales (en/ja/ru/zh-CN/zh-TW)
  • OpenAPI schema description (system-config.ts) plus regenerated openapi-types.gen.ts; enum values unchanged
  • Tests: stream-gate-mode-resolution.test.ts adds the predicate truth table (+18); stream-gate-forwarder-integration.test.ts (+505/-119) moves enforce-mode interception coverage up and adds off/shadow first-byte passthrough, high-concurrency TTFB, and replay-owner TTFB cases; proxy-hedge-lifecycle.test.ts (+6/-2) pins the Discovery test to enforce mode and dispatches downstream before content completes

Behavioral Changes (no API or migration impact)

Scenario Before After
off/shadow + replay owner Precommit gate always ran; bad first frame caused zero-byte failover First byte delivered immediately; bad stream aborted post-hoc, replay entry not published
off/shadow + headerless Codex Responses Bounded precommit sniff; JSON fake-200 triggered failover Transparent passthrough, no precommit sniffing
enforce + high-concurrency mode Precommit gate ran Treated as off: TTFB-first
enforce (default), no high-concurrency Gate plus failover on error/malformed/empty stream Unchanged

Validation

  • Focused stream-gate, mode-resolution, routing-trace suites: 48 passed.
  • Real loopback Discovery/hedge lifecycle suite: 23 passed.
  • Full Vitest suite: 881 test files passed, 2 skipped; 8,815 tests passed, 13 skipped.
  • bun run typecheck: passed.
  • bun run lint and bun run lint:fix: passed; existing Biome schema-version info only.
  • bun run build: passed; existing Edge-runtime warnings only.
  • bun run openapi:check: passed.
  • bun run openapi:lint: passed.
  • bun run i18n:audit-messages-no-emoji:fail: passed.
  • git diff --check: passed.

Notes

The existing settings placeholder audit reports unrelated same-as-zh-CN translation entries in other locale files; the changed messages pass the no-emoji audit.


Description enhanced by Claude AI

Make off, shadow, and high-concurrency routing paths TTFB-first across
serial forwarder, legacy hedge, and Discovery attempts. Previously,
replay owners, forced Codex response handling, and Discovery validity
parsing buffered upstream chunks until the first valid content frame
even when stream gating was disabled or running in shadow mode, delaying
initial byte delivery to downstream clients.

Introduce isStreamGatePrecommitActive so precommit buffering only
engages when streamGateMode is enforce and high-concurrency mode is
disabled. Replay owners and headerless responses now stream the first
upstream byte immediately in non-enforce modes, leaving malformed
stream aborts to downstream response observers.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-03T17:25:44.905508Z d74c848 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 1392fff8-98d2-4cef-998e-c30d67c016ba

📥 Commits

Reviewing files that changed from the base of the PR and between dfeb143 and d74c848.

📒 Files selected for processing (12)
  • messages/en/settings/config.json
  • messages/ja/settings/config.json
  • messages/ru/settings/config.json
  • messages/zh-CN/settings/config.json
  • messages/zh-TW/settings/config.json
  • src/app/v1/_lib/proxy/forwarder.ts
  • src/app/v1/_lib/proxy/stream-gate/stream-content-gate.ts
  • src/lib/api-client/v1/openapi-types.gen.ts
  • src/lib/api/v1/schemas/system-config.ts
  • tests/integration/proxy-hedge-lifecycle.test.ts
  • tests/unit/proxy/stream-gate-forwarder-integration.test.ts
  • tests/unit/proxy/stream-gate-mode-resolution.test.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

本次更新统一流内容预提交门控判定:仅在 enforce 且非高并发模式下启用。串行、Legacy Hedge 和 Discovery 路径现在支持按模式立即转发首字节,并同步更新测试及配置说明。

Changes

流内容门控行为

Layer / File(s) Summary
门控启用契约
src/app/v1/_lib/proxy/stream-gate/stream-content-gate.ts, src/lib/api/v1/schemas/system-config.ts, src/lib/api-client/v1/openapi-types.gen.ts, messages/*/settings/config.json
新增 isStreamGatePrecommitActive。仅当模式为 enforce 且未启用高并发时返回 true。API、Schema 和多语言说明同步更新。
转发路径门控处理
src/app/v1/_lib/proxy/forwarder.ts
串行、Legacy Hedge 和 Discovery 路径使用统一判定。门控未启用时跳过有效性解析,并在首个非空字节时标记请求 ready。
门控行为验证
tests/unit/proxy/stream-gate-forwarder-integration.test.ts, tests/unit/proxy/stream-gate-mode-resolution.test.ts, tests/integration/proxy-hedge-lifecycle.test.ts
测试覆盖 enforceoffshadow、Replay owner、Legacy Hedge、Discovery 和高并发路径。测试验证首字节转发、failover、流完整性和 TTFT 时序。

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to d74c8

The streaming paths consistently apply immediate first-byte forwarding outside enforce mode while retaining enforce-mode gating behavior. No merge-blocking risk is established.

Suggested reviewers: brisbanehuang, tesgth032

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed 标题准确概括了主要变更:在未启用强制流门控时优先交付首字节并改善 TTFB。
Description check ✅ Passed 描述与变更内容一致。它说明了 precommit buffering 的启用条件、Discovery 路径调整、各模式下的首字节行为,以及验证结果。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 6 files. (6 skipped: 5 …
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 6 files. (6 skipped: 5 unsupported, 1 too large.)

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/gateway-streaming-first-char-delay

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added bug Something isn't working area:core labels Sep 3, 2026
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🧪 测试结果

测试类型 状态
代码质量
单元测试
集成测试
API 测试

总体结果: ✅ 所有测试通过

@github-actions github-actions Bot added the size/L Large PR (< 1000 lines) label Sep 3, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

No significant issues identified in this PR. The change centralizes precommit-gate activation into a single predicate (isStreamGatePrecommitActive) and consistently applies it across the serial SSE, legacy hedge, and Discovery paths in the forwarder. Full-context verification confirmed the documented safety net: for off/shadow/high-concurrency modes, the response-handler's protocol observation aborts the replay spool on post-commit bad frames (response-handler.ts observeChunk -> replaySpool.abort), TTFB/TTFT metrics remain correct via the documented recordTtft fallback, and health attribution stays guarded by the authoritative first-byte observation in the response handler.

PR Size: L

  • Lines changed: 718 (568 additions / 150 deletions)
  • Files changed: 12

Size is dominated by test rework (~538 lines) and i18n/OpenAPI description text (~30 lines); actual production logic is ~40 lines. If splitting were desired, the natural seams would be (1) core predicate + forwarder changes, (2) test suite reorganization, (3) locale/OpenAPI description updates - though given the coupling between behavior and its pinning tests, keeping them together is also defensible.

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 0 0 0
Security 0 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 0 0
Simplification 0 0 0 0

Notable candidates investigated and discarded during validation (for transparency):

  • Discovery loser-billing eligibility shifting to first-byte readiness: symmetric with the winner's first-byte commit and identical to the legacy hedge first-chunk semantics; opt-in via billHedgeLosers. Intentional.
  • 100ms timing windows in new TTFB tests: resolution is microtask-based after the first chunk; pattern matches existing file conventions. Below reporting threshold.
  • Discovery off-mode coverage: exercised by existing integration tests that run under the default off mode (drain/billing lifecycle tests); enforce-mode Discovery pinned explicitly by this PR.

Review Coverage

  • Logic and correctness - Clean (all three forwarder paths verified in full context; null-safety of the validity rewrite confirmed equivalent to prior behavior when the gate is active)
  • Security (OWASP Top 10) - Clean (no new input handling, secrets, or injection surface; transparency policy change is admin-configured and documented)
  • Error handling - Clean (no new catch blocks; intentional non-throwing under inactive gate is compensated by post-hoc protocol observation and replay-entry suppression)
  • Type safety - Clean (no any introduced; DiscoveryValidity | null handled via correct short-circuit optional chaining)
  • Documentation accuracy - Clean (settings text updated consistently in all 5 locales, OpenAPI schema and regenerated types match; code comments match new behavior)
  • Test coverage - Adequate (predicate truth table, enforce interception, off/shadow passthrough, high-concurrency TTFB, replay-owner TTFB across serial and hedge paths)
  • Code clarity - Good (predicate centralization reduces previously scattered conditions)

CLAUDE.md compliance: no emoji in changed strings, i18n used for all user-facing text, PR targets dev.


Automated review by Claude AI

@ding113
ding113 merged commit 0baad07 into dev Sep 3, 2026
17 of 19 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Claude Code Hub Roadmap Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core bug Something isn't working size/L Large PR (< 1000 lines)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant