You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: provider definition is lost after metadata relabeling (residual of 4311) #4582
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
Run a Codex App session through the proxy with a provider definition named opencodex.
Relabel provider metadata so the catalog rewrites the provider entry.
Continue the existing thread rather than starting a new one.
The client reports Model provider opencodex not found and the provider definition is gone, even though history now projects correctly after 44027ae.
이 이슈는 이미 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 이유로 닫지 말 것.
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.
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):
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.
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.
Activity
lidge-jun commentedon Sep 14, 2026
리뷰 · 우선순위 64 / 80
이 이슈는 이미 CLOSED된
#4311(paginated Codex history가 provider metadata relabel 뒤 projection을 멈춤)에서 같이 보고됐지만#4577(44027ae5a)이 고치지 않은 두 번째 증상을 따로 빼 둔 residual이다. 지금devHEAD1dc46f42e에는#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이 기대하는opencodexprovider id가 catalog rewrite / metadata relabel 뒤에 실제로 남는지, 아니면 display/catalog 쪽 이름만 바뀌고 클라이언트의 provider 테이블에서 원 id가 빠지는지다.src/server/management/model-routes.ts의provider not found404는 관리 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-#4311projection 절반은 여기로 이미 닫혔다. 이 이슈의 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_HOMEprovider/config 파일 목록과 OpenCodex가 쓴 provider id를 붙이지 않으면 원인 분기가 추측으로 남는다.메인테이너의 판단이 필요한 지점
opencodexid를 바꾸는 쪽(이름 매핑)으로 둘지.#4546/#4550처럼 부분 착지 이슈와 같이, 이 residual을 Round 2 레인에 넣을지 백로그로 둘지.너의 추천
이슈는 열어 두고, 먼저 HEAD(
1dc46f42e)에서 relabel 전후 provider 파일/config id를 덤프하는 재현을 한 번 더 돌린 뒤,inject.tsrelabel stand-down 경로와 catalog rewrite가opencodexprovider 엔트리를 지우는지부터 좁혀라.history-provider.ts에 추가 패치를 얹지 말고, 원인 파일에 짧은 fix PR을dev로 열어라. 중복·대분할 invalidation 이유로 닫지 말 것.이 댓글은 grok-bot이 작성했습니다
luvs01 commentedon Sep 14, 2026
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 existingopencodextable, 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.
lidge-jun commentedon Sep 17, 2026
Verified against
dev@61ee64747bby 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 originalsession_metaon line 1 and writingordinal/history_modeonto 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 taggedopencodexpointing at a provider the config no longer defined, which is the reportedModel 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 intests/codex-integration/codex-inject-integration.test.ts:218injects 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 readsopencodexandconfig.model_providers.opencodex.base_urlis still present.:266moves 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 attests/codex-integration/codex-inject-integration.test.ts:655down 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.tsderives privacy-safe usage labels. Catalog display-name relabeling is display-only and says so atsrc/codex/catalog/effort.ts:121-- it "relabels the picker row but never touches the routing slug, alias, or provider" -- andsrc/server/management/model-routes.ts:460persistsmodelDisplayNamesand 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 --
opencodexrows 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.
lidge-jun commentedon Sep 18, 2026
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:
44027ae5adonly taught the history preflight to read a bounded rollout tail and touched no provider-table code. The actual defect was thatapplystripped 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:
applyretains 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.