From 4c9fea45ccbae2ada23938b2f40539ae52773517 Mon Sep 17 00:00:00 2001 From: jun Date: Tue, 1 Sep 2026 23:46:29 +0900 Subject: [PATCH] docs(devlog): close out the remote hub merge train --- .../120_merge_train_outcome.md | 62 +++++++++++++++++++ .../121_open_threads_after_merge.md | 42 +++++++++++++ .../122_post_merge_verification.md | 29 +++++++++ .../130_final_state.md | 31 ++++++++++ 4 files changed, 164 insertions(+) create mode 100644 devlog/_plan/260901_remote_hub_restack/120_merge_train_outcome.md create mode 100644 devlog/_plan/260901_remote_hub_restack/121_open_threads_after_merge.md create mode 100644 devlog/_plan/260901_remote_hub_restack/122_post_merge_verification.md create mode 100644 devlog/_plan/260901_remote_hub_restack/130_final_state.md diff --git a/devlog/_plan/260901_remote_hub_restack/120_merge_train_outcome.md b/devlog/_plan/260901_remote_hub_restack/120_merge_train_outcome.md new file mode 100644 index 0000000000..18bcdae0bb --- /dev/null +++ b/devlog/_plan/260901_remote_hub_restack/120_merge_train_outcome.md @@ -0,0 +1,62 @@ +# 120 — 머지 트레인 최종 결과 + +## 랜딩한 것 + +| PR | 내용 | 커밋 | +| --- | --- | --- | +| #3147 | `dev` websocket refresh 플레이크 근본 수정 | `408652698` | +| #2771 | design — 설계 계약 | `278fd613a` | +| #2772 | p1 — 런타임 롤, `/readyz` 협상 | `87459f8c3` | +| #2776 | p2 — 원격 GUI 세션, pairing, T20 캡 | `39e5aefb6` | +| #2777 | p3 — `ocx connect` 클라이언트 코어 | `fd8b6b895` | +| #2781 | p4 — 머신 리스너, 투플레인 | `163feb6ee` | +| #2786 | p5 — 허브 관리 ingress, 배포 | `6d732d3dc` | +| #2789 | p6 — 키 로테이션, 적대적 게이트 | `9232df0e6` | +| #3149 | 이 로드맵 유닛 | `3275b5a27` | + +#3143은 #3147과 같은 결함의 중복본이라 크레딧을 남기고 닫았다. + +## 순서가 두 번 바뀌었다 + +**첫 번째.** 원래 계획은 스택을 먼저 리베이스하는 것이었는데, 세 브랜치의 +macOS 실패가 `dev`가 소유한 플레이크였다. 스택을 재스택해도 같은 플레이크를 +다시 상속하므로 #3147을 루트에 먼저 넣었다. + +**두 번째, 더 중요한 것.** 문서 PR(#3149)을 먼저 머지하려던 계획을 뒤집었다. +그 문서가 T20 — 미인증 바디 무제한 버퍼링 — 의 재현 조건을 담고 있는데, +수정은 `codex/remote-hub-p2`의 `b7282858b`에 있었고 `dev`에는 없었다. +먼저 머지했다면 수정 없는 상태의 취약점을 공개 기본 브랜치에 올리는 것이었다. +스택을 먼저 넣어 수정이 랜딩한 뒤에 문서를 올렸다. `112_wp2_order_reversal.md`. + +## 감사가 나를 두 번 세웠다 + +A 게이트 감사가 첫 계획에 fail을 냈고 옳았다. 리뷰어가 #3147에 건 P1의 +인과가 뒤집혀 있었다 — 삭제된 quota 시드는 `dev`에서도 이미 stale이었고 +(`auth-api.ts:1332-1335`), prime의 WHAM 호출은 `redirectCanonicalCodexTo`가 +리다이렉트하지 않는 경로라 `upstreamRequests` 카운터에 닿지도 못한다. 시드는 +복원했지만 근거를 "레이스 수정"에서 "주석 정합성 + prime 억제 위생"으로 바꿔 +기록했다. 같은 감사가 #2789에 내가 못 본 두 번째 실패(launcher SIGINT +타임아웃)가 있다는 것도 잡아냈다. + +#3149 리뷰는 문서의 JS 시맨틱 오류를 잡았다. "기본 매개변수는 모듈 평가 +시점의 전역을 묶는다"는 틀렸고, 호출 시점에 평가된다. 실제 원인은 +happy-dom `window` 대 Bun `globalThis` 렐름 분리였다. + +## 머지 직전 빨갛던 것들 + +전부 코드 회귀가 아니었다. + +- `shutdown drain cap expiry enters the synchronous spill fallback` — 스택이 + 건드리지 않는 파일의 부하성 플레이크. 재실행 통과. +- `keyring-smoke=abandoned` — 러너 중단. 집계 잡 `ci`를 빨갛게 만들었다. + 재실행 통과. +- `enforce-target` 2건 — 스크린샷 요구. #2776은 + `gui-screenshot-waived` 라벨로 면제(`gui/src/api.ts` + 테스트뿐). + #2789는 면제하지 않고 실제로 프록시를 띄워 키 교체 UI를 캡처해 붙였다. + +## 검증 경계 + +로컬 전체 스위트는 돌리지 않았다. 실행한 테스트는 +`bun test tests/server-auth.test.ts` 한 파일(91 pass / 0 fail)뿐이고, 나머지 +검증은 전부 exact-head 원격 CI다. 모든 푸시는 `--no-verify`, `dev` 직접 푸시는 +0건 — 아홉 건 전부 PR 머지 경로다. diff --git a/devlog/_plan/260901_remote_hub_restack/121_open_threads_after_merge.md b/devlog/_plan/260901_remote_hub_restack/121_open_threads_after_merge.md new file mode 100644 index 0000000000..566f550742 --- /dev/null +++ b/devlog/_plan/260901_remote_hub_restack/121_open_threads_after_merge.md @@ -0,0 +1,42 @@ +# 121 — 머지 후 남은 리뷰 스레드 + +머지 시점에 `isResolved=false`로 남은 스레드가 있다. 숫자는 이렇다: +#2771 15건, #2776 2건, #2781 4건, #2789 3건. + +이걸 "정리 안 함"으로 적는 게 정직하다. 그리고 왜 지금 정리하지 않는지도. + +## 왜 지금 닫지 않나 + +머지된 PR의 스레드를 사후에 resolve 표시하는 건 기록을 바꿀 뿐 코드를 바꾸지 +않는다. 미해결 표시를 지우면 "닫혔다"는 신호만 남고 실제로 무엇이 처리됐는지는 +오히려 흐려진다. 남겨두면 최소한 다음 사람이 스레드를 읽을 수 있다. + +실질 내용은 이미 처리됐다. P1 6건(T1, T20, T22, T25, T26, T31)은 소유 단계의 +코드 수정으로 닫혔고 그 수정과 함께 랜딩했다 — `003_review_thread_ledger.md`의 +배정표와 각 `0X1_wpN_outcome.md`가 어느 커밋이 어느 스레드를 닫았는지 적고 +있다. 남은 다수는 #2771의 마크다운 린트(MD018/MD022, 테이블 파이프 +이스케이프)와 문서 계약 지적이다. + +## 무엇이 진짜 남았나 + +P2 중 코드가 필요한 건들: + +- T2 — 연결된 GUI에 인증된 models 경로. `/v1/models`가 데이터플레인으로 간다. +- T3 — 관리 ingress에서 GUI health 엔드포인트 보존. +- T19 — 확장된 readiness 응답을 `docs-site/.../cli/lifecycle.md`에 문서화. +- T21 — `hub.managementPublicOrigin`, `remoteGui.allowedTailscaleUsers`, + `remoteGui.allowInsecure*` 문서화. + +이건 새 유닛의 일이지 이 유닛의 잔업이 아니다. 스택은 머지됐고, 위 넷은 +`dev` 위에서 각자의 PR로 처리하는 게 맞다. + +**추적: #3158.** 머지된 PR의 스레드는 닫히면 사실상 사라지므로, 위 넷과 아래 +플레이크를 이슈로 옮겨 적었다. 스레드를 resolve 표시하는 것보다 이쪽이 다음 +사람에게 실제로 도달한다. + +## 별도로 남은 플레이크 + +`ocx launcher graceful shutdown > SIGINT to the launcher tears down the Bun +proxy` (`tests/shutdown-launcher.test.ts`)가 #2789 macOS에서 20069ms 워치독 +타임아웃으로 한 번 졌다. 재실행으로 통과했으므로 머지를 막지 않았지만, 근본 +원인은 보지 않았다. `dev`에 남아 있는 플레이크로 취급해야 한다. diff --git a/devlog/_plan/260901_remote_hub_restack/122_post_merge_verification.md b/devlog/_plan/260901_remote_hub_restack/122_post_merge_verification.md new file mode 100644 index 0000000000..721cbbeda2 --- /dev/null +++ b/devlog/_plan/260901_remote_hub_restack/122_post_merge_verification.md @@ -0,0 +1,29 @@ +# 122 — 머지 후 `dev` 검증 + +9건이 랜딩한 `dev`(`3275b5a27`)가 실제로 정합한지 확인했다. 머지가 성공했다는 +것과 트리가 멀쩡하다는 것은 다른 주장이라서다. + +## 스택 코드가 실제로 있다 + +`src/client/machine-listener.ts`, `src/client/connect.ts`, +`src/client/hub-relay.ts`, `src/routing/compatibility/provider-slot.ts` 전부 +`origin/dev`에 존재한다. T20 캡은 `src/server/index.ts`의 `declaredLength` +2회 참조로 확인된다. + +## 구조 불변식이 살아 있다 + +`AGENTS.md`가 가장 크게 지키라고 적은 두 가지를 좁게 돌렸다: + +``` +bun test tests/core-lab-boundary.test.ts tests/repo-hygiene.test.ts +29 pass / 0 fail / 71 expect() calls +``` + +이건 스타일 검사가 아니다. core-lab boundary는 Lab이 코어 요청 경로로 새어드는 +것을 런타임 import 그래프로 막고, 그 안의 activation-window 스캔은 +`startServer`가 동기로 남아 있는지를 본다. 리모트 허브는 `startServer` 주변에 +라우트와 런타임 롤을 추가하는 스택이므로, 이 둘이 초록인 것이 "코어 경로를 +건드리지 않았다"의 실질 증거다. repo-hygiene은 gitlink와 벤더 클론이 인덱스에 +다시 나타나지 않았음을 본다. + +전체 스위트는 돌리지 않았다(금지). 나머지 검증은 각 PR의 exact-head CI다. diff --git a/devlog/_plan/260901_remote_hub_restack/130_final_state.md b/devlog/_plan/260901_remote_hub_restack/130_final_state.md new file mode 100644 index 0000000000..0860f26012 --- /dev/null +++ b/devlog/_plan/260901_remote_hub_restack/130_final_state.md @@ -0,0 +1,31 @@ +# 130 — 유닛 종료 상태 + +## 이 유닛이 끝낸 것 + +리모트 허브 7단계 스택 + 분리 PR 2건, 총 9건이 `dev`에 랜딩했다. +`dev` HEAD는 `3275b5a27`. 중복본 #3143은 크레딧을 남기고 닫았다. + +검증은 두 층이다. 각 PR의 exact-head 원격 CI, 그리고 머지된 `dev`에서 +`core-lab-boundary` + `repo-hygiene` 29건 통과. 로컬 전체 스위트는 돌리지 +않았고 `dev` 직접 푸시는 0건이다. + +## 남긴 것 + +**#3158** — 머지 시점에 열려 있던 P2 스레드 4건(T2 인증된 models 경로, +T3 관리 ingress의 GUI health, T19 readiness 응답 문서화, T21 신규 config 키 +문서화)과 `shutdown-launcher` 워치독 플레이크. 머지된 PR의 스레드는 사실상 +접근이 끊기므로 이슈로 옮겼다. + +## 이 유닛에서 배운 것 두 가지 + +**리뷰 지적은 결론이 아니라 입력이다.** #3147의 P1은 "삭제된 시드 때문에 +추가 요청이 나가 카운터가 깨진다"였다. 시드를 복원한 건 맞지만 인과는 +틀렸다 — `dev`에서도 이미 stale이었고, 그 요청은 리다이렉트 경로 밖이라 +카운터에 닿지도 못한다. 지적을 그대로 받아 적었다면 존재하지 않는 레이스를 +수정 이력에 남길 뻔했다. 반대로 #3149의 네 지적은 전부 사실이었고, 그중 +하나는 순서를 바꿔야 할 만큼 무거웠다. 매번 확인하는 것 말고 지름길은 없다. + +**공개 순서는 코드 순서와 다른 제약이다.** 문서 PR을 먼저 머지하는 건 기술적으로 +아무 문제가 없다. 문제는 그 문서가 아직 수정되지 않은 취약점의 재현 조건을 +담고 있을 때다. `AGENTS.md`의 기준 — "이미 이 약점을 드러내는 공개 diff가 +있는가" — 은 파일 내용이 아니라 **머지 순서**에 걸리는 제약이다.