Skip to content

fix: resolve combos by what they are, and check the documented discovery limits (#5216, #5215) - #5294

Merged
lidge-jun merged 6 commits into
devfrom
codex/260920-lane-g-onboarding-update
Sep 20, 2026
Merged

lidge-jun merged 6 commits into
devfrom
codex/260920-lane-g-onboarding-update

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Sep 20, 2026

Copy link
Copy Markdown
Owner

Summary

Roadmap item 16 asks for connect → confirm → change → check state → recover as one flow. This PR
delivers the two targets that were fully specified and self-contained, and records the analysis
the rest needs before it can be sequenced. It adds no new control plane and no new widget.

The finding that shapes the flow

The dashboard is served by the proxy: startServer binds the listener and that same listener
serves gui/dist. When the proxy stops there is no surface left to render a recovery panel, so
the state #5261 was reported in — injected routing pointing Codex's own built-in provider at a
dead loopback port — is one the dashboard cannot be part of getting out of. Recovery belongs to
the surfaces that survive the proxy, which is where #5267 already put it. What the dashboard owes
is disclosure before the fact: it is the only surface present when the integration is applied
and the one that will be gone if the proxy later stops.

#5216 — the compaction panel described behaviour the code does not have

The panel decided whether a selection was a combo by testing for a combo/ prefix. A combo
reached through an alias carries no prefix, so it was described as an ordinary provider and none
of its targets were named. It now asks what the selection resolves to, keyed by the public model
id the server already computes, read through parseComboList — the same reader the combo
workspace uses, so the selector rule is not written down twice. The canonical prefix is kept as
an independent signal, because it is the only one left while /api/combos is unanswered or
unavailable, and losing it there would call a combo "the provider named combo".

The warning claimed a covered compaction goes to every target including failover targets.
core-combo.ts dispatches one target per loop iteration, returns as soon as one responds, and
advances only after a retryable failure. An operator reading the old text would budget fan-out
cost and latency for something that never happens. Reworded in all ten locales.

#5215 — hand-copied registry values had no check behind them

Thirteen presets restate a byte ceiling and a row ceiling across eight guides. #5198 fixed a
preset count that had drifted across sixteen files for months for exactly this reason; these are
the same shape one layer down. Every value is now read from that preset's modelDiscovery, so
lowering a ceiling fails in all eight locales at once.

Sections are located by brand name plus the presence of a KiB/MiB token rather than by a
translated sentence, because a restated anchor phrase is the same hand-copied value the guard
exists to remove. The byte ceiling is compared as an exact token set and the row ceiling is read
with the unit tokens removed, so neither can pass on the other's digits.

The guard earned its keep immediately. structure/ops/docs-and-release.md asserted in prose that
the guides carry the same limits, across sixteen-plus files, verified by nobody. That claim was
false when it was written
: the Korean guide had no Featherless section, so it documented twelve
of the thirteen limited presets. The section is added and the prose is replaced by a description
of what is actually asserted.

#4560 and #5068 — analysed, deliberately not merged

The instruction was to review the real difference and consolidate only duplicated screens. They
are not the same feature. 46 and 39 files, intersecting in 31, of which only nine are
byte-identical. #4560 is the UI foundation (responsive grid, collapsible rails, Cockpit import,
the quota-analysis suite); #5068 is the pool follow-up (pool strategy persistence and preview,
per-account refresh, token estimates, plan badges, focus trapping).

Three findings decide their sequencing, and none of them is "they overlap":

  1. feat(gui): isolate pool-workspace follow-up on fresh dev #5068 removes behaviour feat(gui): redesign provider accounts workspace with adaptive grid, collapsible rails, and quota controls #4560 keeps — its ProviderAccountCard.tsx drops the Grok coupon
    badge and the ProviderAccountQuota fallback, so landing it after feat(gui): redesign provider accounts workspace with adaptive grid, collapsible rails, and quota controls #4560 would silently
    revert them.
  2. feat(gui): isolate pool-workspace follow-up on fresh dev #5068 changes an email-masking decisionaccount-quota-analysis.ts adds rawEmail and
    prefers an unmasked value where feat(gui): redesign provider accounts workspace with adaptive grid, collapsible rails, and quota controls #4560 uses the management API's projected email. That is a
    privacy boundary and needs explicit review against emailMaskingEnabled before either lands.
  3. feat(gui): isolate pool-workspace follow-up on fresh dev #5068 cannot land as it stands — it folds the collapsed-sidebar CSS into
    gui/src/styles.css, whose committed cap is 2,958 lines; its head is 3,186. The ratchet only
    moves downward, so the remedy is the sibling file feat(gui): redesign provider accounts workspace with adaptive grid, collapsible rails, and quota controls #4560 already uses, not a new number.

