Skip to content

fix(lab): read per-model overrides in the report the way the runtime reads them - #2077

Closed
ntdatt812 wants to merge 2 commits into
lidge-jun:devfrom
ntdatt812:fix/compat-behavior-model-overrides
Closed

fix(lab): read per-model overrides in the report the way the runtime reads them#2077
ntdatt812 wants to merge 2 commits into
lidge-jun:devfrom
ntdatt812:fix/compat-behavior-model-overrides

Conversation

@ntdatt812

@ntdatt812 ntdatt812 commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

#2059 fixed the list-shaped half of the behavior report. The per-model override maps are the other half, and they had the same shape of bug plus one more.

modelValue was a bare index:

function modelValue<T>(map: Record<string, T> | undefined, modelId: string): T | undefined {
  return map?.[modelId];
}

The runtime reads these maps through modelRecordValue (src/reasoning-effort.ts:73), which checks own properties, then the pre-colon family, then a case-folded key. Nine of the ten maps the report reads go through it at runtime — modelContextWindows, modelMaxInputTokens, modelMaxOutputTokens, modelInputModalities, modelReasoningEfforts, modelDefaultReasoningEfforts, modelReasoningEffortMap, modelSupportsReasoningSummaries, modelReasoningSummaryDelivery. The tenth, modelPreferHostedTools, is read in openai-responses.ts with its own explicit hasOwnProperty guard.

The three disagreements

1. Pre-colon family. ollama-cloud serves gpt-oss:120b. With modelMaxOutputTokens: {"gpt-oss": 1234}:

value
wire the adapter builds max_tokens: 1234
report limits.maxOutputTokens null

2. Case folding. A differently-cased key resolves at runtime and did not in the report.

3. Prototype chain — this one is not just wrong data.

Model ids are operator-controlled, so one can be constructor or toString. The bare index then returned an Object.prototype function:

report limits.contextWindow for 'constructor' = function Object() { [native code] }

jcsStringify rejects a function, so buildBehaviorFingerprintV1 threw unsupported value type function, and resolvePassiveRouteSubjectId swallows the throw — the subject silently never links and Lab loses that traffic with no diagnostic. The linker's contract states an implementation is "synchronous, free of side effects with respect to the request, and non-throwing"; the try/catch is described there as belonging to the mechanism so the guarantee is not restated by callers — a backstop, not a licence. openai-responses.ts:996-1001 already guards modelPreferHostedTools against exactly this, and says why in a comment.

Change

Two lookups, because the ten maps are not one contract.

modelValue delegates to modelRecordValue for the nine family-aware maps, so the report cannot disagree with the runtime on any of them at once.

A new exactOwnValue serves the two that are deliberately exact-own at runtime: modelPreferHostedTools, read through hasOwnProperty at src/adapters/openai-responses.ts:1001 and documented as "Exact-model hosted tools" at src/types.ts:1584, and modelOpenRouterRouting, read through Object.hasOwn at src/providers/openrouter-routing.ts:89.

Family-resolving those two would be this PR's own divergence with the sign flipped — the report claiming an override applies that the adapter will never apply. A bare index is not the alternative either: it walks the prototype chain, which is the defect being fixed. modelOpenRouterRouting at behavior.ts:87 was still a bare read, so it carried that bug untouched by the first commit.

Measured, first 16 hex of the behavior fingerprint, with modelPreferHostedTools: {"gpt-oss": ["image_generation"]} and modelOpenRouterRouting: {"gpt-oss": {order: ["fireworks"]}} present:

gpt-oss:120b fingerprint
both maps sent through modelRecordValue 96a2ad0adbcae1de a different subject, from an override the adapter never applies
both maps through exactOwnValue 5c992edff35bd7e9 unchanged, and equal to the no-hosted-tools config

Blast radius, measured

Same config, before and after, first 16 hex of the behavior fingerprint:

model dev this branch
gpt-oss:120b 54154e19bd2c8ee4 5c992edff35bd7e9 was missing the 1234 override
gpt-oss 5c992edff35bd7e9 180a84b2d837619d was missing the case-folded 55555
glm-5.3 54154e19bd2c8ee4 54154e19bd2c8ee4 unchanged
constructor THROW 54154e19bd2c8ee4 now computable

Re-measured on the rebased head; the exact-own split does not move any of these, because none of those configs carries a hosted-tools or OpenRouter-routing override.

Only subjects whose overrides were being missed move, so resolverVersion stays at 2 for the same reason as #2059 — say the word if you would rather draw a generation boundary.

