Skip to content

Commit e4f0b33

Browse files
committed
docs(plan): disposition all 41 open issues against dev head
Three close cleanly: #759 (video modality filtered at three write paths), #754 (init EOF rejects pending prompts), #767 (native slugs withheld across every Desktop writer). Three lane errors are recorded rather than quietly dropped, because each would have produced a wrong row: A reported typecheck failure was an empty node_modules in a fresh worktree, not a tree defect. After bun install it exits 0. #570 came back both FIXED and PARTIAL. Both readings are correct about different questions: the port-remap failure it reported is gone at auth-cors.ts:37-51, while non-loopback host aliases stay rejected at :85 -- a request the issue never made. Closing on the reported mode, splitting the alias question out. #764's covering PR merged remotely but its merge commit is not an ancestor of the frozen HEAD, so the reading stands for this round. #658 now has a located fix site. The adapter fails closed at anthropic.ts:866-881 whenever EOF arrives without stop_reason, and relaxing it there was already reverted once. bridge.ts:771 is where it belongs -- the same place PR #781 adds failCurrentToolCall(). Acceptance-boundary analysis stays in gitignored scratch per AGENTS.md; only neutral pointers are here.
1 parent 6b70112 commit e4f0b33

1 file changed

Lines changed: 206 additions & 0 deletions