Both are 28 commits behind dev and conflict on all ten locale catalogs through #5197.

Remaining scope (these issues stay open)

Verification

  • Static source review of every changed file, plus an adversarial source review of the branch.
    That review found all three defects fixed in af33bc39d7: a combo alias of constructor or
    toString read an inherited Object member and was joined as a target list; recognizing a
    combo only through the fetched list lost the prefix signal when /api/combos was unavailable;
    and the row-ceiling check could pass on the byte ceiling's digits.
  • The documentation guard was transcribed into a standalone script and run over all eight guides
    before committing, rather than assumed. That is how the Korean gap surfaced and how the byte
    and row values were confirmed to already agree with the registry everywhere else. 104 of 104
    locale/section combinations resolve to exactly one paragraph with one unit token.
  • Union-defect classes checked by hand: no changed file is at or over a file-size cap
    (gui/src/styles.css is untouched here, which is precisely why feat(gui): isolate pool-workspace follow-up on fresh dev #5068 cannot land as it
    stands); the new test is registered in both scripts/test-layout/layout.json and
    tests/fixtures/test-layout-expected.json; all ten locale catalogs keep an identical key set
    because only values changed; and no count is restated — the limits are derived.
  • Rebased onto dev 53725b0dec and pushed at that base, so hosted CI runs at the exact head.
  • NOT RUN: bun run test, individual bun test files, bun run typecheck,
    bun run lint:gui, bun run build:gui, bun run structure:check, bun install, and live
    ocx execution. This lane verifies by static review plus exact-head hosted CI only; the CI run
    on this head is the test evidence.

Closes #5216
Closes #5215

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.

Summary by CodeRabbit

  • New Features

    • Added provider discovery guidance for Featherless, including supported plans, filtering, limits, and API key requirements.
    • Improved compaction routing support for aliased combo models without requiring a specific naming format.
  • Bug Fixes

    • Corrected combo routing disclosures to explain sequential fallback behavior rather than implying all targets receive the conversation.
    • Added coverage for unavailable combo data and reserved aliases.
  • Documentation

    • Updated provider guide limit information and added automated consistency checks across supported locales.

UI change evidence (no screenshot — GUI build is out of scope for this lane)

enforce-target arms the screenshot gate from guiPathsChanged(changedFilePaths), and this PR
changes gui/, so the gate applies. I cannot satisfy it: producing a screenshot needs
bun run build:gui and a running proxy to serve the dashboard, and this lane forbids builds and
live ocx execution. Below is the evidence a screenshot would have carried, so a maintainer can
judge whether to waive it with the gui-screenshot-waived label or a comment.

Layout is unchanged. No element is added, removed, resized or moved. The panel keeps its
section.panel, the same three Select controls and save button, and the same single
div.notice-warn[role="note"] in the same position beneath them. The only change is which of
two existing strings renders inside that note, and the wording of one of them
.

Selected compaction model Before After
A provider model, e.g. gateway/cheap "…sends the full conversation contents to gateway for summarization." unchanged
A prefixed combo, combo/compact "…to every target of combo combo/compact (gateway, openai-apikey), including failover targets, for summarization." "…to combo combo/compact for summarization. The combo attempts its targets (gateway, openai-apikey) in order and uses the first that answers, so any one of them can receive the conversation."
An aliased combo, e.g. quickpick "…sends the full conversation contents to quickpick for summarization." — the alias is named as if it were a provider, and its targets are never shown "…to combo quickpick for summarization. The combo attempts its targets (xai, gateway) in order…"
A combo while /api/combos is unavailable (prefixed combos only) the combo wording with "its configured target providers" unchanged for prefixed combos; an alias falls back to the provider wording, since nothing can resolve it

The third row is the user-visible defect #5216 reports. The second row is the wording correction.