Tests

Extends tests/routing-compatibility-model-matching.test.ts from #2059, same pattern: assert the wire the adapter really builds, then hold the report to it. Prototype-shaped ids get their own cases, including one asserting the fingerprint stays computable and that two such ids hash alike.

The exact-own group adds five more. Their ground truth is executable rather than cited: resolveOpenRouterRouting is exported, and it returns the entry for the exact key and undefined for the tagged sibling.

Whole file, 21 tests, against current dev: 13 pass / 8 fail. Against this branch's first commit — i.e. with both exact-own maps wrongly family-resolved — the two "report agrees" cases go red instead. Both numbers matter: the first shows the original defect, the second shows the correction to it.

Verification

Rebased onto 7a2d13a74; the branch was 31 commits behind.

bun run typecheck                                          exit 0
bun test tests/routing-compatibility-model-matching.test.ts
                                                           21 pass / 0 fail
  same file with src reverted to dev:                      13 pass / 8 fail
bun test <compatibility, openrouter-routing, fastwire-observability,
          lab-live-review-regressions>                     116 pass / 0 fail

Not the full suite: this is a Windows machine and bun run test panics partway through on Bun 1.3.14 (index out of bounds: index 0, len 0), so a result from it would be a truncated log. The batch ran through scripts/test.ts so each file keeps its isolated home.

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

Summary by CodeRabbit

  • Bug Fixes

    • Improved per-model configuration matching for model names and families, including case-insensitive matches.
    • Prevented inherited or unsupported values from affecting routing, hosted-tool preferences, and compatibility fingerprints.
  • Tests

    • Added coverage for model-family matching, case variations, unrelated models, prototype-shaped model IDs, and fingerprint generation.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added bug Something isn't working review-ready labels Aug 19, 2026
@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

✅ READY

  • all PR quality gates passed; the review readiness checklist is complete.

Review readiness checklist

  • ✅ All CI tests are green on my local testing.
  • ✅ I pushed my PR to the latest dev commit.
  • ✅ I resolved all correct Codex and CodeRabbit findings.
  • ✅ My PR is ready for review.

4/4 boxes ticked.

This pull request is already Ready for Review.
The review-ready label marks this PR as ready; review automation runs independently.
Maintainers: @lidge-jun @Ingwannu @Wibias

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 212c9b92-cf79-48cf-aa7b-699f0d96c434

📥 Commits

Reviewing files that changed from the base of the PR and between ab42ba0 and 7d6d3a6.

📒 Files selected for processing (1)
  • src/routing/compatibility/behavior.ts

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


📝 Walkthrough

Walkthrough

The change adds family-aware, case-insensitive own-property lookup for model behavior overrides and exact-own lookup for selected routing maps. Tests cover matching, prototype-shaped model IDs, routing overrides, hosted-tool preferences, and fingerprint computation.

Changes

Model override resolution

Layer / File(s) Summary
Model override lookup semantics
src/routing/compatibility/behavior.ts
modelRecordValue resolves per-model behavior overrides with family-aware and case-insensitive matching. exactOwnValue preserves exact own-property matching for OpenRouter and hosted-tool overrides.
Override and fingerprint validation
tests/routing-compatibility-model-matching.test.ts
Tests validate tagged models, case-folded keys, unrelated models, prototype-shaped IDs, exact-own routing behavior, hosted-tool preferences, and fingerprint computation.

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

Merge Risk: ⚪ Minimal · up to 7d6d3

This localized change aligns behavior-report model override lookups with runtime resolution and adds targeted regression coverage; no actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers: ingwannu

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: aligning Lab report per-model override lookup with runtime behavior.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@lidge-jun

Copy link
Copy Markdown
Owner

