Skip to content

refactor(codex): split inject and catalog sync behind facades - #4643

Merged
lidge-jun merged 8 commits into
codex/m2k-l3-state-shimfrom
codex/m2k-l4-inject-sync
Sep 14, 2026
Merged

lidge-jun merged 8 commits into
codex/m2k-l3-state-shimfrom
codex/m2k-l4-inject-sync

Conversation

@lidge-jun

Copy link
Copy Markdown
Owner

Summary

src/codex/inject.tssrc/codex/catalog/sync.ts를 파사드로 남기고 리프로 나눈다. 순수 이동이며 로직·식별자·문자열을 바꾸지 않았다. 두 파일의 공개 export 표면은 이동 전과 같다.

파일 새 리프
src/codex/inject.ts 2,342 987 inject/routing-target.ts 125, inject/routing-classify.ts 109, inject/remove.ts 194, inject/config-toml.ts 563, inject/restore.ts 538
src/codex/catalog/sync.ts 2,698 52 catalog/subagent-roster.ts 175, catalog/derive-entry.ts 229, catalog/gated-native-warn.ts 63, catalog/restore.ts 132, catalog/auto-review.ts 506, catalog/retained-sync.ts 703, catalog/build-entries.ts 981

sync.ts가 52줄 순수 파사드가 된 것은 계획보다 더 나눈 결과다. retained-sync가 build/merge 심볼 다섯을 쓰는데 파사드가 retained-sync를 재수출하므로 build/merge를 sync.ts에 남기면 순환이 확정된다. 그래서 build-entries.ts를 함께 뽑았다.

불변식 승계를 명시한다. INV-TOML-01은 루트키 선삽입 로직을 가져간 inject/config-toml.ts가, INV-AGENT-01은 catalog/subagent-roster.ts가 승계하고 각 파일 헤더에 id 주석을 옮겼다.

본문을 텍스트로 읽는 오라클 세 곳을 같이 고쳤다. 인라인 syncCodexHistoryProvider 호출이 파사드에서 inject/restore.ts로 옮겨갔기 때문에 codex-history-reachability.test.tsINLINE_ALLOWED를 바꾸지 않으면 그 테스트는 반드시 실패한다. codex-retained-root-serialization.test.ts의 슬라이스 대상도 restore.ts로 옮겼고, codex-inject-history-wording.test.ts는 리터럴 여섯이 파사드와 restore.ts로 갈라져 두 파일을 이어 읽게 했다.

catalog/effort.tsderiveEntry import는 호출 사이트가 없는 죽은 줄이었고, 남겨두면 effort → sync(파사드) → derive-entry 순환이 되므로 지웠다.

Verification

  • bun scripts/structure-ssot.tsstructure/ SSOT checks passed (subagents.md, catalog.md의 백틱 경로를 새 소유 모듈로 교체한 뒤)
  • bun scripts/file-size-ratchet.tsfile-size ratchet passed
  • Bun.Transpiler 구문 검사 통과
  • 파사드 export 표면 대조(origin/dev 기준): inject.ts 35 → 35, catalog/sync.ts 31 → 31, 누락 0
  • 로컬 typecheck·full suite·install은 실행하지 않았다. 타입 해석과 런타임 회귀는 이 PR head의 hosted CI가 증거다.

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.

Pure move. inject.ts 2342 -> 987 with five leaves, catalog/sync.ts 2698 -> 52 with seven leaves. INV-TOML-01 moves to inject/config-toml.ts and INV-AGENT-01 to catalog/subagent-roster.ts. Three source oracles that read these files as text are repointed in the same commit.
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 14, 2026 15:53
@coderabbitai

coderabbitai Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (2)
  • ^dev$
  • ^preview$

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: f94fedb6-dd70-466e-9fae-a76385bb6291

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 14, 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-14T15:59:09.469415Z c63e9ea PR opened
ℹ️ 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.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the chore Maintenance, CI, tests, refactors, or build changes (not a user-facing bug or feature). label Sep 14, 2026

@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: c63e9ea676

ℹ️ 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 thread src/codex/inject/restore.ts Outdated
@@ -0,0 +1,539 @@
import { loadConfig, shouldSyncCodexOnStart } from "../../config";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Import the restore gate from desired-state

When any caller imports src/codex/inject.ts, its new re-export instantiates this module, but src/config.ts does not export shouldSyncCodexOnStart; that function is defined in src/codex/desired-state.ts. Bun/TypeScript therefore rejects the module before CLI startup or native restoration can run. Import loadConfig from ../../config and shouldSyncCodexOnStart from ../desired-state.