Rendered-output coverage stands in for the image: gui/tests/compaction-routing-panel.test.tsx
mounts the real component against a fixture /api/combos payload and asserts the exact text of
[role="note"] in each of those states, including a new aliased-combo case, a new
combos-unavailable case, and a new case for an alias that shadows an Object member. The
locale catalogs keep an identical key set, so no layout reflow from a missing key is possible.

…t runs

Two user-visible strings on the compaction-routing surface described behaviour
the code does not have.

The panel decided whether a selection was a combo by testing for a "combo/"
prefix. A combo reached through an alias carries no prefix, so it was described
as an ordinary provider and none of its targets were named -- the answer existed
and the operator could not see it. The panel now asks what the selection
resolves to: the combo list is keyed by the public model id the server already
computes, which is the alias when one is set and "combo/<id>" otherwise, so both
spellings answer the same way. It reads that list through parseComboList, the
same reader the combo workspace uses, so the selector rule is not spelled out a
second time here.

The combo warning told the operator that a covered compaction goes to every
target, including failover targets. It does not. core-combo.ts dispatches one
target per loop iteration, returns as soon as one responds, and advances only
after a retryable failure. An operator reading the old text would budget fan-out
cost and fan-out latency for something that never happens. The warning now says
the targets are attempted in order and the first that answers is used, which is
both what happens and what someone debugging a slow compaction needs.

Wording changed in all ten locales. The regression covers the aliased combo the
prefix test could not see, and asserts the ordering sentence rather than the
fan-out claim.

Closes #5216
The provider guides restate a byte ceiling and a row ceiling for thirteen
fixed-host presets, in eight pages, and nothing compared any copy to the
registry. #5198 fixed a preset count that had drifted across sixteen files for
months for exactly that reason; these limits are the same shape one layer down.

Every number is now read from that preset's modelDiscovery and asserted against
every shipped guide, so lowering a ceiling fails in all eight locales at once
instead of leaving seven translations describing the old one. A grouped section
must first agree in the registry before one sentence may speak for two presets,
which is what makes the Nscale/Vultr and Command Code sentences legitimate
rather than convenient.

Sections are located by brand name and the presence of a KiB or MiB token, not
by a translated sentence. A restated anchor phrase is the same hand-copied value
the guard exists to remove, and the brand names are Latin in all eight published
locales. The byte ceiling is compared as an exact token set rather than a
substring, so a stale number left beside the current one fails.

The structure record claimed the guides carried identical limits. That claim was
false when it was written: the Korean guide had no Featherless section, so it
documented twelve of the thirteen limited presets. The section is added and the
prose is replaced by a description of what is actually asserted.

Closes #5215
…lane

Combo target lookup read a plain object by the selected model id. A combo id is
free-form, so an alias of "constructor" or "toString" resolved to an inherited
Object member and the renderer tried to join a function. Read it with
Object.hasOwn.

Recognizing a combo only through the fetched list lost the canonical prefix as
a signal of its own. When /api/combos has not answered yet or failed, a
"combo/x" selection was described as an ordinary provider named "combo" -- worse
than the alias gap this lane set out to fix, because that path is reachable
whenever the management API is briefly unavailable. The prefix is kept as an
independent signal and the target names fall back to the existing
"its configured target providers" wording.

The documentation guard compared the row ceiling as a substring of the whole
paragraph, so the byte ceiling's own digits could satisfy it: a Hyperbolic
paragraph saying "256 KiB and 128 raw rows" would have passed an expected 256
rows. Row numbers are now read from the prose with the unit tokens removed. All
104 locale/section combinations still pass, verified by transcribing the test's
own logic over the eight guides.
Why the recovery path cannot live in the dashboard, what each of the six targets needed, the differential between the two workspace pull requests with the three findings that decide their sequencing, and the one src/ defect this lane identified and left stated rather than half-fixed.
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 20, 2026 08:21
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 20, 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-20T09:41:13.780997Z e701a06 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.

@coderabbitai

coderabbitai Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Repository: lidge-jun/opencodex/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 8004405f-f88c-4fa5-8152-c74ee10097bd

📥 Commits

Reviewing files that changed from the base of the PR and between 53725b0 and e701a06.