Reviewed as part of a four-PR batch (#2077, #2085, #2086, #2100) applying the same modelRecordValue migration at four call sites.

The prototype-chain defect is real and worth fixing. A bare index walks the prototype chain, so a routed model id of constructor or toString yields an Object.prototype function, JCS rejects it (src/lab/conformance/jcs.ts:59), and the subject is dropped without a trace. modelRecordValue genuinely prevents it — both direct lookups use hasOwnProperty and the final scan uses own enumerable entries.

Holding on scope. modelValue is also used for modelPreferHostedTools (src/routing/compatibility/behavior.ts:186), and that map is deliberately exact-own-only at runtime (src/adapters/openai-responses.ts:989, documented at src/types.ts:1583). After this PR a gpt-oss family entry changes the behavior fingerprint for gpt-oss:120b even though the adapter will never apply it — which inverts the very contract the PR is enforcing. There is no test covering that path.

One missed read: effective.modelOpenRouterRouting?.[modelId] at behavior.ts:71 is still bare. That map is also exact-own-only (src/providers/openrouter-routing.ts:83), so it needs an exact own-property lookup — not modelRecordValue, and not the current bare index either.

Suggested shape: modelRecordValue for the nine family-aware maps, plus a small exact-own helper for hosted tools and OpenRouter routing.

One correction for the description: the throw is caught at src/routing/compatibility/subject.ts:125, which returns no route; resolvePassiveRouteSubjectId's catch is a second backstop and does not see this exception. The silent-drop conclusion is right, the described control flow is not.

@lidge-jun

Copy link
Copy Markdown
Owner

Reviewed as part of a four-PR batch with #2085, #2086, and #2100.

Verdict: hold — the migration is too broad, and it violates the contract it is enforcing.

First, the good part: the prototype-chain defect is real, and for the nine maps the runtime genuinely resolves through modelRecordValue, this fix is right.

The problem. modelValue is also used for modelPreferHostedTools (src/routing/compatibility/behavior.ts:186), and that map is deliberately exact, own-property only at runtime (src/adapters/openai-responses.ts:989, documented on the type at src/types.ts:1583). After this PR a gpt-oss family entry affects gpt-oss:120b in the behavior fingerprint even though the adapter will never apply it. That is the same class of divergence the PR sets out to remove, pointed the other way.

modelOpenRouterRouting at behavior.ts:71 is also exact-own-only at runtime (src/providers/openrouter-routing.ts:83) and is still a bare read here — so it keeps the prototype-walk bug.

To land: use modelRecordValue for the nine family-aware maps, and a separate exact-own-property helper for hosted tools and OpenRouter routing. A bare map?.[modelId] is wrong for those two as well — it walks the prototype chain — but modelRecordValue is wrong in the opposite direction. The right primitive is neither.

One correction to the description, since it will end up in the commit message: the throw is caught at src/routing/compatibility/subject.ts:125, which returns no route, and registration then yields null. resolvePassiveRouteSubjectId's catch is a second backstop and does not catch this one. The silent-subject-drop conclusion is correct; the control flow as described is not.

Also missing: coverage for the modelPreferHostedTools behavior change.

@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 47 / 80

#2059가 리스트 절반을 맞춘 뒤, 리포트의 per-model 오버라이드 맵이 런타임 modelRecordValue와 어긋나던 나머지 절반을 고친다. 베어 인덱스는 gpt-oss:120b의 패밀리 값을 놓치고, 대소문자를 놓치고, constructorObject.prototype 함수를 돌려 buildBehaviorFingerprintV1이 throw한다. 링커는 그 throw를 삼켜 트래픽을 조용히 버린다. hygiene 통과, review-ready, 체크리스트 4/4다. 방향은 맞아서 아이디어는 52다. 점수는 47이다. 메인테이너가 이미 hold했다. modelValuemodelPreferHostedTools에도 쓰이는데, 그 맵은 exact/own-property만 봐야 한다.

코드는 src/routing/compatibility/behavior.tsmodelValue() 한 줄이다. map?.[modelId] 대신 modelRecordValue(map, modelId)다. 아홉 맵은 런타임과 같아진다. 열 번째 modelPreferHostedToolsopenai-responses.tshasOwnProperty로만 읽는다. 리포트가 패밀리/케이스폴드까지 적용하면, 런타임이 안 쓰는 hosted-tools 오버라이드를 리포트가 있다고 말하게 된다. 저자가 맞추려던 계약과 반대다.

테스트는 와이어 max_tokens: 1234를 먼저 고정한 뒤 리포트 limits.maxOutputTokens를 묶는다. 케이스폴드 윈도우, 무관 모델 null, prototype id, fingerprint 계산 가능까지 본다. 좋은 형태다. 빠진 건 modelPreferHostedTools가 family/case-fold로 커지면 안 된다는 네거티브다.

#2100/#2085/#2086과 같은 배치로 보면 안 된다. 여기 hold 이유는 이 헬퍼가 두 계약을 한 함수에 넣었다는 점이다. resolverVersion을 안 올린 선택은 #2059와 같다. 메인테이너가 generation boundary를 원할 수 있다.

해결방안

modelPreferHostedToolsmodelRecordValue를 타지 않게 분리하라. 나머지 아홉 맵만 위임하면 hold는 풀린다. 그 분리를 테스트 한 줄로 고정하고, hosted-tools가 gpt-oss 패밀리로 번지지 않는지 보라. 그 전엔 머지하지 마라. #2100과 한꺼번에 들이지 마라.

이 댓글은 grok-bot이 작성했습니다

ntdatt812 added a commit to ntdatt812/opencodex that referenced this pull request Aug 19, 2026
Review feedback on lidge-jun#2077: routing every override map through
`modelRecordValue` was too broad, and for two of them it inverted the very
contract the PR is enforcing.

`modelPreferHostedTools` and `modelOpenRouterRouting` are deliberately exact
at runtime. The adapter reads the first through `hasOwnProperty`
(src/adapters/openai-responses.ts:1001) and `resolveOpenRouterRouting` reads
the second through `Object.hasOwn` (src/providers/openrouter-routing.ts:89);
the type documents the first as "Exact-model hosted tools"
(src/types.ts:1584). Family-resolving them would make the report say a
`gpt-oss` entry applies to `gpt-oss:120b` when the adapter never applies it --
the same divergence this PR removes, pointed the other way.

A bare index is not the answer for those two either: it walks the prototype
chain, which is the defect `modelValue` was changed to fix. `modelOpenRouterRouting`
was still a bare read at behavior.ts:87 and therefore still carried that bug.
Neither existing primitive fits, so this adds a third: `exactOwnValue`.

Split is now nine family-aware maps through `modelValue`, two exact-own maps
through `exactOwnValue`.

Five tests. The two "report agrees" cases are red if either map is sent back
through `modelRecordValue`; the ground-truth and control cases pass either way
by design. Ground truth for the routing half is executable --
`resolveOpenRouterRouting` is exported, and it returns the entry for the exact
key and undefined for the tagged sibling.

Also corrects the docblock's control flow, which the review flagged: the throw
is caught at src/routing/compatibility/subject.ts:125, which returns no route.
`resolvePassiveRouteSubjectId`'s catch is a second backstop and does not see it.
@ntdatt812
ntdatt812 force-pushed the fix/compat-behavior-model-overrides branch from f4213f2 to ab42ba0 Compare August 19, 2026 13:33
@ntdatt812

Copy link
Copy Markdown
Contributor Author

@lidge-jun the hold is correct on every point, and all four are fixed in ab42ba031. I verified each against the code rather than taking them on trust.

The scope objection was right, and it was the sharper half of the review. modelValue also served modelPreferHostedTools, which is exact-own at runtime — hasOwnProperty at src/adapters/openai-responses.ts:1001, and src/types.ts:1584 literally says "Exact-model hosted tools". Family-resolving it would have been this PR's own divergence with the sign flipped.

And you caught one I missed: modelOpenRouterRouting at behavior.ts:87 was still a bare read, so it kept the prototype-walk bug the first commit was written to remove. resolveOpenRouterRouting reads it through Object.hasOwn (src/providers/openrouter-routing.ts:89).

So the split is now nine family-aware maps through modelValue, two exact-own maps through a new exactOwnValue — your suggested shape exactly. Measured, with both override maps present:

gpt-oss:120b fingerprint
both maps through modelRecordValue 96a2ad0adbcae1de — a different subject
both maps through exactOwnValue 5c992edff35bd7e9 — unchanged

That is the concrete cost of getting it wrong: an override the adapter will never apply, silently moving the subject identity.

Coverage for the behaviour change is five new tests. The two "report agrees" cases go red if either map is sent back through modelRecordValue; a prototype-shaped id resolves neither map is red against dev. Ground truth for the routing half is executable rather than cited — resolveOpenRouterRouting is exported, so the test asserts it returns the entry for the exact key and undefined for the tagged sibling before asserting anything about the report.

The description correction is in too. You were right: the throw is caught at src/routing/compatibility/subject.ts:125, which returns no route; resolvePassiveRouteSubjectId's catch is a second backstop and never sees it. Fixed in the body and in the docblock, since that text was going into the commit message.

Corrected counts: the file is 21 tests, 13 pass / 8 fail against current dev — not the 9 pass / 7 fail the old description claimed.

Rebased onto 7a2d13a74 (31 commits behind). bun run typecheck exit 0; 116 pass / 0 fail across compatibility, openrouter-routing, fastwire-observability and lab-live-review-regressions.

Full bun run test had one failure, selection order across rotation strategies > … main draining is honored everywhere in tests/codex-pool-rotation.test.ts (5.7 s under load). It passes 69/69 in isolation, imports only src/codex/* and src/config, and nothing under src/codex/ references routing/compatibility. Reporting it rather than calling the run clean.

One thing I found and deliberately did not touch. effectiveOpenRouterRouting has no isCanonicalOpenRouterTarget(baseUrl) gate, while resolveOpenRouterRouting returns undefined before reading anything when the base URL is not a canonical OpenRouter target. So for a non-OpenRouter provider carrying openRouterRouting, the report describes routing the runtime never applies — same contract, pre-existing, and closing it would move fingerprints for existing configs. That feels like it wants the generation boundary you hinted at rather than a quiet fix inside this PR. Happy to open it separately, or fold it in here if you would rather have the file's evidence contract closed in one go.

@github-actions
github-actions Bot marked this pull request as draft August 19, 2026 13:35
ntdatt812 and others added 2 commits August 19, 2026 20:56
…reads them

lidge-jun#2059 fixed the list-shaped half of the behavior report. The per-model maps
are the other half, and they had the same shape of bug plus one more.

`modelValue` was a bare index, `map?.[modelId]`. The runtime reads these maps
through `modelRecordValue`, which checks own properties, then the pre-colon
family, then a case-folded key. So the report disagreed three ways:

- ollama-cloud serves `gpt-oss:120b`. With `modelMaxOutputTokens: {"gpt-oss":
  1234}` the adapter puts `max_tokens: 1234` on the wire, while the report said
  `limits.maxOutputTokens: null`.
- a differently-cased key resolved at runtime and not in the report.
- the index walked the prototype chain. Model ids are operator-controlled, so
  one can be `constructor` or `toString`, and the row then held an
  Object.prototype *function*.

That last one is not merely wrong data. `jcsStringify` rejects a function, so
`buildBehaviorFingerprintV1` threw `unsupported value type function`, and
`resolvePassiveRouteSubjectId` swallows the throw -- the subject silently never
links, and Lab loses that traffic with no diagnostic. The linker's own contract
says a registered implementation is "synchronous, free of side effects with
respect to the request, and non-throwing"; the try/catch is the backstop, not a
licence. openai-responses.ts already guards `modelPreferHostedTools` against
exactly this, with a comment saying why.

Nine of the ten maps the report reads are read through `modelRecordValue` at
runtime; delegating to it makes the report agree with all of them at once.

Fingerprints, same config, before and after:

    gpt-oss:120b   54154e19bd2c8ee4 -> 5c992edff35bd7e9   (was missing 1234)
    gpt-oss        5c992edff35bd7e9 -> 180a84b2d837619d   (was missing 55555)
    glm-5.3        54154e19bd2c8ee4 -> 54154e19bd2c8ee4   (unchanged)
    constructor    THROW            -> 54154e19bd2c8ee4   (now computable)

Only subjects whose overrides were being missed move; `resolverVersion` stays
at 2 for the reason given in lidge-jun#2059.

Tests extend the file lidge-jun#2059 added: the adapter's wire is asserted first, then
the report is held to it, and the prototype-shaped ids get their own cases
including one that the fingerprint stays computable. Seven of the nine fail on
current dev.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review feedback on lidge-jun#2077: routing every override map through
`modelRecordValue` was too broad, and for two of them it inverted the very
contract the PR is enforcing.

`modelPreferHostedTools` and `modelOpenRouterRouting` are deliberately exact
at runtime. The adapter reads the first through `hasOwnProperty`
(src/adapters/openai-responses.ts:1001) and `resolveOpenRouterRouting` reads
the second through `Object.hasOwn` (src/providers/openrouter-routing.ts:89);
the type documents the first as "Exact-model hosted tools"
(src/types.ts:1584). Family-resolving them would make the report say a
`gpt-oss` entry applies to `gpt-oss:120b` when the adapter never applies it --
the same divergence this PR removes, pointed the other way.

A bare index is not the answer for those two either: it walks the prototype
chain, which is the defect `modelValue` was changed to fix. `modelOpenRouterRouting`
was still a bare read at behavior.ts:87 and therefore still carried that bug.
Neither existing primitive fits, so this adds a third: `exactOwnValue`.

Split is now nine family-aware maps through `modelValue`, two exact-own maps
through `exactOwnValue`.

Five tests. The two "report agrees" cases are red if either map is sent back
through `modelRecordValue`; the ground-truth and control cases pass either way
by design. Ground truth for the routing half is executable --
`resolveOpenRouterRouting` is exported, and it returns the entry for the exact
key and undefined for the tagged sibling.

Also corrects the docblock's control flow, which the review flagged: the throw
is caught at src/routing/compatibility/subject.ts:125, which returns no route.
`resolvePassiveRouteSubjectId`'s catch is a second backstop and does not see it.
@ntdatt812
ntdatt812 force-pushed the fix/compat-behavior-model-overrides branch from ab42ba0 to 7d6d3a6 Compare August 19, 2026 13:56
@ntdatt812
ntdatt812 marked this pull request as ready for review August 19, 2026 14:44
@ntdatt812

Copy link
Copy Markdown
Contributor Author

Rebased again onto 0fc8d136e and re-verified — dev had moved 72 commits in the hour since the previous rebase. Checklist ticked, out of draft.

bun run typecheck exit 0. Targeted and blast-radius suites green.

A heads-up that is not about this PR. The full bun run test on that head has two failures in tests/ws-upstream.test.ts:

(fail) handleResponses Codex WS relay selection > an HTTP fallback remains on the configured legacy tee path
(fail) handleResponses Codex WS relay selection > an older runtime stays on HTTP SSE without opening a WebSocket

Both assert isEagerRelaySseResponse(response) is false and get true. They are not mine and not flaky — they reproduce in isolation, and they still fail with src/ checked out wholesale to origin/dev (21 pass / 2 fail either way). They also did not appear in my full-suite runs against 7a2d13a74 earlier today.

git bisect run over the 72 commits points at:

159d2ab183c69db98a2955660c2f8344f83c8e4d  fix(windows): keep catalog discovery off request event loop  (@Ingwannu)

It widened collectCatalogState to allow a Promise return and switched defaultCollectCatalogState to collectCodexAppServerCatalogStateForRequest. I have not dug past the bisect, so treat the mechanism as unverified — but the boundary is reproducible.

Worth knowing that I am on bun 1.3.14, which tests/ws-upstream.test.ts:42 pins as not supporting the bounded relay, so the second test is one your CI may skip on a newer bun. The first one injects BOUNDED_WS_RUNTIME explicitly, so it should be runtime-independent.

Happy to open this as its own issue if you would rather not have it sitting in a PR thread.

@ntdatt812

Copy link
Copy Markdown
Contributor Author

Correction to my previous comment — I named the wrong commit, and the wrong author.

I attributed the two tests/ws-upstream.test.ts failures to 159d2ab18 (@Ingwannu). That is wrong, and I apologise for putting a name to it. My bisect declared 7a2d13a74 as the "good" end on the strength of ws-upstream not appearing in two earlier full-suite logs — absence from a log is not a passing test, and I should not have treated it as one. 7a2d13a74 fails too, so the whole bisect ran inside an already-broken range.

Re-bisected with both endpoints measured rather than assumed:

dec332c49  23 pass / 0 fail
5a75e57ff  21 pass / 2 fail   fix(grok): switch to Responses backend and backfill required annotations

That commit adds createResponsesFieldBackfillBlockRewrite() to blockRewrites unconditionally, so needsClientRewrite is now always true. isWin32EagerRewrite is platform === "win32" && needsClientRewrite (src/lib/bun-stream-caps.ts:126), so on Windows every Responses stream now takes the eager single-reader relay. The two tests assert isEagerRelaySseResponse(response) is false, which on win32 no longer holds for a reason unrelated to WS selection.

Instrumented at the gate to confirm rather than infer:

[EAGER] {"forceCodexWsEagerRelay":false,"useEagerRelay":null,"win32EagerRewrite":true,
         "needsClientRewrite":true,"platform":"win32","blockRewrites":1}

So this is Windows-only, it is not a WS-path defect, and it is not @Ingwannu's change. Still unrelated to this PR — but my earlier account of it was wrong and I would rather correct it in the same place I got it wrong.

@lidge-jun

Copy link
Copy Markdown
Owner

Thanks for this, @ntdatt812 — closing as superseded by #2140, which carries your patch applied unchanged, alongside your #2077 for the Lab behavior report.

They are combined because they are one thesis on two disjoint files: model-keyed lookups must use the runtime's own resolution rules. Your tests came across verbatim, including the prototype-id cases, which are the load-bearing part — reverting just the two source files fails 13 of them.

Your work is credited in that PR's description.

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

Labels

bug Something isn't working review-ready

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants