Skip to content

[Bug]: provider definition is lost after metadata relabeling (residual of 4311) #4582

Closed

Description

@lidge-jun

Client or integration

Codex App

Area

Proxy / routing

Summary

Splitting a residual out of issue 4311, which is otherwise resolved on dev by 44027ae.

That issue reported two symptoms together. The first — paginated Codex history stopping projection after provider metadata relabeling — is fixed: src/codex/history-provider.ts now inspects a newest-record window and refuses in-place paginated tails, so the projector no longer stops at ordinal 0.

The second symptom is a different defect and was never addressed by that change: after the same relabeling, the client reports Model provider opencodex not found and the provider definition does not survive. Closing the parent issue against the merge without recording this would have quietly lost it, so it lives here instead.

Reproduction

  1. Run a Codex App session through the proxy with a provider definition named opencodex.
  2. Relabel provider metadata so the catalog rewrites the provider entry.
  3. Continue the existing thread rather than starting a new one.
  4. The client reports Model provider opencodex not found and the provider definition is gone, even though history now projects correctly after 44027ae.

Version

2.54.0 (dev at 44027ae)

Operating system

macOS

Provider and model

opencodex-local

Logs or error output

Model provider opencodex not found

Screenshots and supporting files

None.

Redacted configuration

Not applicable — the trigger is provider metadata relabeling rather than a specific configuration value.

Checks

  • I searched existing issues before filing
  • I can reproduce this on the current version