📒 Files selected for processing (18)
  • devlog/_plan/260920_meaning_preservation_batch/020_lane_g.md
  • docs-site/src/content/docs/ko/guides/providers.md
  • gui/src/components/CompactionRoutingPanel.tsx
  • gui/src/i18n/de.ts
  • gui/src/i18n/en.ts
  • gui/src/i18n/fr.ts
  • gui/src/i18n/ja.ts
  • gui/src/i18n/ko.ts
  • gui/src/i18n/ru.ts
  • gui/src/i18n/tr.ts
  • gui/src/i18n/vi.ts
  • gui/src/i18n/zh-TW.ts
  • gui/src/i18n/zh.ts
  • gui/tests/compaction-routing-panel.test.tsx
  • scripts/test-layout/layout.json
  • structure/ops/docs-and-release.md
  • tests/ci-workflows/docs-provider-discovery-limits.test.ts
  • tests/fixtures/test-layout-expected.json
 ______________________________________________
< Making your bugs an offer they can't refuse. >
 ----------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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 the bug Something isn't working label Sep 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

…ect key

A combo's public model id is free-form and operator-configured, and
readComboProviders wrote it straight into an object literal. That is a
prototype-pollution sink on the write side, and the read side returned an
inherited member for an alias of "constructor" or "toString" -- the previous
commit guarded the read with Object.hasOwn and left the write as it was.

A Map removes both. There is no prototype to shadow, the guard disappears, and
the failed-fetch fallback returns an empty Map rather than an empty object, so
the two branches keep the same type.

@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: 5445e38a24

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