File tree

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# 020 — 열린 이슈 41건 처분
2+
3+
기준 `7132828b3`. `010`의 PR 처분을 입력으로 쓴다(`COVERED-BY-PR` 판정에 필요).
4+
5+
luna-max 6개 레인을 겹치지 않는 구획으로 파견했다. 레인 간 불일치와 오류가 셋 나왔고
6+
전부 소스로 직접 재확인했다. 아래 "레인 오류" 절에 남긴다.
7+
8+
## 요약
9+
10+
| 판정 | 건수 |
11+
|---|---|
12+
| `FIXED-ON-DEV` (닫을 수 있음) | 3 |
13+
| `PARTIAL` | 10 |
14+
| `OPEN` | 8 |
15+
| `COVERED-BY-PR` | 3 |
16+
| `NEEDS-DECISION` | 7 |
17+
| `UPSTREAM` | 5 |
18+
| 로드맵/기능요청 (장기) | 5 |
19+
20+
## 지금 닫을 수 있는 것 3건
21+
22+
| 이슈 | 근거 |
23+
|---|---|
24+
| **#759** 카탈로그 video modality 거부 | `catalog/provider-fetch.ts:327-333``text\|image\|audio`로 필터, `parsing.ts:281-285`가 재차 정리, `sync.ts:451-458`이 디스크 보존 행에도 적용. 세 경로 전부 막힘 |
25+
| **#754** `ocx init` EOF busy-loop | `cli/init.ts:9-32``close`에서 대기 중 프롬프트를 reject, `:213-223`이 EOF를 종료코드 1로. `bfa1a599c`가 HEAD 조상 |
26+
| **#767** Claude Desktop native 모델 opt-out | `catalog/metadata.ts:126-129``desktopNativeModels:false`일 때 native slug 미반환, `management/shared.ts:224-248`이 할당·기본값도 제거. `f72610027` |
27+
28+
세 건 다 보고된 실패 모드가 실제로 해소됐는지까지 확인했다. 같은 파일을 건드린
29+
커밋이 있다는 것만으로 닫지 않았다.
30+
31+
## 레인 오류 3건 — 기록해두는 게 낫다
32+
33+
### 1. typecheck 실패는 트리 문제가 아니었다
34+
35+
게이트 레인이 `bun run typecheck` FAIL을 보고했다:
36+
37+
```
38+
error TS2688: Cannot find type definition file for 'bun-types'.
39+
```
40+
41+
이대로면 "dev 트리에 타입 오류가 있다"가 된다. 확인해보니 이 워크트리의
42+
`node_modules`**비어 있었다**. `bun install` 후:
43+
44+
```
45+
$ bun run typecheck
46+
$ bun x tsc --noEmit
47+
(exit 0)
48+
```
49+
50+
새 워크트리에 의존성을 안 깐 것뿐이다. 환경 문제를 코드 결함으로 적을 뻔했다.
51+
52+
### 2. #570은 "고쳐졌다"와 "안 고쳐졌다"가 둘 다 맞다
53+
54+
한 레인은 `FIXED-ON-DEV`, 다른 레인은 `PARTIAL`을 냈다. 소스를 보면 둘 다 옳다.
55+
56+
`auth-cors.ts:37-51`:
57+
58+
```
59+
export function isLoopbackRequestHost(value: string | null): boolean {
60+
const parsed = parseHttpHost(value);
61+
if (!parsed) return true;
62+
// Loopback is a trust boundary by hostname, not by port. `ssh -L 20100:localhost:10100`
63+
// legitimately arrives as `Host: localhost:20100`, and refusing it took the whole /v1/*
64+
// data plane down with it, not just CORS.
65+
return isLoopbackHostname(parsed.hostname);
66+
```
67+
68+
포트 동등성 비교가 사라졌다. **#570이 보고한 실패 모드 — 포트 리맵 터널의 403 —
69+
는 재현되지 않는다.** `#573`이 해결했다.
70+
71+
동시에 `myhost.lan` 같은 비-loopback 별칭은 `:85`에서 여전히 거부된다. 그건 사실이지만
72+
**#570이 낸 질문이 아니다.** 별도 요청이다.
73+
74+
처분: `FIXED-ON-DEV`로 닫되, 별칭 호스트 신뢰 목록은 별건으로 분리한다. 원 보고자의
75+
실패 모드가 해소됐는데 인접한 미구현 기능 때문에 계속 열어두는 건 트래커를 흐린다.
76+
77+
### 3. #764는 PR이 머지됐지만 이 HEAD에는 없다
78+
79+
#780은 05:17:31Z에 머지됐는데 머지 커밋 `12eae74ec``7132828b3`의 조상이 아니다.
80+
동결 HEAD 기준 판정은 그대로 두고, 다음 라운드가 새 HEAD에서 다시 본다.
81+
82+
## 심각도 높은 잔여 — 부분 수정된 것들
83+
84+
직전 라운드가 절반씩 고친 것들이다. **잔여를 정확히 적는 게 이 표의 목적이다.**
85+
"고쳐졌음"으로 뭉뚱그리면 다음 사람이 남은 절반을 못 찾는다.
86+
87+
| 이슈 | 랜딩된 것 | 남은 것 |
88+
|---|---|---|
89+
| **#766** 대시보드 blank | GUI first-paint 분리(`dashboard-core-poll.ts:251-265`), stale 상태를 hard error로 매핑하지 않음(`startup-health-ui.ts:97-103`) | ACL 타임아웃은 여전히 503(`management-auth.ts:58-69,122-140,192-194`). startup 프로브가 여전히 5초 Bun 서브프로세스(`startup-health-cache.ts:10-12`). `/api/logs?surface=`가 서버에서 무시됨(`request-log.ts:741-763`) |
90+
| **#765** anthropic 어댑터 | URL 정규화(`anthropic.ts:253-262`), JSON delta의 tool 블록 스코핑(`:835-836`), 없는 ID 합성(`:808-811`, `:903-907`) | 빈/공백 ID는 nullish 검사만이라 통과. terminal frame 없는 EOF는 여전히 에러(`:866-881`). malformed 접두 문자열 입력은 복구 대신 폐기(`:269-284`) |
91+
| **#764** Windows 서비스 stop | 생존 프로세스 감지 후 native 복원 전 비정상 종료(`service.ts:1994-2006`) | `stopTrackedProxyIfRunning()`이 PID 없이 `"none"` 반환(`:1668-1679`). 식별 프로브 750ms 제한(`proxy-liveness.ts:69-87`). `uninstallWindows()`가 태스크 제거 검증 전에 자산 삭제(`:1431-1474`). WinSW 콘솔 프롬프트(`winsw.ts:90-96`) |
92+
| **#796** Ark 구조화 content | Ark 호스트에 `[{type:"text",text:""}]` 전송(`openai-chat.ts:408-409`) | **여전히 미검증.** 소스가 `:396-403`에서 스스로 unverified로 표기. 실제 엔드포인트 확인 필요 |
93+
| **#545** Claude Desktop 3P 분류기 | 거짓 502 로그 분류만 수정(`request-log.ts:641`이 200으로 기록) | 64토큰 incomplete가 `stop_reason=max_tokens`로 충실히 반환되어(`claude/outbound.ts:411`) 클라이언트 재시도를 그대로 유발 |
94+
| **#753** GUI 로딩 상태 | 공유 로딩 프리미티브(`data-surface.ts:52-131`), 중복 quota 재조회 제거(`Providers.tsx:84-100`) | `App.tsx:307-319`이 여전히 페이지 언마운트. 계정 상태가 빈 값으로 시작(`useProviderAccountPools.ts:62-64`)해 잠시 blank. 요청 수는 38 → 31(`6d13736dd`)로 줄었을 뿐 |
95+
| **#95** 다중 사용자 호스팅 | 비-loopback 수용(`auth-cors.ts:191-203`), LiteLLM preset(`registry.ts:1052-1057`) | **테넌트 격리 없음.** 요청 로그에 사용자 식별 필드 자체가 없음(`request-log.ts:34-126`, `usage/log.ts:41-78`) |
96+
97+
## 열린 PR이 덮는 것
98+
99+
| 이슈 | 덮는 PR | 현재 상태 |
100+
|---|---|---|
101+
| #760 TLS Origin 403 | #779 | `management-api.ts:82-85`가 인증 **전에** 거부. PR은 초록, 보안 리뷰만 남음 |
102+
| #726 로그 200건 상한 | #784 | `request-log.ts:128-129` `MAX_LOG_SIZE=200` 그대로 |
103+
| #724 stale plan | #750 | `auth-api.ts:140-147``freshPlan`을 버리고 `account.plan`을 방출 |
104+
| #723 Antigravity 탐색 실패 | #744 | `registry.ts:799``liveModels` 없음 → `provider-routes.ts:84-90`이 live로 취급 |
105+
106+
## 우리가 고칠 수 있는 것
107+
108+
PR도 없고 오너 판단도 필요 없는 것들이다.
109+
110+
| 이슈 | 위치 | 성격 |
111+
|---|---|---|
112+
| **#719** Kiro 대형 MCP 카탈로그 | `adapters/kiro-tools.ts:144-171` | 설명만 절단하고 **총량 예산이 없다**. `kiro.ts:419-425`가 전체 목록 유지, `:562-563`이 그대로 업스트림 전송 |
113+
| **#716** Kiro 설치 안내 Unix 전용 | `oauth/kiro.ts:360,378` + 5개 로케일 | `providers.md` en:88,156 / ko:83,106 / ja:83,106 / zh:77,98 / ru:91,116 전부 `curl \| bash`. `install.ps1` 없음 |
114+
| **#753** 잔여 blank 렌더 | `useProviderAccountPools.ts:62-64`, `Providers.tsx:311` | 첫 페인트 전에 loading 초기화 |
115+
116+
## 제품 판단이 필요한 것
117+
118+
- **#690** `ocx claude` `bypassPermissions` 자동 주입 — Claude Code 도구 실행을 자동
119+
승인한다. 오해 없이 opt-in이어야 한다. `types.ts:339-346`에 필드 없음
120+
- **#695** Antigravity 계정 자동 전환 — 자동 풀은 현재 Anthropic만
121+
(`oauth-account-routes.ts:241-268`). provider 정책 함의 있음
122+
- **#755** 릴리스 큐 추적 — 본문의 "main is now an ancestor of dev"가 사실과 다르다.
123+
`origin/main`(`1adad3573`)은 HEAD 조상이 아니다(`rev-list --left-right --count``1 25`)
124+
- **#561** Modelsell, **#201** TRAE, **#178** Factory, **#177** Warp, **#540** WordPress —
125+
전부 `MAINTAINERS.md:35` 증거 요건 미달. #178/#177은 provider가 아니라 에이전트
126+
실행 백엔드라 설계 결정이 먼저다
127+
128+
## 나머지 — 기능 요청과 장기 항목
129+
130+
분석은 했는데 위 절에 안 들어간 것들이다. 완결성을 위해 전부 적는다.
131+
132+
| 이슈 | 판정 | 현재 상태 |
133+
|---|---|---|
134+
| **#709** 카탈로그를 관리 API로 제공 | `FIXED-ON-DEV` | `management/model-routes.ts:101-112``GET /api/catalog` 구현, 없으면 404, 버전 헤더 포함. `5d7ab0cb7`. 잔여는 raw 바이트 대신 재직렬화한다는 점과 `models_cache.json` 경로 미구현 — 원 요청 범위 밖 |
135+
| **#650** GPT-5.6 Pro 라우팅 | `COVERED-BY-PR` (#757) | `registry.ts:607`에 virtual Pro ID는 있으나 `provider-registry-parity.test.ts:99`가 일반 `gpt-5.6-pro`를 명시적으로 거부. `adapter-resolve.ts:41`에 browser 어댑터 없음 |
136+
| **#572** provider 12종 승격 (umbrella) | `PARTIAL` | 공유 discovery 계약(`48f2e8362`)은 dev에 있음. 12종 전부 canonical 미등록 — Baseten(#653) DeepInfra·Novita(#747) Hyperbolic(#751)만 PR 존재. Chutes SambaNova Nebius DigitalOcean Scaleway Nscale Vultr Featherless는 **PR 없음** |
137+
| **#586** Pool/Direct 전환 UI | `NEEDS-DECISION` | 백엔드는 `provider-routes.ts:149`에 있음. `ProviderSettings.tsx:138`이 mode를 안 보내고 `types.ts:88` 패치 타입에 필드 없음. `CodexAuth.tsx:21`은 뱃지만 표시. **UI 위치 결정이 먼저** |
138+
| **#657** 거부 기반 quota 회복 | `OPEN` | 현재 `responses/core.ts:237`이 429/402를 전부 재시도 대상으로 받음. reset credit 상환은 수동 엔드포인트(`auth-api.ts:926`)뿐. 자동 상환은 되돌릴 수 없는 크레딧을 소모하므로 정책 결정 필요 |
139+
| **#656** 저장 계정을 native 로그인으로 | `NEEDS-DECISION` | native 자격증명은 `main-account.ts:22`에서 읽기 전용. 풀 자격증명은 `types.ts:1191`의 별도 4필드 레코드. `auth.json` 교체는 자격증명 생명주기 조작이라 보안 리뷰 대상 |
140+
| **#425** 계정 네임스페이스 picker | `PARTIAL` | 검증(`config.ts:693`)과 셀렉터 생성(`account-namespaces.ts:80`)은 있는데 `server/index.ts:461`이 bare 모델만 방출. 소비자가 없다 |
141+
| **#415** provider 네이티브 검색 sidecar | `OPEN` | backend 타입이 `"openai"\|"anthropic"` 2값 고정(`types.ts:848-870`), dispatch도 둘뿐(`web-search/loop.ts:475-485`) |
142+
| **#414** Exa 등 검색 sidecar | `OPEN` | 같은 지점. `config-routes.ts:321-330` 검증과 `dashboard-shared.ts:154-166` GUI도 2값 |
143+
| **#553** Copilot TLS hostname mismatch | `OPEN` | `fff8c369f`**진단만** 개선. `responses/core.ts:2119`이 TLS 에러를 502로 변환하는 건 그대로. 잘못된 인증서는 환경 문제라 인증서 검증 비활성화나 hostname 재작성은 **안전하지 않다** — 우리가 고칠 수 없다 |
144+
| **#386** macOS 메뉴바 companion | `OPEN` | `apps/macos-menu-bar` 없음, `package.json:35-55`에 빌드 스크립트 없음. PR #387은 CLOSED |
145+
146+
#572가 중요하다. umbrella에 12종이 걸려 있는데 PR이 있는 건 4종뿐이고, 나머지 8종은
147+
아무도 안 하고 있다. 이걸 열어둔 채로 개별 preset PR을 증거 미달로 계속 돌려보내면
148+
양쪽 다 안 움직인다. `030`에서 다룬다.
149+
150+
## upstream-tracking 4건 — 전부 유효
151+
152+
오래됐다고 닫지 않는다. 조건이 살아 있는지만 확인했다.
153+
154+
| 이슈 | 조건 | 확인 |
155+
|---|---|---|
156+
| #417 한국어 음성 U+FFFD | 업스트림 `openai/codex#35161` | 여전히 OPEN. 릴레이는 `server/index.ts:164-207`에서 재디코딩 없이 전달, `server-live.test.ts:642-735`가 바이트 동일성 고정 |
157+
| #241 Desktop picker 누락 | Desktop 클라이언트 allowlist | ocx는 `sync.ts:162-185`에서 `visibility:"list"`로 기록하고 `/v1/models`(`index.ts:447-463`)로 노출. 필터는 외부 |
158+
| #92 V2 NEW_TASK 암호문 | Fernet 암호문 복호 불가 | `encrypted-payload.ts:182-231`이 감지, `:261-307`이 보존. `sub-agent-surface.md:20-28`에 한계 문서화 |
159+
| #418 V2 custom→custom 위임 | 자식 요청이 프록시에 도달하기 전 실패 | 로컬 구현 없음. `collaboration.ts:234-250`은 안내만 |
160+
161+
## #658 — 수정 지점이 확정됐다
162+
163+
직전 라운드는 "진짜 수정 지점은 어댑터가 아니라 bridge"라고만 남겼다. 이번에 그
164+
지점을 정확히 찾았고, 별도 레인에서 확인한 #781의 내용과 **같은 곳으로 수렴한다.**
165+
166+
현재 동작(`anthropic.ts:866-881`):
167+
168+
```
169+
if (!emittedDone) {
170+
// Fail closed on transport EOF.
171+
if (pendingStopReason !== undefined) { ... yield done ... }
172+
else {
173+
yield { type: "error", message: "upstream stream ended before message_stop — possible truncation" };
174+
}
175+
```
176+
177+
`stop_reason` 없이 EOF가 오면 무조건 에러다. AgentRouter는 정확히 그렇게 끝낸다.
178+
레인이 리다이렉트된 프로브로 `text_delta → error → response.failed`를 재현했고,
179+
Anthropic 출력에 `message_stop`이 없었다.
180+
181+
어댑터에서 이걸 완화하려던 시도는 `95d8ed77f`로 리버트됐다. 어댑터는 프로토콜
182+
계약을 지키는 게 맞고, 완화는 프로토콜 위반이기 때문이다.
183+
184+
`bridge.ts:771``case "error"`가 실제 지점이다. 지금은 에러를 받으면
185+
`closeCurrentMessage()`류로 열린 블록을 닫는데, tool call의 경우 이게
186+
`function_call_arguments.done``status:"completed"`**먼저** 내보낸 뒤
187+
`response.failed`가 나간다. 클라이언트는 발행된 tool call을 본 상태가 된다.
188+
189+
**#781이 이미 이걸 고친다.** `010`에서 확인한 `failCurrentToolCall()`이 정확히
190+
`status:"incomplete"`로 취소하는 경로다. 즉 #658의 잔여와 #765의 잔여와 #781
191+
bridge 변경이 한 지점에서 만난다.
192+
193+
남는 설계 질문 하나: EOF에 `stop_reason`이 없을 때 **버퍼된 텍스트가 유효하면
194+
완료로 내보낼 것인가**. 이건 provider 스코프 호환 모드(AgentRouter 한정)로
195+
`responses/core.ts:2475` 호출부에서 넘겨야 한다. 전역으로 완화하면 진짜 절단을
196+
놓친다 — 직전 라운드가 `#773`에서 겪었을 가능성이 있는 실패 모드다.
197+
198+
## 보안 관련
199+
200+
수용 경계(#760/#570/#766) 상세 분석은 `AGENTS.md` 규칙에 따라 **이 저장소에 쓰지
201+
않는다.** 미공개 상태의 인증 경계 분석이다. 스크래치 경로:
202+
`.tmp/260731-acceptance-boundary-notes.md` (gitignore 확인함).
203+
204+
여기 적는 건 중립적 사실뿐이다: #760`management-api.ts:84`, #766
205+
`management-auth.ts:138-140`에서 갈린다. #779#782는 서로 충돌하지 않고 필수
206+
랜딩 순서도 없지만, 랜딩 후 결합 검증이 필요하다.

0 commit comments

Comments
 (0)