AGENTS.md reference: AGENTS.md:L373-L375

Useful? React with 👍 / 👎.

Comment thread src/codex/inject/remove.ts Outdated
OCX_SECTION_MARKER,
REALTIME_WS_BASE_URL_KEY,
hasInjectedOpenaiBaseUrl,
readRootTomlString,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Import the TOML reader from paths

The inject.ts facade re-exports this module, but injected-marker.ts has no readRootTomlString export; the helper remains exported by src/codex/paths.ts. Consequently, importing the facade fails during ESM linking even for callers that do not invoke removal. Move this named import to ../paths.

AGENTS.md reference: AGENTS.md:L373-L375

Useful? React with 👍 / 👎.

Comment thread src/codex/catalog/derive-entry.ts Outdated
} from "./parsing";
import type { CatalogModel, RawEntry } from "./parsing";
import {
applyNativeOpenAiContextOverride,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Import the context override from catalog parsing

Loading src/codex/catalog/sync.ts instantiates this extracted module, but metadata.ts does not export applyNativeOpenAiContextOverride; the function is still exported from catalog/parsing.ts. This invalid named import makes catalog sync fail at module linking before any catalog can be built, so source the helper from ./parsing.

AGENTS.md reference: AGENTS.md:L373-L375

Useful? React with 👍 / 👎.

Comment thread src/codex/catalog/build-entries.ts Outdated
CODEX_NATIVE_ALIAS_CATALOG_KIND,
NATIVE_OPENAI_MODELS,
SUPPORTED_NATIVE_OPENAI_SLUGS,
applyNativeOpenAiContextOverride,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Source the build-time context override from parsing

This second extracted catalog module also imports applyNativeOpenAiContextOverride from metadata.ts, which has no such export; its definition remains in parsing.ts. Even after correcting derive-entry.ts, the sync.ts facade will still fail to instantiate because it re-exports build-entries.ts, so move this import to ./parsing as well.

AGENTS.md reference: AGENTS.md:L373-L375

Useful? React with 👍 / 👎.

Comment thread src/codex/catalog/retained-sync.ts Outdated
import { loadConfig, websocketsEnabled } from "../../config";
import { shouldSyncCodexOnStart } from "../desired-state";
import { legacyCustomModelCatalogSlugs } from "../custom-model-catalog-migration";
import { activeCodexModelsCachePath, getCodexHome, readCodexCatalogPath, readCodexCatalogPathForHome } from "../paths";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Import retained catalog path helpers from parsing

For every retained catalog sync, this module requests activeCodexModelsCachePath, readCodexCatalogPath, and readCodexCatalogPathForHome from src/codex/paths.ts, but all three are exported by catalog/parsing.ts instead. The missing named exports prevent the catalog facade from loading; keep only getCodexHome on this import and source the three catalog helpers from ./parsing.

AGENTS.md reference: AGENTS.md:L373-L375

Useful? React with 👍 / 👎.

Comment thread src/codex/catalog/retained-sync.ts Outdated
observedReserveCatalogSource,
shouldIncludeAccountBoundNativeOpenAi,
shouldIncludeNativeOpenAi,
trustedAccountBoundNativeCatalogSlug,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Import the retained-sync account helper from account-models

metadata.ts imports trustedAccountBoundNativeCatalogSlug for its own use but does not re-export it; the public definition remains in account-models.ts. Thus this named import independently prevents retained-sync.ts and the catalog/sync.ts facade from linking. Add the helper to the existing ./account-models import instead.

AGENTS.md reference: AGENTS.md:L373-L375

Useful? React with 👍 / 👎.

Comment thread src/codex/catalog/subagent-roster.ts Outdated
import { slugsEquivalent } from "../../providers/slug-codec";
import { readCatalog, readCodexCatalogPath } from "./parsing";
import type { RawEntry } from "./parsing";
import { SUPPORTED_NATIVE_OPENAI_SLUGS, trustedAccountBoundNativeCatalogSlug } from "./metadata";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Import the roster account helper from account-models

The roster extraction requests trustedAccountBoundNativeCatalogSlug from metadata.ts, but that module does not export it; it is exported by account-models.ts. Because catalog/sync.ts re-exports this roster module, the invalid import breaks all consumers of the catalog facade, not only callers of effectiveSubagentRoster. Source the helper from ./account-models.

AGENTS.md reference: AGENTS.md:L373-L375

Useful? React with 👍 / 👎.

@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 50 / 80

이 PR은 제품 기능을 바꾸려는 것이 아니라, godfile round2 사이클 3에서 이미 약속한 대로 src/codex/inject.ts(지금 dev에서 2,342줄)와 src/codex/catalog/sync.ts(2,698줄)를 파사드 + 리프 모듈로 나누는 순수 이동이다. 작성자가 밝힌 대로 로직·식별자·문자열을 바꾸지 않았고, 공개 export 표면은 이동 전과 같다 (inject 35→35, sync 31→31; 심볼 집합으로 대조해도 inject 44/44·sync 41/41로 누락·추가가 없다).

지금 dev HEAD는 627274b8f이고, 방금 올라온 tip은 #4546 비용 가드 스택의 wpc(#4624 identity domains) → wpe(#4625 spend ledger) → wpf(#4626 half-open probe lease / Retry-After)다. 패키지는 2.56.0이고 epic #4546은 아직 OPEN이며 다음 층은 wpd/wpa/wpb/wpg다. 이 PR은 그 라우팅 레인과 직교한다. 같은 시각에 열린 m2k 스택 (#4635 로드맵 → #4636 파일 크기 래칫 → #4642 state/shim 파사드 → #4643 inject/sync 파사드)의 사이클 3 실행물이다. base는 dev가 아니라 codex/m2k-l3-state-shim(#4642)이므로, 단독으로 dev에 올릴 수 있는 PR이 아니다.

나눈 모양은 030 계획과 맞다. inject 쪽은 inject/routing-target.ts(125) · routing-classify.ts(109) · remove.ts(194) · config-toml.ts(563) · restore.ts(539)이고, 파사드 잔여는 987줄이다 (계획의 injectCodexConfigImpl 723줄을 이 사이클에서 더 쪼개지 말라는 금지와도 맞다). catalog 쪽은 subagent-roster.ts(175) · derive-entry.ts(229) · gated-native-warn.ts(63) · restore.ts(132) · auto-review.ts(506) · retained-sync.ts(703) · build-entries.ts(981)이고, sync.ts는 52줄 순수 재수출 파사드가 됐다. retained-sync가 build/merge를 쓰는데 파사드가 retained-sync를 재수출하면 순환이 생기므로 build-entries를 같이 뽑은 판단은 030 정정 문단과 같다.

불변식도 계획대로 옮겼다. INV-TOML-01 헤더는 inject/config-toml.ts 첫 줄로, INV-AGENT-01은 catalog/subagent-roster.ts 첫 줄로 갔다. 본문을 텍스트로 읽는 오라클 세 곳도 같이 고쳤다. INLINE_ALLOWED는 인라인 syncCodexHistoryProvider 호출이 파사드에 더 이상 없으므로 codex/inject/restore.ts로 바꿨고, retained-root 직렬화 슬라이스 대상도 restore.ts로, history-wording은 파사드+restore를 이어 읽게 했다. effort.ts의 죽은 deriveEntry import는 경로만 바꾸면 effort↔derive-entry 순환이 남으니 삭제한 것도 맞다. 테스트 훅 setBeforeRestoreConfigForTests / setHistoryArtifactStageForTests / setBeforeHistoryArtifactCommitForTests는 소유 모듈에 두고 파사드가 재수출한다.

형제 #4642와 비교하면 이 PR은 hygiene가 이미 통과했다(src+테스트 오라클이 한 커밋에 들어갔다). 다만 Cross-platform CI의 test/gates/keyring 등은 아직 pending이고 mergeStateStatus는 UNSTABLE이다. 작성자도 로컬 typecheck·full suite·install은 돌리지 않았고 hosted CI를 증거로 둔다고 했다. types.ts/config.ts 분할 캠페인과는 겹치지 않는다(여기는 inject/catalog sync 분해). close-don't-rebase 대상도 아니다. 다만 파일 크기 래칫 기준선(tests/fixtures/file-size-baseline.json)은 이 PR write set에 없다. 래칫이 통과한 것은 맞고, inject/sync가 SHRANK로 잡히지만, --update로 캡을 내려 커밋하지 않으면 파사드가 다시 2,342·2,698까지 커져도 GREW가 안 난다. 쪼개기 승리를 잠그려면 기준선 하향이 같은 스택에 따라와야 한다.

경로 tests/fixtures/file-size-baseline.json - 이 PR write set에 없음. inject.ts/sync.ts 줄 수 감소가 래칫 캡에 반영되지 않아, 쪼개기 후에도 예전 상한(2342/2698)까지 다시 커질 수 있다. bun scripts/file-size-ratchet.ts --update 결과를 같은 스택(또는 직후 PR)에 넣어야 승리가 잠긴다.
경로 structure/config.md:277 / structure/catalog.md:325 / structure/subagents.md:346 - 히스토리 writer 문단이 아직 src/codex/inject.ts만 가리킨다. 030 계획은 restore 본문이 옮긴 뒤 inject.tsinject/restore.ts를 병기하라고 했다. catalog.md·subagents.md의 auto-review/roster 백틱은 고쳤지만 이 세 문장은 빠졌다.
경로 structure/config.md:75 - 공개 inject 동작이라 facade 경로를 유지해도 되지만, 030은 루트 키 배치 소유를 inject/config-toml.ts로 병기할 수 있다고 적었다. INV-TOML-01을 옮긴 김에 한 줄만 보태 두면 문서와 헤더 id가 같은 파일을 가리킨다.
경로 tests/providers/cursor/cursor-display-names.test.ts 주석 - 여전히 routedDisplayName (codex/catalog/sync.ts)라고 적혀 있다. 심볼은 derive-entry.ts로 옮겼고, 030도 주석 경로를 같이 고치라고 했다. 기계 오라클은 아니지만 다음 읽는 사람을 헷갈리게 한다.
경로 src/codex/catalog/build-entries.ts (981줄) / src/codex/inject.ts 잔여(987줄) - 둘 다 2,000 미만이라 래칫 NEW_OK/SHRANK에는 들어가지만, 여전히 큰 편이다. injectCodexConfigImpl을 더 쪼개지 말라는 금지는 지키되, build-entries는 다음 라운드 후보로 이름을 남겨 두는 편이 좋다.
CI / enforce-target - Cross-platform test·gates가 아직 pending이고, base가 dev가 아니라 스택 PR이라 enforce-target은 형제들과 같이 실패할 가능성이 크다. 머지 판단은 #4635#4636→#4642가 dev에 오른 뒤, 이 head를 retarget하거나 merge-train으로 묶은 다음에 해야 한다.

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

너의 추천
닫지 말고 스택을 유지한다. 우선 #4635#4636→#4642가 dev에 안정적으로 오른 뒤 이 PR을 이어서 머지한다. 머지 전에 (1) hosted CI(test/gates) 초록을 확인하고, (2) file-size-ratchet.ts --update로 inject/sync 캡을 내린 기준선 커밋을 같은 스택에 넣으며, (3) structure 히스토리 writer 세 문단과 cursor-display-names 주석만 짧게 고친다. types/config 분할과 무관하고 중복도 아니므로 close-don't-rebase 대상이 아니다. 우선순위 50 — 분해 방향·오라클·INV·export 패리티는 탄탄하고 hygiene도 통과했지만, 스택 의존·CI pending·래칫 캡 미잠금 때문에 지금 당장 merge train 맨 앞에 두지는 않는다.

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

Pure move. routing.ts 3507 -> 1475 with six leaves, quota.ts 3313 -> 558 with five leaves. Dispatchers that would close a cycle stay on the facade. Retry budget scope is unchanged; no new attempt counter exists in any leaf.
The inject and catalog leaves imported six symbols from modules that never exported them. Each one is re-pointed at where it is actually defined: parsing, account-models, subagent-roster, paths, desired-state. Import paths only; no declaration moved.
…ta split

Fifteen symbols lost their binding: leaves that defined a symbol never exported it, quota type imports pointed at src/types instead of providers/quota-types, and isModelDetourAffinityScope lost its definition entirely while its call site survived. Imports and exports only; no declaration was moved or rewritten.
@lidge-jun lidge-jun added the test-exception-approved Maintainer approved a non-automated regression-test exception label Sep 14, 2026
lidge-jun and others added 2 commits September 15, 2026 01:44
The leaf sits one directory deeper than routing.ts, so ../config resolved to src/codex/config, which does not exist. Every test shard that loaded the routing graph failed at import time.
refactor(codex,providers): split routing and quota behind facades
@github-actions github-actions Bot removed the test-exception-approved Maintainer approved a non-automated regression-test exception label Sep 14, 2026
@lidge-jun
lidge-jun merged commit 60d935f into codex/m2k-l3-state-shim Sep 14, 2026
27 checks passed
@lidge-jun
lidge-jun deleted the codex/m2k-l4-inject-sync branch September 14, 2026 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Maintenance, CI, tests, refactors, or build changes (not a user-facing bug or feature).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant