Skip to content

fix(combos): preserve all five combo strategies in dashboard and docs - #2929

Merged
lidge-jun merged 1 commit into
lidge-jun:devfrom
x3M3x:codex/combo-strategy-followup
Aug 29, 2026
Merged

lidge-jun merged 1 commit into
lidge-jun:devfrom
x3M3x:codex/combo-strategy-followup

Conversation

@x3M3x

@x3M3x x3M3x commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Follow-up to feat(combos): add random, least-used, and reset-window routing strategies #2050. The dashboard combo parser still collapsed the newer random, least-used, and reset-window strategies to failover, so opening a combo in the workspace and saving it untouched silently rewrote its strategy and stripped the weights that random honors.
  • Parse and save (PUT) now round-trip all five runtime strategies, weights serialize for both round-robin and random, and the strategy picker renders a preserved strategy that is outside the two quick options as a disabled chip instead of mislabeling it.
  • Documents all five strategies plus weight and stickyLimit scoping in the English combos guide and the routing reference.

Preserved random strategy in the combo workspace

Combo detail showing the preserved random strategy

Verification

  • On the rebased head (14cb43b0c, latest dev): bun test ./gui/tests/combo-strategy-roundtrip.test.ts — 4 pass; cd gui && bun run build (tsc -b + vite) passes.
  • Before the rebase, on the identical diff: the six combo test files (20 pass, including the four new round-trip cases), cd gui && bun run lint:i18n, and the docs-site build all passed.
  • Screenshot captured against a throwaway config with dummy providers and placeholder keys; no real credentials involved.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

No authentication, credential, or workflow surface is touched by this change.

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

  • New Features

    • Added three combo routing strategies: random, least-used, and reset-window.
    • Added weighted routing support for random and round-robin strategies.
    • Updated the configuration interface to display and preserve all supported strategies.
  • Documentation

    • Expanded routing guidance, strategy descriptions, weight behavior, and sticky-limit details.
  • Tests

    • Added coverage for strategy parsing, persistence, weighted routing, and fallback behavior.

PR lidge-jun#2050 added random, least-used, and reset-window strategies, but the dashboard parser still collapsed them to failover, so an untouched save silently rewrote the configured strategy and stripped weights that random honors. Parse and PUT now round-trip all five runtime strategies, weights are serialized for round-robin and random, and the strategy picker shows the preserved value when it is outside the two quick options.

Also documents all five strategies, weight, and stickyLimit scoping in the English combos guide and routing reference.

Validation: focused bun test (6 combo test files, 20 pass incl. 4 new), gui lint:i18n, gui build (tsc -b + vite), docs-site build.
@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 81d9ad82-445c-409a-8584-dd49a108a95a

📥 Commits

Reviewing files that changed from the base of the PR and between 1d9b389 and 14cb43b.

📒 Files selected for processing (7)
  • docs-site/src/content/docs/guides/combos.md
  • docs-site/src/content/docs/reference/configuration/routing.md
  • gui/src/combo-workspace-data.ts
  • gui/src/components/combo-workspace-add-modal.tsx
  • gui/src/components/combo-workspace-controls.tsx
  • gui/src/components/combo-workspace-detail-panel.tsx
  • gui/tests/combo-strategy-roundtrip.test.ts

📝 Walkthrough

Walkthrough

The PR expands combo routing from two strategies to five. It updates GUI strategy handling, random weight serialization and validation, round-trip tests, and documentation for the new routing behavior.

Changes

Combo strategy expansion

Layer / File(s) Summary
Strategy contract and round-trip handling
gui/src/combo-workspace-data.ts, gui/tests/combo-strategy-roundtrip.test.ts
The GUI supports failover, round-robin, random, least-used, and reset-window. Random and round-robin weights are serialized and validated. Tests cover normalization and round-trip behavior.
Strategy-aware GUI controls
gui/src/components/combo-workspace-controls.tsx, gui/src/components/combo-workspace-add-modal.tsx, gui/src/components/combo-workspace-detail-panel.tsx
Controls display additional strategy values, show weights for random routing, and omit failover or round-robin hints for other strategies.
Strategy documentation
docs-site/src/content/docs/guides/combos.md, docs-site/src/content/docs/reference/configuration/routing.md
Documentation describes the three new strategies and updates the allowed strategy values, weight behavior, stickyLimit, and combo comparison text.

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

Suggested reviewers: ingwannu

✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 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.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Aug 29, 2026
@github-actions

github-actions Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • review readiness checklist open (1/4 boxes ticked).

What to do

  • Tick all four boxes in the PR description once you're done (currently 1/4).

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.

1/4 boxes ticked.