Activity

  1. added
    bugSomething isn't working
    proxyHTTP proxy, routing, reverse-proxy / management auth
    on Sep 14, 2026
  2. lidge-jun commented on Sep 14, 2026

    @lidge-jun
    OwnerAuthor

    리뷰 · 우선순위 64 / 80

    이 이슈는 이미 CLOSED된 #4311(paginated Codex history가 provider metadata relabel 뒤 projection을 멈춤)에서 같이 보고됐지만 #4577(44027ae5a)이 고치지 않은 두 번째 증상을 따로 빼 둔 residual이다. 지금 dev HEAD 1dc46f42e에는 #4577의 history 가드가 들어 있다. src/codex/history-provider.ts의 assertLegacyHistoryWritable이 첫 줄만이 아니라 롤아웃 최신 구간(readRolloutTailCompleteLines, 약 1MiB tail)을 보고, in-place paginated 꼬리가 있으면 rollout/SQLite/manifest를 건드리지 않고 거절한다. 그래서 “히스토리가 ordinal 0에서 끊긴다”는 쪽은 현재 dev에서 막힌 상태다.

    그런데 이 이슈가 말하는 증상은 그 가드와 다른 축이다. 같은 relabel 흐름 뒤에 Codex App이 Model provider opencodex not found 를 내고, 이름이 opencodex인 provider definition이 스레드 계속 사용 시점에 사라져 있다는 것이다. 히스토리 projection은 살아도, 클라이언트가 고를 provider 엔트리 자체가 없으면 기존 스레드는 사실상 죽은 것과 같다. 부모 이슈를 #4577에 닫을 때 이 증상을 같이 닫아버리면 조용히 유실되므로, #4582로 분리한 판단 자체는 맞다. Round 1 outcome(040_round1_outcome.md)도 이 residual을 명시해 두었다.

    코드 쪽에서 의심할 곳은 history 가드가 아니라 config/inject의 relabel 단위다. src/codex/inject.ts는 conversation-history relabel unit을 stand down할 수 있고, 그 경로에서 “Existing provider definitions and conversation files were preserved” 메시지를 남기도록 설계돼 있다. src/codex/sync.ts도 relabel이 서면 config만 쓰고 history는 native writer에 맡기는 경고 분기가 있다. 문제는 “preserved”라고 말해도 Codex App이 기대하는 opencodex provider id가 catalog rewrite / metadata relabel 뒤에 실제로 남는지, 아니면 display/catalog 쪽 이름만 바뀌고 클라이언트의 provider 테이블에서 원 id가 빠지는지다. src/server/management/model-routes.ts의 provider not found 404는 관리 API 문자열이고, 이슈 로그의 Model provider opencodex not found 는 Codex App 쪽 메시지로 보이므로 서버 404와 동일 경로로 단정하면 안 된다.

    현재 dev에는 이 이슈를 겨냥한 open PR이 없다. types.ts/config.ts 대분할에 직접 묶인 패치도 아직 없다. 중복 이슈로 보이진 않는다(#4311은 projection 쪽만 닫힘). 우선순위 64는 “이미 닫힌 부모의 잔여를 올바르게 추적 중이고, 기존 스레드 연속 사용을 깨뜨리는 실사용 버그”이지만, 재현 로그·config 스냅샷·relabel 전후 provider 테이블 dump가 아직 없어서 즉시 merge할 패치 후보가 없다는 점을 반영한 값이다.

    경로 src/codex/history-provider.ts / assertLegacyHistoryWritable - #4311 projection 절반은 여기로 이미 닫혔다. 이 이슈의 provider-definition 소실은 이 함수만으로 설명되지 않는다. 수정 타깃을 history 가드에 또 얹지 말 것.
    경로 src/codex/inject.ts / relabel unit stand-down - config는 쓰이고 history relabel은 내려앉는 분기에서 provider definition 테이블이 어떻게 유지·삭제되는지 먼저 확인해야 한다. preserved 문구와 실제 Codex home provider 파일이 일치하는지가 핵심이다.
    경로 src/codex/sync.ts - historyPreflightFailureReason 경고만으로 App이 provider를 잃는다면, 경고 뒤에 provider id rewrite/strip이 있는지 trace가 필요하다.
    심볼 재현 절차 1-4 - 버전을 2.54.0/44027ae5ad로 적었고 현재 패키지는 2.55.0/1dc46f42e다. residual이 HEAD에서도 남는지 한 번 더 확인하는 재현이 필요하다.
    로그 Model provider opencodex not found - App UI 한 줄만 있다. relabel 직전/직후 CODEX_HOME provider/config 파일 목록과 OpenCodex가 쓴 provider id를 붙이지 않으면 원인 분기가 추측으로 남는다.

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

    • 수정 범위를 inject/config provider 유지로 둘지, catalog relabel이 opencodex id를 바꾸는 쪽(이름 매핑)으로 둘지.
    • #4546/#4550처럼 부분 착지 이슈와 같이, 이 residual을 Round 2 레인에 넣을지 백로그로 둘지.
    • 재현이 macOS Codex App 전용인지, CLI/Desktop에서도 provider definition이 같은 방식으로 사라지는지.

    너의 추천
    이슈는 열어 두고, 먼저 HEAD(1dc46f42e)에서 relabel 전후 provider 파일/config id를 덤프하는 재현을 한 번 더 돌린 뒤, inject.ts relabel stand-down 경로와 catalog rewrite가 opencodex provider 엔트리를 지우는지부터 좁혀라. history-provider.ts에 추가 패치를 얹지 말고, 원인 파일에 짧은 fix PR을 dev로 열어라. 중복·대분할 invalidation 이유로 닫지 말 것.

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

  3. luvs01 commented on Sep 14, 2026

    @luvs01
    Collaborator

    There is now a narrowly scoped candidate in #4576, at a5325913c0d2ee97ce4680d7eab438174952bfeb. It covers one concrete way to lose the provider definition: a root-override candidate would remove an existing opencodex table, but paginated history is detected only after the candidate's earlier admission. The patch refuses/compensates that late transition rather than committing table removal after history relabeling stands down.

    The regression cases cover the late transaction stages, coordinated rollback and the permitted provider-table mode. On the current branch the full injection file reports 80 pass, 1 skip and 1 unrelated Windows TOML-path assertion failure (handled separately by #4568). Exact-head CI is running; this is not a claim that the matrix is green.

    This should not close this entire residual issue yet. The candidate proves the late-migration rollback contract, not every catalog rewrite or native App scenario described here, and it does not implement arbitrary provider-table-field retention or full native-writer restore/uninstall support. The original macOS App symptom still needs its before/after config evidence to identify whether it is this path or another one. Keeping that distinction here should avoid rebuilding the already-covered late-transition fix while preserving the broader unresolved report.

  4. lidge-jun commented on Sep 17, 2026

    @lidge-jun
    OwnerAuthor

    Verified against dev@61ee64747b by static source reading. This is already fixed, and it should be closed rather than reimplemented.

    First, what #4311 actually fixed, because this issue is described as its residual and the two are not the same defect. #4311 was closed by #4577 (44027ae5ad), which only taught history preflight to inspect a bounded rollout tail: a newer Codex can migrate a live rollout in place, leaving the original session_meta on line 1 and writing ordinal / history_mode onto later records, so reading line 1 alone missed it (src/codex/history-provider.ts:382). That made the stand-down fire correctly. It did nothing about the provider table.

    The residual was real. Injection detects and strips the existing table to normalize the config (src/codex/inject.ts:311, hadOcxProviderTableOnDisk), so a Design B candidate could be published with no [model_providers.opencodex] definition. If Codex paginated after admission or as the worker started, history relabeling stood down and left rows tagged opencodex pointing at a provider the config no longer defined, which is the reported Model provider opencodex not found.

    It was closed by #4576 (behaviour commit d7128a5101), which restores an existing definition into every root-override candidate before the witness and independently of the preflight result (src/codex/inject.ts:486):

    ~ts if (hadOcxProviderTableOnDisk && !providerTableMode) { content = applyEol( content.trimEnd() + "\n" + buildProviderTableBlockForTarget(routingTarget, websocketsEnabled(config ?? {})), eol, ); } ~

    Those bytes become the admitted candidate (:500) and are written atomically (:590); a later stand-down skips the worker without touching the retained config (:784). The regression matrix in tests/codex-integration/codex-inject-integration.test.ts:218 injects pagination before preflight, after preflight, after config publication, after all artifacts, and in coordinated and authless variants, and every case asserts both halves of the invariant -- the row still reads opencodex and config.model_providers.opencodex.base_url is still present. :266 moves pagination to immediately before the worker and asserts the same thing.

    The mirror-image gap on the way out was closed afterwards by #4896 (dfa02fe96a): restore captures the block before stripping and reattaches it verbatim unless removal was explicitly requested (src/codex/inject/restore.ts:345), asserted at tests/codex-integration/codex-inject-integration.test.ts:655 down to the exact retained lines.

    On the "metadata relabeling" wording specifically: the relabel paths this issue could mean do not write provider definitions at all. src/codex/account-label.ts derives privacy-safe usage labels. Catalog display-name relabeling is display-only and says so at src/codex/catalog/effort.ts:121 -- it "relabels the picker row but never touches the routing slug, alias, or provider" -- and src/server/management/model-routes.ts:460 persists modelDisplayNames and asks for catalog convergence without removing the table. The only path that rewrites it is injection, which is the one #4576 fixed.

    Two adjacent limitations remain, and neither is this issue: apply regenerates the managed table from the current routing target rather than preserving arbitrary extra fields byte-for-byte, and a home already corrupted before these fixes -- opencodex rows with no table on disk -- is not reconstructed, because the retention branch is conditioned on a table having been there. If either matters, they are worth their own issue with that framing.

    No patch is warranted. The regression home already asserts the exact invariant.

  5. lidge-jun commented on Sep 18, 2026

    @lidge-jun
    OwnerAuthor

    Closing as already fixed, with a correction to the attribution in the title.

    The residual was real, but #4311 and #4577 are not where it lived: 44027ae5ad only taught the history preflight to read a bounded rollout tail and touched no provider-table code. The actual defect was that apply stripped the table while normalizing a root-override candidate.

    That was fixed by #4576 (d7128a5101), which rebuilds an existing definition into every candidate before the admission witness and independently of the preflight, and #4896 (dfa02fe96a) closed the mirror-image restore path. The integration matrix asserts both halves of the invariant across seven pagination timings.

    One wording correction so the contract is not over-read: apply retains the definition semantically but regenerates the managed table, so it does not preserve arbitrary custom fields byte for byte. Verbatim retention exists on restore. Two adjacent limitations surfaced while verifying this and are accurate follow-up candidates, but neither is this issue; if either matters to you, a separate report naming it will be easier to act on.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingproxyHTTP proxy, routing, reverse-proxy / management auth

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions