Skip to content

fix(grok): clear stale references when excluding managed models #2830

Description

@luvs01

Client or integration

Other (Grok Build)

Area

Catalog / models

Summary

When injectGrokConfig adopts an OpenCodex-owned pre-fence table for a current catalog model, grokExcludedModels intentionally removes that table and emits no replacement. If [models].default or [ui].fork_secondary_model names the removed alias, the reference remains dangling.

This behavior is present on current dev independently of retired-orphan preservation. Keeping the excluded table would violate the user's visibility choice, while choosing an arbitrary remaining model would silently change routing policy.

Expected behavior:

  • Continue removing an explicitly excluded OpenCodex-owned table.
  • When no replacement exists, clear only the two managed reference assignments that name the removed alias so Grok can use its native fallback.
  • Match sections precisely and preserve unrelated keys, user-owned model tables, and unrelated bytes.
  • Do not invent a replacement model.

Reproduction

  1. Start with an OpenCodex-owned Grok table outside the managed fence.
  2. Point [models].default and [ui].fork_secondary_model at that table's alias.
  3. Add the model to grokExcludedModels.
  4. Run Grok configuration synchronization.
  5. Observe that the owned table is removed and no replacement is emitted, while both references still name the removed alias.

A complete regression should also cover all-models-excluded, re-enable, repeated-sync idempotence, quote variants, and unrelated same-named keys.

Version

dev d7a82a8fc42632760750a160c9811543b18bd76d

Operating system

Platform-independent configuration rewrite; reproduced by focused unit fixture on Windows 11.

Provider and model

Any routed model exposed to Grok Build.

Logs

N/A — this is a deterministic configuration transformation.

Redacted configuration

[models]
default = "ocx-example"

[ui]
fork_secondary_model = "ocx-example"

[model.ocx-example]
model = "provider/example"
base_url = "http://127.0.0.1:12345/v1"
api_key = "opencodex-loopback"

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

github-actions commented on Aug 28, 2026

@github-actions
Contributor

Issue reopened

The report now contains the information required by the automated check. Thanks for updating it.

added
bugSomething isn't working
catalogModel catalog, slugs, visibility, routed entries
on Aug 28, 2026

lidge-jun commented on Aug 28, 2026

@lidge-jun
Owner

리뷰 · 우선순위 65 / 80

설명

이 이슈는 Grok Build 설정에서, 사용자가 grokExcludedModels 로 끈 우리 모델 표를 지운 뒤에 [models] default 와 [ui] fork_secondary_model 이 그 사라진 별명을 그대로 가리키는 구멍을 고치자는 말이다. 지금 dev HEAD는 d7a82a8fc 이다. 바로 전에 들어간 #2819 는 키로 빈 exec와 끝난 답을 다시 열지 않는 쪽이고, #2820 은 dest CI다. 이 구멍은 src/grok/inject.ts 의 제외 쓰기와 별명 다시 쓰기라서 축이 다르다. types.ts/config.ts 스플릿에 밀려 닫을 대상이 아니다. 열린 #2828 은 은퇴한 고아 표를 남기는 쪽이고, 이 이슈는 지금 카탈로그에 있는데 사용자가 끈 표를 지운 뒤 참조만 치우는 쪽이다. 반대 방향이라 중복이 아니다.

지금 HEAD의 동작은 이렇다. src/grok/sync.ts 는 보이는 모델 전체를 넘기고, 끈 아이디는 excluded 집합으로 따로 넘긴다. buildGrokManagedBlock 은 끈 아이디도 별명 자리를 쓰지만 표는 안 쓴다. 울타리 밖에 우리 api_key 와 루프백 base_url 을 가진 표가 있으면 findOpencodexOrphans 가 모아 removeOrphanTables 로 지운다. 그 다음 rewriteAliasReferences 가 default 와 fork_secondary_model 을 살아남은 별명으로 옮긴다. 문제는 대체 표가 없을 때다. 418–420행 주석은 대체할 표가 없으면 참조를 건드리지 말라고 한다. 낡은 이름이 남는 편이, 없는 이름을 가리키는 것보다 낫다는 뜻이다. 은퇴 표를 남기는 #2828 에서는 그 말이 맞다. 제외는 표를 일부러 안 쓰므로, 참조를 그대로 두면 없는 모델을 가리킨다. 그게 이 이슈의 재현이다.