Automatic draft conversion failed. Please convert this pull request to a draft manually until every box above is ticked.

@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 61 / 80

이 PR은 대시보드가 콤보를 저장할 때 전략을 몰래 바꾸는 버그를 고친다. 지금 dev HEAD는 1d9b389c1 (#2926 Windows 신원 조회 한도 공유)이다. 런타임은 이미 #2050 으로 전략이 다섯 개다. src/combos/types.ts 216–222행이 failover, round-robin, random, least-used, reset-window 를 받고, src/types/config.ts 665행의 OcxComboStrategy 도 같다. src/combos/resolve.ts 는 그 다섯 갈래로 실제로 고른다. random 은 요청마다 가중치로 뽑고, least-used 는 성공이 가장 적은 쪽, reset-window 는 할당량이 먼저 돌아오는 쪽이다. stickyLimit 는 round-robin 에만 쓰인다.

그런데 대시보드 쪽은 아직 옛 두 칸만 안다. gui/src/combo-workspace-data.ts 10행의 ComboStrategyfailover | round-robin 이고, 138–140행 normalizeStrategyround-robin 이 아니면 전부 failover 로 접는다. 그래서 설정 파일에 random 으로 적어 둔 콤보를 워크스페이스에서 열면 화면에는 장애 조치로 보이고, 손대지 않고 저장해도 PUT 본문이 failover 가 된다. 같은 파일 474–476행은 가중치를 round-robin 일 때만 보내므로 randomweight 도 빠진다. 미리보기 배포는 계획에 없고, types/config 분리와도 겹치지 않는다. GUI와 영문 문서만 고친다.

고치는 내용은 그 침묵 재작성만 먼저 막는다. 타입을 다섯 개로 맞추고, 파서가 모르는 값만 failover 로 돌린다. PUT 는 round-robinrandom 에 가중치를 실어 보내고, stickyLimit 는 예전처럼 round-robin 에만 붙인다. 새 테스트 gui/tests/combo-strategy-roundtrip.test.ts 가 다섯 전략 보존, 모르는 값의 failover 정규화, random 가중치 왕복, round-robin 의 stickyLimit 을 잠근다. 전략 단추 StrategySeg 는 여전히 빠른 선택 두 개만 고를 수 있고, 나머지 셋은 꺼진 칩으로 현재 값을 보여 준다. 영문 docs-site/src/content/docs/guides/combos.mdrouting.md 에 세 전략과 weight/stickyLimit 범위를 적어 런타임과 맞춘다. 초안이고, 작성자 체크리스트의 테스트·리뷰 준비 칸이 아직 비어 있다. CI 는 enforce-target/hygiene 만 초록이고 전체 스위트는 초안이라 아직 안 돈 것으로 보인다.

이 범위는 #2050 의 대시보드 후속으로 맞다. 런타임을 다시 만지지 않고, 저장이 설정을 깨는 길만 막는다. 다만 화면 분류는 그대로다. groupCombos 는 round-robin 이 아니면 전부 failover 칸에 넣는다. ComboWorkspace.tsx 130–131행 레일과 overview 숫자도 그 두 칸만 센다. 그래서 고친 뒤에도 random 콤보가 장애 조치 목록에 앉는다. 칩은 번역 키 없이 영문 슬러그 random 을 그대로 찍고, 힌트 문장은 세 전략에서 빈 값이 된다. 새로 만들 때도 고를 수 있는 건 여전히 두 개뿐이다. 즉 파일로 만든 콤보는 저장해도 안 깨지지만, 대시보드만으로는 그 세 전략을 만들거나 제대로 설명하지 못한다.

점수는 침묵 재작성이 실제 설정 손실이라 중간보다 조금 높다. 초안이고 레일 분류·번역·생성 UI 가 빠졌으므로 지금 합치지는 않는다.

라인 - gui/src/combo-workspace-data.ts groupCombos (199–206행) - round-robin이 아니면 전부 failover 칸에 넣는다. 고친 뒤에도 random/least-used/reset-window 콤보가 장애 조치 목록과 숫자에 섞인다.
라인 - gui/src/components/ComboWorkspace.tsx 130–131행 / combo-workspace-overview-panel.tsx - 레일과 개수 알약이 두 칸뿐이다. ComboSections 타입도 failover와 roundRobin만 있어서 세 전략을 넣을 칸이 없다.
라인 - gui/src/components/combo-workspace-controls.tsx StrategySeg 꺼진 칩 - 번역 키 없이 영문 슬러그를 그대로 보여 준다. 한국어 화면에서도 random 으로 적힌다.
라인 - combo-workspace-add-modal.tsx / combo-workspace-detail-panel.tsx 힌트 - failover/round-robin이 아니면 설명 문장이 null이라 빈 칸이 된다. 옛 삼항은 random을 라운드로빈 설명으로 속였을 테니, 빈 칸이 거짓 설명보다는 낫다. 그래도 설명이 없다.
경로/심볼 - StrategySeg 선택지 - 빠른 단추 두 개만 고를 수 있다. 보존은 되지만 대시보드에서 세 전략을 새로 고를 수는 없다. 의도된 범위면 본문에 그렇게 밝혀야 한다.
경로/심볼 - gui/src/i18n/en.ts cws.overviewBlurb / models.subtitle.combos - 화면 소개가 아직도 failover와 round-robin만 말한다. 문서만 다섯 개로 맞춰져 화면과 어긋난다.

메인테이너의 판단이 필요한 지점

  • 이번 조각은 저장 보존만 할지, 대시보드에서 다섯 전략을 직접 고르게 할지.
  • 레일을 칸을 더 나눌지, 기타 칸 하나를 둘지.
  • 초안 체크리스트와 전체 CI를 기다릴지, 보존 고침만 먼저 받을지.

너의 추천
지금 머지하지 마라. 초안을 유지하라. 침묵 재작성 고침과 combo-strategy-roundtrip 테스트는 가져가라. 합치기 전에 groupCombos가 세 전략을 failover 칸에 넣는 것을 고치거나, 적어도 별도 칸을 만들어라. 보존만 할 거면 본문에 그렇게 쓰고 칩/힌트 번역 키라도 추가하라. 대시보드에서 만들 수 있게 할 거면 StrategySeg 선택지를 다섯 개로 늘려라. 체크리스트와 CI가 끝난 뒤 초안을 풀고 합쳐라. types/config 분리 때문에 닫지 마라.

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

@lidge-jun

Copy link
Copy Markdown
Owner

Verified independently at head 14cb43b0c and this is a real data-loss fix, not a cosmetic one. Reverting normalizeStrategy to the old two-value form turns two of your tests red with exactly the reported symptom:

Expected: "random"
Received: "failover"
(fail) saving an untouched combo round-trips merged strategies and random weights

4 pass / 0 fail restored, and cd gui && bun run build succeeds on my checkout too.

The part I checked hardest was whether the widened type is correct rather than merely wider. COMBO_STRATEGIES mirrors OcxComboStrategy in src/types/config.ts exactly — all five, same spellings — and the runtime's own comment on OcxComboTarget.weight says "round-robin batches and random selection," so extending the weight serialization and validation to random matches what the router actually honors rather than guessing. Hoisting the weight loop out of the stickyLimit block is right for the same reason: weights are not sticky-limit-scoped.

Rendering a preserved out-of-band strategy as a disabled chip is the right call over silently relabeling it. A picker that cannot represent a value should say so, not lie about it.

One note for the record rather than a change request: normalizeStrategy falling back to failover for an unknown string is still the correct default, and it now only triggers for values the runtime itself would not accept.

Merging once the readiness checklist is complete and CI is green — the two unticked boxes are yours to confirm (local CI green, and Codex/CodeRabbit findings resolved). I did not tick them for you.

1 similar comment
@lidge-jun

Copy link
Copy Markdown
Owner

Verified independently at head 14cb43b0c and this is a real data-loss fix, not a cosmetic one. Reverting normalizeStrategy to the old two-value form turns two of your tests red with exactly the reported symptom:

Expected: "random"
Received: "failover"
(fail) saving an untouched combo round-trips merged strategies and random weights

4 pass / 0 fail restored, and cd gui && bun run build succeeds on my checkout too.

The part I checked hardest was whether the widened type is correct rather than merely wider. COMBO_STRATEGIES mirrors OcxComboStrategy in src/types/config.ts exactly — all five, same spellings — and the runtime's own comment on OcxComboTarget.weight says "round-robin batches and random selection," so extending the weight serialization and validation to random matches what the router actually honors rather than guessing. Hoisting the weight loop out of the stickyLimit block is right for the same reason: weights are not sticky-limit-scoped.

Rendering a preserved out-of-band strategy as a disabled chip is the right call over silently relabeling it. A picker that cannot represent a value should say so, not lie about it.

One note for the record rather than a change request: normalizeStrategy falling back to failover for an unknown string is still the correct default, and it now only triggers for values the runtime itself would not accept.

Merging once the readiness checklist is complete and CI is green — the two unticked boxes are yours to confirm (local CI green, and Codex/CodeRabbit findings resolved). I did not tick them for you.

@lidge-jun

Copy link
Copy Markdown
Owner

Merging this as maintainer rather than waiting on the remaining checklist boxes, and saying plainly why.

Three boxes are unticked: local CI green, Codex/CodeRabbit findings resolved, and ready-for-review. The first is an author attestation the gate cannot verify for a fork contributor — you cannot start repository CI, so it exists on trust either way. The second has nothing outstanding: there are no reviews and no unresolved inline findings on this PR. And repository CI is green on 14cb43b0c across every platform, which is stronger evidence than the box it stands in for.

What made me comfortable is that I verified the substance rather than the process: reverting normalizeStrategy turns two of your tests red with the exact reported symptom (Expected: "random", Received: "failover"), COMBO_STRATEGIES matches OcxComboStrategy exactly, and extending weight handling to random matches what the router documents it honors. cd gui && bun run build passes on my checkout.

Thanks for the follow-up on #2050 — silently rewriting a saved strategy is the kind of bug users experience as "the dashboard corrupted my config," and the disabled-chip choice for out-of-band strategies is better than relabeling.

@lidge-jun
lidge-jun marked this pull request as ready for review August 29, 2026 16:27
@lidge-jun
lidge-jun merged commit 112db9e into lidge-jun:dev Aug 29, 2026
5 checks passed
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 29, 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-08-29T16:32:54.981067Z 14cb43b Draft marked ready
ℹ️ 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.

@x3M3x

x3M3x commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the merge and for the independent verification. The UI gaps named in the Korean review above were still open at merge head 14cb43b0c, so I opened #2931 as a focused follow-up: a third "Other strategies" rail in groupCombos (plus an "Other" count pill), translated strategy chips via cws.strategy.* keys instead of the raw slug, per-strategy strategy/targets hints replacing the two-way ternaries that rendered blank for random/least-used/reset-window, and refreshed cws.overviewBlurb / models.subtitle.combos copy — with the new keys added to all nine locales and a groupCombos bucket test. Scope statement stands as before: the dashboard preserves and displays all five strategies; pickers still offer the two quick options, the other three stay config/CLI-only.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 14cb43b0ce

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +149 to +150
return typeof raw === "string" && COMBO_STRATEGY_SET.has(raw)
? raw as ComboStrategy

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep advanced strategies out of the failover count

When /api/combos returns random, least-used, or reset-window, this normalization now preserves the value, but groupCombos() still places every non-round-robin item in its failover bucket; consequently, OverviewPanel reports all three advanced strategies as Failover. Add strategy-specific buckets/counts or otherwise exclude these values from the failover total so the dashboard reflects the management configuration model.

AGENTS.md reference: gui/AGENTS.md:L9-L10

Useful? React with 👍 / 👎.

Comment on lines +42 to +46
type="button"
role="radio"
aria-checked={true}
className="btn btn-sm btn-primary"
disabled

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep the selected advanced strategy keyboard-focusable

For a combo using random, least-used, or reset-window, the only radio marked checked is unconditionally disabled, so keyboard focus skips the current selection and lands on an unchecked quick option instead. Render the preserved selection as a focusable checked radio (using aria-disabled if it must remain read-only) so keyboard and assistive-technology users can reach and identify the active strategy.

AGENTS.md reference: gui/AGENTS.md:L31-L34

Useful? React with 👍 / 👎.

Comment on lines +345 to +346
| `targets[].weight` | No | `1` | Integer from 1 to 10,000. Used by round-robin and random; ignored by failover, least-used, and reset-window. |
| `strategy` | No | `"failover"` | `"failover"`, `"round-robin"`, `"random"`, `"least-used"`, or `"reset-window"`. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Synchronize translated strategy tables

The canonical table now documents five strategies, but all seven translated combo guides and translated routing references still explicitly say that only failover and round-robin are valid and that weights apply only to round-robin. Users browsing those locales therefore receive configuration guidance that contradicts both this page and the runtime; update the directly affected localized tables and strategy descriptions alongside the English source.

AGENTS.md reference: docs-site/AGENTS.md:L7-L10

Useful? React with 👍 / 👎.

tarunravi pushed a commit to tarunravi/opencodex that referenced this pull request Sep 14, 2026
…lidge-jun#2929)

PR lidge-jun#2050 added random, least-used, and reset-window strategies, but the dashboard parser still collapsed them to failover, so an untouched save silently rewrote the configured strategy and stripped weights that random honors. Parse and PUT now round-trip all five runtime strategies, weights are serialized for round-robin and random, and the strategy picker shows the preserved value when it is outside the two quick options.

Also documents all five strategies, weight, and stickyLimit scoping in the English combos guide and routing reference.

Validation: focused bun test (6 combo test files, 20 pass incl. 4 new), gui lint:i18n, gui build (tsc -b + vite), docs-site build.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants