Skip to content

Commit 7132828

Browse files
committed
merge: the 260731 PR round into dev
Brings in the round staged on codex/260731-pr-merge-round: six contributor PRs landed as squashes, five defects rebuilt where the contributor's implementation no longer fit the tree, and the devlog unit recording every decision. One real conflict, in src/lib/provider-outbound.ts. Both sides fixed lidge-jun#758 independently and arrived at the same design -- even the same helper name, providerAllowsPrivateNetwork. dev's shorter form is kept; the branch's comment explaining WHY the registry default has to be consulted at the fetch boundary is kept with it, since that is the part a future reader needs. The duplicate helper auto-merge produced in destination-policy.ts is collapsed to dev's implementation. The branch's SSRF negative tests survive alongside dev's positive one: dev proves Ollama can now reach loopback, and the branch proves it still cannot reach metadata, link-local or unspecified addresses. Those are different questions and both are worth pinning. Also renames 040_round_outcome.md to 050 -- the branch and dev each added an 040 in this unit.
2 parents afe2aa3 + d380b1b commit 7132828

46 files changed

Lines changed: 2572 additions & 158 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# 000 — 열린 PR 43건 머지 판단
2+
3+
로컬 `dev`는 성능 최적화 유닛이 진행 중이라 손댈 수 없다. 그래서 이번 라운드는
4+
`dev`에 직접 올리지 않고 **스테이징 브랜치**에 쌓는다. 최적화 작업이 끝나면
5+
사용자가 이 브랜치를 `dev`로 머지하고 릴리스한다.
6+
7+
- 워크트리: `/Users/jun/.codex/worktrees/260731-merge/opencodex`
8+
- 브랜치: `codex/260731-pr-merge-round`
9+
- 기준: `origin/dev = 356924263` (2026-07-31 재측정)
10+
- 금지: `dev` / `main` / `preview` 푸시, npm 배포, 버전 bump
11+
12+
메인 체크아웃(`/Users/jun/Developer/new/700_projects/opencodex`)에는 커밋되지 않은
13+
파일 22개가 있다. 이 라운드의 실패 조건 1번은 그 파일들이 스테이징되거나 사라지는
14+
것이다. 배치마다 `git status --porcelain`으로 확인한다.
15+
16+
## 이 저장소의 머지 컨벤션 (이력에서 추출)
17+
18+
세 가지 형태가 실제로 쓰이고 있다. 커밋 이력에서 직접 확인한 것만 적는다.
19+
20+
| 형태 | 예시 | 언제 쓰이나 |
21+
|---|---|---|
22+
| GitHub 기본 머지 커밋 | `Merge pull request #773 from Wibias/fix/735-openai-chat-eof` (`5718d44e1`) | 웹 UI에서 머지할 때 |
23+
| 손으로 쓴 머지 커밋 | `merge: PR #737 — tolerate late proxy readiness (#720)` (`62e937614`) | 메인테이너가 CLI로 머지할 때. 이슈 번호를 괄호로 단다 |
24+
| 스쿼시 | `fix(cursor): add kimi-k3 with low/high/max effort tiers (#646)` (`275345a61`) | 기여자 PR을 한 커밋으로 접을 때 |
25+
26+
스쿼시가 지배적이다. 최근 300커밋 중 머지 커밋은 25개이고 나머지 275개는 전부
27+
`type(scope): subject` 단일 부모 커밋이다.
28+
29+
**기여자 크레딧**: 스쿼시할 때 원저자를 `--author`로 유지하거나 `Co-authored-by`
30+
트레일러를 단다. 최근 300커밋에 23건 있다(본문 기준 22건 + 머지 커밋 1건).
31+
`275345a61`은 기여자를 author로 두고
32+
메인테이너를 `Co-authored-by`에 넣었다 — 기여자 PR 위에 수정을 얹은 경우다.
33+
`d24c5233f`는 반대로 메인테이너가 author, 기여자가 `Co-authored-by`다.
34+
이번 라운드는 후자를 쓴다. 브랜치에서 재작성하는 건이 많기 때문이다.
35+
36+
**커밋 메시지 본문**: 이 저장소는 본문을 길게 쓴다. 무엇이 왜 깨졌는지, 어떤
37+
측정을 했는지, 무엇이 반증됐는지까지 적는다(`1a46299b5`, `c777c8e76` 참고).
38+
한 줄 요약만 있는 커밋은 이 저장소의 관행이 아니다.
39+
40+
**CI 게이트** (`AGENTS.md` + `MAINTAINERS.md`):
41+
42+
- PR 타깃은 `dev`만. `enforce-target``main` 조상 위에 있으면서 `dev`보다 한참
43+
뒤처진 PR과 빈약한 설명을 거부한다.
44+
- 인증/자격증명/OAuth/Actions/릴리스 자동화/의존성 설치를 건드리면 **명시적 보안
45+
리뷰**가 필요하다.
46+
- 새 provider preset은 자격증명 목적지 변경이다. 문서화된 엔드포인트, ToS와 법인,
47+
중개업체면 재판매·라우팅 권한, 유지보수 담당자, 인용 가능한 검증 날짜가 있어야
48+
canonical 등록이 된다. 증거가 부족하면 `free-directory.ts`의 비활성 행으로.
49+
- `bun run typecheck`, `bun run test`, `bun run privacy:scan`이 게이트다.
50+
51+
## 판정 매트릭스
52+
53+
terra 서브에이전트 4개를 겹치지 않는 슬라이스로 병렬 파견해 각 PR을 **현재 HEAD
54+
코드와 직접 대조**했다. PR 설명은 근거로 인정하지 않았고, `git cherry`와 patch-id로
55+
이미 HEAD에 있는지부터 확인했다. 아래 SHA는 전부 내가 직접 재확인했다.
56+
57+
### 이미 dev에 들어간 것 — 닫는다 (7건)
58+
59+
같은 수정이 다른 커밋으로 이미 랜딩됐다. 지금 머지하면 **더 새로운 코드를 되돌린다.**
60+
61+
| PR | HEAD의 해당 커밋 | 이슈 |
62+
|---|---|---|
63+
| #736 Windows 서비스 상태 locale 독립 | `1d9e196e7` | #722 FULL |
64+
| #752 tray host 소켓 상속 차단 | `c1ecbe1b5` | #733 FULL |
65+
| #743 discovery 경로 하드닝 | `fd1933099` | #572 PARTIAL |
66+
| #610 `codex --version` 프로브 캐싱 | `716f39cb6` | #606 FULL |
67+
| #734 `OPENCODEX_BUN_PATH` 존중 | `9b5c864ff` + `f81e98aca` | #721 FULL |
68+
| #777 catalog video modality | `e64a00e9f` (+ `7a041e2bc`, `299f35dc9`) | #759 PARTIAL |
69+
| #533 npm 캐시 복구 | #557이 같은 14커밋 + 후속 2건 ||
70+
71+
#736이 대표적인 함정이다. HEAD는 `decodeSchtasksOutput()`로 schtasks의 UTF-16LE
72+
출력을 디코딩하는데(`src/service.ts:364-393`), PR head를 머지하면 그 블록이 통째로
73+
삭제되고 `encoding: "utf8"`로 되돌아간다. "CLEAN하게 머지된다"가 "머지해도 된다"를
74+
뜻하지 않는다는 걸 보여주는 사례다.
75+
76+
#734는 이전 라운드가 macOS `/var` vs `/private/var` 테스트 실패 때문에 뺐던
77+
건인데, `f81e98aca``realpathSync`로 그 테스트를 고쳤다. 이제 8/8 통과한다.
78+
79+
#533은 결함이 남아 있지만 #557이 같은 커밋 시리즈에 하드닝 2건을 더 얹은
80+
후속이다. 둘 다 열어둘 이유가 없다.
81+
82+
### 이번 브랜치에 태울 것 (배치 A, 6건)
83+
84+
HEAD에 결함이 남아 있고, 보안 경계를 넓히지 않으며, 실패하는 회귀 테스트를
85+
가져오는 건들이다. 전부 재기준(restack)이 필요하다 — 76커밋 이상 뒤처져 있다.
86+
87+
| PR | 내용 | 이슈 | 손봐야 할 것 |
88+
|---|---|---|---|
89+
| #772 | `GET /api/catalog` | #709 FULL | restack만 |
90+
| #774 | `ocx init` 파이프 stdin EOF 무한루프 | #754 FULL | restack만 |
91+
| #783 | Claude Desktop 모델 목록에서 `native/*` 제외 | #767 FULL | restack만 |
92+
| #768 | Kiro Windows 실행파일 PATH 해석 || 디렉터리/비실행 파일 거부 추가 |
93+
| #781 | Anthropic `/v1/messages` baseUrl 중복, 스트림 quirk | #765 PARTIAL | 문자열 `tool_use.input` 정규화, 죽은 `sawContent` 제거, **`/api/logs` 봉투 테스트 헬퍼 분리** |
94+
| #769 | Baseten free-directory 행 || 없음 (canonical 아님) |
95+
96+
#772#783`src/codex/catalog.ts`에서 충돌한다. `readCatalog`
97+
`desktopVisibleNativeSlugs` export를 둘 다 살려야 한다.
98+
99+
**감사가 잡아낸 것 — #744를 배치 A에서 뺀다.** 이 PR은 OAuth 재조정을 바꾸고
100+
provider 설정을 영속화하며 토큰 해석 순서를 static 분기 앞뒤로 옮긴다
101+
(`59d95c0e4`, `39543a3c0`). `MAINTAINERS.md` 기준 명시적 보안 리뷰 대상이다.
102+
"카탈로그를 static으로 고정한다"는 요약이 그 사실을 가렸다. 보류로 옮긴다.
103+
104+
**#781도 그대로 못 태운다.** 토픽 커밋 `70031f470`이 Anthropic 코드와 함께
105+
`/api/logs` 테스트를 `logsFromApiBody`로 갈아끼운다. 그 헬퍼(`2f6c031cc`,
106+
`tests/helpers/logs-api.ts`)는 배열과 `{logs}` 봉투를 **둘 다** 받아준다 — 배치 B가
107+
거부하기로 한 바로 그 봉투 계약을 테스트 쪽에서 미리 받아들이는 것이다.
108+
Anthropic 변경만 떼어내고 HEAD의 배열 단언은 그대로 둔다.
109+
110+
### 브랜치에서 다시 만들 것 (배치 B, 3건)
111+
112+
결함은 진짜인데 구현이 지금 트리와 맞지 않는다. 기여자 커밋을 그대로 태우면
113+
회귀가 난다. `Co-authored-by`로 크레딧을 유지하며 재작성한다.
114+
115+
- **#790 / #784 — 대시보드 로그.** 둘 다 `/api/logs`를 배열에서
116+
`{timeZone, logs}` 봉투로 바꾼다. 그 계약 변경이 배열을 가정한 기존 소비자를
117+
깬다: `tests/server-auth.test.ts:1623`, `tests/claude-native-passthrough.test.ts:119`,
118+
`tests/openai-provider-option-e2e.test.ts:489`, GUI mock 다수. 게다가 #790
119+
고친 유일한 테스트는 두 형태를 모두 허용해서 **패치 없이도 통과한다.**
120+
배열 계약을 유지하고 타임존은 응답 헤더로 나르는 쪽으로 재작성한다.
121+
#726(200건 상한)과 #725(타임존)를 함께 닫는다.
122+
- **#771 — Windows autostart Run 260자 초과.** VBS 런처 방향은 맞다.
123+
`tests/windows-tray.test.ts` import 충돌만 있고 나머지는 깨끗하다. #696 FULL.
124+
- **#780 — Windows 스케줄러 stop.** 진단이 얕다. 패치는 `schtasks /end`
125+
**실패할 때만** 6.5초 기다린다. 그런데 보고된 실패는 `/end`가 성공했는데 래퍼가
126+
살아남아 5초 뒤 자식을 재생성하는 경우다. 즉 이 패치로도 여전히 거짓 성공을
127+
보고한다. 재시작 창을 통과할 때까지 검증하도록 다시 만든다. #764 PARTIAL.
128+
129+
### 보류 (증거·리뷰 대기)
130+
131+
**보안 리뷰가 필요한 건**`MAINTAINERS.md`가 요구하는 명시적 보안 리뷰는
132+
메인테이너 판단이다. 내가 대신할 수 없으므로 브랜치에 태우지 않고 근거만 남긴다.
133+
134+
- #782 admin token ACL opt-in. 그리고 버그가 하나 있다: 디렉터리 하드닝이 soft
135+
continue할 수 있는데(`management-auth.ts:61-65`) 그 결과가 버려져서
136+
`/api/settings``aclUnverified: false`를 보고할 수 있다. 파일 하드닝만
137+
상태를 세운다. 이건 리뷰 전에 고쳐야 한다.
138+
- #744 Antigravity static 고정. OAuth 설정 영속화와 토큰 해석 순서 변경.
139+
- #750 Codex 계정 풀 plan 영속화. 자격증명·토큰 회전 경합·계정 상태 영속화.
140+
- #746 GitHub Copilot Responses 라우팅. OAuth 갱신과 키 풀 복구 경로.
141+
- #644 Windows tray가 활성 Codex home을 따라가게. draft이고
142+
`.github/workflows/pr-labeler.yml`까지 건드린다 — Actions 변경은 보안 리뷰 대상.
143+
게다가 `.codexclaw/goalplans/**``devlog/.DS_Store`가 diff에 들어 있다.
144+
저장소 위생 문제라 그대로는 못 받는다.
145+
- #779 TLS 종단 Origin scheme skew. 분석상 인증 우회는 없다 —
146+
`requireManagementAuth`가 먼저 돌고(`index.ts:391`) 세션 경로는 여전히
147+
origin 완전 일치와 CSRF를 요구한다(`management-auth.ts:205`). 그래도 CORS 수용
148+
범위를 넓히는 변경이라 리뷰 대상이다.
149+
- #775 Ollama private-network discovery (SSRF/destination policy).
150+
- #778 doctor의 provider API key 진단 (자격증명 취급).
151+
- #693 A6API 크레딧 (Bearer 키를 새 목적지 2곳으로 보낸다).
152+
- #616 hosted image tool (management validation 변경).
153+
154+
**provider preset — 증거 미달**: #751(증거는 완비, CHANGES_REQUESTED 상태만 남음),
155+
#747, #653, #611, #776. 각각 무엇이 빠졌는지는 `010`에 적는다.
156+
157+
**자체 리뷰 사이클이 필요한 대형 건**: #757(GPT-5.6 Pro 브라우저 자동화, 40파일),
158+
#581(zh-TW 로케일, 59파일), #715(계정 풀 선택 순서, 62파일),
159+
#707(외부 기여자의 보안 하드닝, 88파일), #671(exact account routing),
160+
#569(readiness 계약, draft), #557(npm 캐시 복구, draft).
161+
머지 라운드에서 처리할 물건이 아니다. 블라스트 반경과 리뷰 표면 때문이지
162+
분량 때문이 아니다.
163+
164+
**기타**: #745(정규화는 맞는데 회귀 테스트가 없다 — 테스트를 우리가 쓴다),
165+
#763(코드는 괜찮은데 필수 CI 기록이 없다), #793(#773이 왜 리버트됐는지 기록이
166+
없다. 이유를 모른 채 같은 걸 되돌리는 건 안 된다 — 오너 판단 필요).
167+
168+
## 사이클 구성
169+
170+
- `010` — 이미 랜딩된 7건 PR과 해당 이슈 정리 (머지 없음)
171+
- `020` — 배치 A: restack 6건
172+
- `030` — 배치 B: 재작성 3건
173+
- `040` — 남은 이슈 정리와 인계
174+
175+
각 배치는 `tsc` + 대상 테스트 + 배치 종료 시 전체 스위트 + `privacy:scan`
176+
통과한 뒤에만 푸시한다. 이슈는 랜딩된 코드가 실제로 결함을 없앤 게 확인될 때만
177+
닫고, 부분 해결은 코멘트만 남기고 열어둔다.
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# 010 — 이미 랜딩된 7건 정리
2+
3+
머지가 없는 사이클이다. HEAD가 이미 같은 결함을 고쳤다는 걸 커밋 단위로 확인하고,
4+
PR과 이슈를 근거와 함께 닫는다.
5+
6+
## 확인 방법
7+
8+
`git cherry HEAD refs/prs/<N>`으로 patch-id 동등성을 보고, 동등하지 않으면 HEAD
9+
소스를 직접 읽어 결함이 사라졌는지 확인했다. patch-id가 다른데 결함은 없어진
10+
경우가 있다 — 메인테이너가 같은 문제를 다르게 고친 경우다. 이때는 PR을 머지하면
11+
**더 나은 구현을 되돌린다.**
12+
13+
## 건별 근거
14+
15+
### #736#722 (FULL)
16+
17+
HEAD `1d9e196e7 fix(service): make Windows status locale independent`.
18+
19+
`git cherry`가 PR의 커밋 하나를 `+`(미적용)로 표시하지만 오해다. HEAD의 구현이 더
20+
새롭다. 확인:
21+
22+
```
23+
git diff HEAD refs/prs/736 -- src/service.ts
24+
```
25+
26+
PR head 방향으로 가면 `decodeSchtasksOutput()` 전체(`src/service.ts:364-393`)와
27+
XML 판독 실패 분기(`:607-619`)가 **삭제되고** `runFile()``encoding: "utf8"`
28+
돌아간다. schtasks `/query /xml`은 UTF-16LE를 뱉기 때문에 그 상태로는 모든 health
29+
check가 실패하고 성공한 elevated create를 롤백한다. 즉 이 PR을 지금 머지하면
30+
#722를 다시 연다.
31+
32+
### #752#733 (FULL)
33+
34+
HEAD `c1ecbe1b5 feat(windows): add restart-safe tray controls`.
35+
`src/tray/windows.ts:474-477``stdio: "ignore"`로 띄운다. 소켓 핸들이 상속되지
36+
않는다. PR 커밋은 patch-id 동등(`-`).
37+
38+
### #743#572 (PARTIAL)
39+
40+
HEAD `fd1933099 fix(providers): harden discovery path and test isolation`.
41+
`src/providers/model-discovery.ts:93-95`가 백슬래시와 `%2e` 디코딩된 `..` 세그먼트를
42+
거부한다. 두 커밋 모두 patch-id 동등.
43+
44+
#572는 닫지 않는다. 그 이슈는 OpenAI 호환 provider 배치 승격 전체이고 이건 discovery
45+
경로 하드닝 한 조각이다.
46+
47+
### #610#606 (FULL)
48+
49+
HEAD `716f39cb6 fix(codex): key catalog cache by runtime and address CodeRabbit follow-ups`.
50+
`src/codex/catalog/bundled.ts:153-168`이 주입된 executor만 전달하고
51+
`discoverAlternatives`를 기본 `false`로 둔다. 두 커밋 patch-id 동등.
52+
53+
이전 라운드 문서가 이 PR head를 NOT-ON-DEV로 기록했는데, 그 뒤에 랜딩됐다.
54+
55+
### #734#721 (FULL)
56+
57+
HEAD `9b5c864ff merge: PR #734` — 이미 머지돼 있다. 열려 있는 건 GitHub 상태가
58+
갱신되지 않아서다. 남아 있던 macOS 테스트 실패는 `f81e98aca`가 고쳤다:
59+
`tests/bun-runtime.test.ts:7-9``realpathSync`로 temp root를 먼저 해석한다.
60+
이전 라운드가 이 PR을 뺀 이유가 그 실패였다. 지금 8/8 통과.
61+
62+
### #777#759 (PARTIAL)
63+
64+
HEAD `e64a00e9f``src/codex/catalog/parsing.ts:274-285`에서 모든 카탈로그 엔트리의
65+
`input_modalities`를 정규화한다. `text`/`image`/`audio`만 통과시키고, 전부 걸러지면
66+
빈 배열 대신 `["text"]`로 둔다. 오염된 영속 행 복구는
67+
`tests/codex-catalog-sync-hardening.test.ts:161-193`이 덮는다. `7a041e2bc`
68+
`299f35dc9`가 커스텀 모델 라우트 쪽 enum 경계를 추가로 막았다.
69+
70+
PR의 테스트는 지금 컴파일도 안 된다 — import하는 sanitizer 헬퍼가 HEAD에 없다.
71+
#759는 열어둔다. 이슈가 더 넓은 enum 경계 점검을 명시적으로 남겨뒀다.
72+
73+
### #533#557로 대체
74+
75+
patch-id로 확인: #533의 update-recovery 14커밋이 #557에 전부 같은 patch-id로
76+
들어 있고 #557이 하드닝 2건을 더 얹었다. 다만 `refs/prs/533``refs/prs/557`
77+
**그래프 조상은 아니다** — 재작성된 같은 시리즈다. 둘 다 draft이고 250커밋 이상
78+
뒤처져 있다. #557을 후속으로 남기고 #533만 닫는다.
79+
80+
#737(`62e937614`, 이미 dev에 있음)이 이 둘을 대체하지 않는다는 것도 확인했다.
81+
#737`src/update/job.ts`와 그 테스트 86줄만 바꾼다. 캐시 소유권 preflight,
82+
recovery-tree 검증, 프로세스 트리 정리는 들어 있지 않다.
83+
84+
## 이슈 처리
85+
86+
닫는다: #722, #733, #606, #721.
87+
열어둔다: #572(부분), #759(부분).
88+
89+
## 이 사이클이 바꾸는 파일
90+
91+
없다. 문서만 추가한다. GitHub 상태만 정리한다.

0 commit comments

Comments
 (0)