? targets.map(target => (target as { provider?: unknown })?.provider).filter((value): value is string => typeof value === "string")
: [];
result[(combo as { id: string }).id] = [...new Set(providers)];
for (const combo of parseComboList(payload)) {

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 Index aliased combos under their canonical selector too

When compactionRouting.model is the canonical combo/<id> for a combo that also has a public alias, /api/combos returns only the alias in combo.model, so this map has no entry for the saved canonical selector. That selector remains valid by design (resolveComboId explicitly accepts canonical IDs for backward compatibility), and combo edits do not migrate compactionRouting; the prefix fallback therefore recognizes the combo but displays “its configured target providers” instead of the actual providers, regressing the disclosure that previously worked for canonical IDs. Index each row by both combo.model and comboModelId(combo.id).

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

Useful? React with 👍 / 👎.

Comment thread gui/src/i18n/en.ts
"compactionRouting.autoNotice": "Automatic compaction runs on its own, so a long conversation can be sent to that provider without you asking for it.",
"compactionRouting.providerWarning": "With this setting, every covered compaction request sends the full conversation contents to {provider} for summarization.",
"compactionRouting.comboWarning": "With this setting, every covered compaction request sends the full conversation contents to every target of combo {combo} ({providers}), including failover targets, for summarization.",
"compactionRouting.comboWarning": "With this setting, every covered compaction request sends the full conversation contents to combo {combo} for summarization. The combo attempts its targets ({providers}) in order and uses the first that answers, so any one of them can receive the conversation.",

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 Avoid claiming configured-order selection for every combo

For combos using round-robin, random, least-used, or reset-window, this warning is inaccurate: pickComboTarget in src/combos/resolve.ts chooses the first target using weight, state, usage, or quota-reset data rather than the displayed configured order. Because the same copy is rendered for every strategy, operators can be told that (provider-a, provider-b) is attempted in that order when the request may start with provider-b; use strategy-neutral wording or include the combo strategy in the warning.

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

Useful? React with 👍 / 👎.

Comment on lines +129 to +130
expect(rowNumbers(paragraph), `${guide.path} ${section.brand} row ceiling`)
.toContain(rows);

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 Bind the row check to the row-limit statement

For Featherless, every guide paragraph contains two standalone 100 values: the request asks for the top 100 models and discovery is capped at 100 raw rows. If the raw-row limit sentence is removed or becomes stale while the unrelated query-size value remains, rowNumbers(paragraph).toContain(rows) still passes, so the new guard does not actually ensure that this documented row ceiling exists. Match a number in row-limit context or require an unambiguous occurrence rather than accepting any integer in the paragraph.

Useful? React with 👍 / 👎.

@github-actions

github-actions Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • UI screenshot required.

What to do

  • Add a screenshot of the UI change to the PR description.

Automatic draft conversion failed (token cannot change draft status). Please convert this pull request to a draft manually. The required enforce-target check will keep failing until every issue above is resolved.

@github-actions
github-actions Bot marked this pull request as draft September 20, 2026 08:28
@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 41 / 80

이 PR은 압축 라우팅 화면이 콤보를 잘못 읽던 부분과, 공급자 안내 문서에 손수 적힌 discovery 한도가 레지스트리와 어긋날 수 있던 부분을 고칩니다. 베이스는 dev입니다. #5216과 #5215만 닫고, 레인 G의 나머지(#4560, #5068, #5016, #2811)는 분석만 남깁니다.

예전에 화면은 이름이 combo/로 시작하는지로만 콤보인지 봤습니다. 별칭으로만 고른 콤보는 접두사가 없어서, 일반 공급자로 보이고 대상 이름도 안 나왔습니다. 지금은 /api/combos 목록을 parseComboList로 읽고, 서버가 쓰는 공개 모델 id로 Map에 넣습니다. 별칭이든 combo/...든 같은 칸을 봅니다. 경고 문구도 “모든 대상에 한꺼번에 보낸다”에서 “순서대로 시도하고 먼저 답한 하나를 쓴다”로 바꿨습니다. 런타임(core-combo.ts)은 한 번에 하나 보내고 성공하면 돌아가기 때문입니다. 조회 키를 객체 대신 Map으로 둔 것도 맞습니다. 별칭이 constructor 같은 이름이면 예전 객체 읽기는 Object 멤버를 잡았습니다.

문서 쪽은 13개 고정 호스트 프리셋의 바이트·행 한도를 레지스트리 modelDiscovery에서 읽어 여덟 개 가이드와 맞춥니다. 그 검사가 한국어 가이드에 Featherless 절이 없던 구멍을 바로 잡았고, 그 절을 넣었습니다. structure/ops/docs-and-release.md의 “한도가 같다”는 문장 주장도 실제 검사 설명으로 바꿨습니다. 테스트·레이아웃 등록도 같이 들어가 있습니다.

라인 - gui/src/components/CompactionRoutingPanel.tsx isCombo/api/combos가 아직 없거나 실패하면, combo/ 접두사만으로 콤보로 남깁니다. 별칭만 있는 선택은 그때도 일반 공급자 경고로 갑니다. 접두사 경로는 테스트로 막았고, 별칭+목록 실패는 아직 없습니다.

라인 - gui/tests/compaction-routing-panel.test.tsx constructor 테스트 — 목록에 constructor 별칭 콤보를 넣지 않습니다. “콤보가 아닐 때 공급자로 보인다”만 확인합니다. Map이 그 별칭을 맞는지 직접 증명하지는 않습니다.

라인 - 콤보 경고 문구(열 개 로케일) — “순서대로 시도”는 failover에 가깝습니다. round-robin·random·least-used도 한 대상만 쓰지만, 고르는 순서는 “목록 순서”가 아닐 수 있습니다. 팬아웃 오해는 풀렸고, 전략 이름까지 맞추지는 않았습니다.

라인 - CI — react-doctor가 이 HEAD(4fc7650)에서 실패입니다. test 조각·docs site·docker smoke 등은 통과·진행 중이었습니다. 드래프트라 CodeRabbit 리뷰는 건너뛰었습니다. 작성자 본문대로 로컬 bun test / typecheck / lint는 이 레인에서 안 돌렸고, 호스티드 CI를 증거로 둡니다.

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

레인 G 분석(#4560 vs #5068 순서, 이메일 마스킹, styles.css 상한, codexStatus가 intent만 보고 applied를 안 보는 결함)을 이 PR과 같이 갈지, 다음 티켓으로만 둘지. #4560/#5068을 닫거나 landed-via로 묶을지는 지금 코드에 없으니 이 PR만으로 닫으면 안 됩니다. 별칭 콤보가 API 다운일 때 공급자로 보이는 구멍을 이번 머지 전에 막을지, 접두사 폴백만으로 충분한지도 정해 주세요.

너의 추천

#5216·#5215 범위는 방향이 맞고, 적대 패스로 잡은 세 구멍(상속 멤버, 접두사 폴백, 행 한도 숫자 혼동)도 코드에 반영되어 있습니다. react-doctor 실패 원인만 확인한 뒤 드래프트를 풀고, CI 초록이면 dev에 머지해도 됩니다. 별칭+목록 실패 케이스와 constructor 별칭이 콤보로 잡히는 테스트 한 줄은 있으면 더 안전하고, 없어도 이번 닫기 범위를 막을 정도는 아닙니다. #4560/#5068/#5016은 이 PR로 닫지 마세요. types/config 분할 중복으로 닫을 대상도 아닙니다.

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

React Doctor's js-flatmap-filter fired on the map().filter(Boolean) this lane
introduced at CompactionRoutingPanel.tsx:51 -- one new warning in one file, and
the job's blocking threshold is warning. flatMap does the same work in a single
pass. The related js-combine-iterations rule is switched off in
gui/doctor.config.json, but this is a different rule and is enabled, so this is
a real new finding rather than an accepted one.
@lidge-jun

Copy link
Copy Markdown
Owner Author

추가 리뷰 · 우선순위 32 / 80

이전 리뷰(HEAD 4fc7650) 이후 커밋은 e701a067 하나뿐입니다. CompactionRoutingPanel.tsxreadComboProviders에서 map(...).filter(Boolean)flatMap(... ? [x] : []) 한 줄로 바꿨습니다. React Doctor의 js-flatmap-filter가 warning 임계로 막고 있었고, 그 경고를 없앤 커밋입니다. 동작은 같고, 빈 provider를 건너뛰는 뜻도 같습니다. 그 결과 이 HEAD에서 react-doctor는 통과합니다. PR 본문이 말한 #5216·#5215 범위와 Map 키·접두사 폴백·문서 discovery 한도 검사 방향은 그대로입니다. 베이스는 여전히 dev입니다.

라인 - react-doctor — 이전 리뷰에서 막히던 지점은 이 커밋으로 풀렸습니다. 확인됨.

라인 - enforce-target — 이 HEAD에서도 실패(또는 취소된 실패로 남음)입니다. gui/가 바뀌어서 스크린샷 게이트가 켜지는데, 작성자는 레이아웃은 그대로이고 경고 문자열만 바뀌었다고 적었고 gui-screenshot-waived나 면제 댓글을 요청했습니다. 이 레인에서 GUI 빌드·라이브 ocx를 안 돌리므로 스크린샷은 못 올립니다.

라인 - 드래프트 — 아직 draft입니다. 머지 전에 Ready로 올려야 합니다.

라인 - gui/src/components/CompactionRoutingPanel.tsx isCombo/api/combos 실패·미응답일 때 별칭만 있는 선택은 여전히 일반 공급자 경고로 갑니다. 이번 커밋에서 바뀐 부분 아닙니다.

라인 - gui/tests/compaction-routing-panel.test.tsxconstructor 별칭이 Map에 들어가 콤보로 잡히는 긍정 테스트, 별칭+목록 실패 회귀는 아직 없습니다.

라인 - 콤보 경고 문구 — “순서대로 시도”는 failover에 가깝고, round-robin 등 다른 전략 이름까지 맞추지는 않았습니다. 팬아웃 오해는 이전 커밋에서 이미 풀렸습니다.

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

gui-screenshot-waived를 붙여 enforce-target을 면제할지. 면제하면 드래프트만 풀고 CI 초록을 보면 됩니다. 별칭+API 다운 구멍과 constructor 긍정 테스트를 이번 머지 전에 넣을지, 다음으로 미룰지도 정해 주세요. #4560/#5068/#5016/#2811과 codexStatus applied 결함은 이 PR 코드에 없으니 여기서 닫지 마세요.

너의 추천

이전 차단이었던 react-doctor는 고쳐졌으니 코드 쪽 급한 구멍은 줄었습니다. 남은 실제 게이트는 enforce-target(스크린샷 면제)과 draft 해제입니다. 면제 라벨을 달고 Ready로 올린 뒤, 호스티드 CI가 초록이면 dev에 머지해도 됩니다. 테스트 보강은 있으면 좋고, 없어도 #5216·#5215 닫기 범위를 막을 정도는 아닙니다. types/config 분할 중복으로 닫을 대상도 아닙니다.

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

@lidge-jun
lidge-jun marked this pull request as ready for review September 20, 2026 09:37
@lidge-jun
lidge-jun merged commit 21fb6e8 into dev Sep 20, 2026
29 of 31 checks passed
@lidge-jun
lidge-jun deleted the codex/260920-lane-g-onboarding-update branch September 20, 2026 09:37
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.

1 participant