작성자가 원하는 고침은 범위가 좁다. 끈 우리 표는 계속 지운다. 대체 표가 없으면 [models] default 와 [ui] fork_secondary_model 두 칸만, 지운 별명을 가리킬 때 그 한 줄을 지운다. 다른 칸, 사람이 쓴 표, 같은 이름의 다른 키는 그대로 둔다. 남은 모델 하나를 마음대로 기본값으로 넣지 않는다. 그게 맞다. 아무 모델이나 기본값으로 넣으면 라우팅이 몰래 바뀐다. 참조를 비우면 Grok이 자기 기본값으로 돌아간다.

테스트가 이 구멍을 안 본다. tests/grok-selection.test.ts 는 끈 표가 안 쓰이는지만 본다. default 나 fork_secondary_model 은 안 넣는다. tests/grok-orphan-adoption.test.ts 는 표가 살아남거나 다른 별명으로 옮겨지는 경우만 본다. 그래서 HEAD에서도 테스트는 초록이고, 참조가 허공에 남는 사고는 드러나지 않는다. 작성자가 적은 회귀는 전부 필요하다. 모델을 전부 끈 경우, 다시 켠 경우, 두 번째 동기화가 그대로인지, 따옴표 종류, 같은 이름인데 다른 칸에 있는 키.

한 가지 더 있다. rewriteAliasReferences 는 고아 표가 하나라도 있을 때만 돈다. 대시보드에서 울타리 안 표만 끈 경우에는 고아가 없으니 참조를 아예 안 본다. 그 길이 더 흔하다. PR은 울타리 밖 입양만이 아니라, 울타리 안 표를 끈 경우도 같이 봐야 한다.

라인 src/grok/inject.ts 320 - excluded면 표를 안 쓴다. 의도는 맞다. 참조 정리는 여기 없다.
라인 src/grok/inject.ts 418–436 - 고아가 있을 때만 다시 쓰고, 대체 별명이 있을 때만 옮긴다. 대체 없으면 참조가 남는다. 418–420행 주석이 이 제외 경로에서는 틀린 말이다.
라인 src/grok/inject.ts 250–258 rewriteAliasReferences - 큰따옴표만 보고, [models]/[ui] 칸인지는 안 본다. 다른 칸의 default = 도 같이 바뀔 수 있다. 참조를 지우는 기능도 없다.
경로 tests/grok-selection.test.ts - 제외 테스트가 표 생략만 본다. 기본값 참조는 없다.
경로 #2828 - 은퇴 표를 남긴다. 이 이슈와 파일이 같다. 같이 머지하면 충돌할 수 있다. 닫을 중복은 아니다.

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

  • #2828을 먼저 넣을지, 이 이슈 PR과 한 열차로 넣을지.
  • 울타리 안만 끈 경우도 같은 PR에서 참조를 지울지.
  • 참조를 지울 때 그 한 줄만 지울지. 작성자는 한 줄만이라고 했다.

너의 추천
열어 두어라. #2828과 중복으로 닫지 마라. 고침은 src/grok/inject.ts에서 대체 표가 없을 때 두 참조만 지우는 쪽이다. 아무 모델로 채우지 마라. 테스트에 전부 제외, 다시 켜기, 두 번째 동기화, 따옴표, 다른 칸 같은 이름을 넣어라. #2828이 먼저 들어가면 그 위에 리베이스하면 된다. types/config 스플릿 때문에 닫지 마라.

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

lidge-jun commented on Aug 28, 2026

@lidge-jun
Owner

Fixed on dev by merge commit 2a44e3a (PR #2846).

When a managed model is excluded and has no replacement, its model table was deleted while references to it were left pointing at nothing. References are now cleared across every shape the current Grok Build configuration can express — the five models.* pins, the UI fork selector, subagents.models.*, subagents.roles.*.model, subagents.personas.*.model, the auto classifier, and the three goal-role shapes.

The reference cleanup also no longer depends on a non-empty orphan list; it compares the previous and replacement managed blocks directly, so it runs on the normal exclusion path. That gating bug meant the first version of the fix never actually executed.

Verified with a 13-shape behavioral matrix in tests/grok-orphan-adoption.test.ts driven RED (dangling references present) then GREEN (zero), plus tests/grok-sync.test.ts and tests/native-grok-toggle.test.ts — 80 pass, 0 fail. The matrix doubles as a ratchet: a new reference field that is not declared will fail it.

Credit to @luvs01, whose #2828 carried the orphan-table preservation this builds on. That PR targeted dev, so GitHub did not auto-close this issue — closing manually.

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 workingcatalogModel catalog, slugs, visibility, routed entries

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions