Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
45e08fe
docs(devlog): remote hub restack roadmap — measured conflict surface …
Sep 1, 2026
66bafbc
docs(devlog): fold audit r1 — 10 blockers closed, 33 review threads l…
Sep 1, 2026
d18aa34
docs(devlog): fix markdown lint in the restack unit (MD018/MD060/MD04…
Sep 1, 2026
6dd5820
docs(devlog): record wp1 outcome — design rebased, six contract defec…
Sep 1, 2026
208dc48
docs(devlog): record wp2 outcome — p1 rebased, catalog contract recon…
Sep 1, 2026
2914933
docs(devlog): record the wp2 commit map and why the fixups are a sepa…
Sep 1, 2026
1b9574a
docs(devlog): record wp3 outcome — p2 rebased, plaintext pairing remo…
Sep 1, 2026
349939a
docs(devlog): record the wp3 commit map
Sep 1, 2026
cdc0162
docs(devlog): record wp4 outcome — p3 rebased, stranded-connection jo…
Sep 1, 2026
cddf765
docs(devlog): record the wp4 commit map
Sep 1, 2026
d5658bc
docs(devlog): record wp5 outcome — p4 rebased, machine plane declared…
Sep 1, 2026
ca95323
docs(devlog): record the wp5 commit map
Sep 1, 2026
58307e5
docs(devlog): record wp6 outcome — p5 rebased, three of four reported…
Sep 1, 2026
9152956
docs(devlog): record the wp6 commit map
Sep 1, 2026
91010b1
docs(devlog): record wp7 outcome — p6 rebased, rotation abort orderin…
Sep 1, 2026
158d8b5
docs(devlog): record the rebased stack state across all seven phases
Sep 1, 2026
6be23bd
docs(devlog): record the exact-head CI repairs and the dev-side macos…
Sep 1, 2026
209a718
docs(devlog): record the route-registry gap and the dev flake root ca…
Sep 1, 2026
2c021fa
docs(devlog): close the remote hub restack unit
Sep 1, 2026
fa88164
docs(devlog): note the split-out dev flake PR in the outcome
Sep 1, 2026
1995193
docs(devlog): audit remote hub exposure, requests, and rollback for a…
Sep 1, 2026
eb5245b
docs(devlog): record the exposure, request, and rollback polish
Sep 1, 2026
4f1c1fb
docs(devlog): record the polish commit map and final chain
Sep 1, 2026
89dfdcf
docs(devlog): describe the lint suppression without writing the direc…
Sep 1, 2026
d43ae71
docs(devlog): record which axis closed where
Sep 1, 2026
15540b5
docs(devlog): record the per-axis verification commands
Sep 1, 2026
b0026ce
docs(devlog): record why the server axis needed no change
Sep 1, 2026
b797a85
docs(devlog): record why rollback was the heaviest axis
Sep 1, 2026
b7dfb68
docs(devlog): record the post-polish stack state
Sep 1, 2026
2357a06
docs(devlog): plan the stack merge train and the #3147 prerequisite
Sep 1, 2026
e1022b7
docs(devlog): correct the merge train plan after the audit refuted th…
Sep 1, 2026
60d47d4
docs(devlog): record the #3147 seed restore and what it does not fix
Sep 1, 2026
692fabb
docs(devlog): reverse the merge order so the T20 fix lands before its…
Sep 1, 2026
9d59ce5
docs(devlog): correct the fetch-binding claim, replace snapshot green…
Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 0 additions & 57 deletions devlog/_plan/260901_merge_train_round3/061_wp7_outcome.md

This file was deleted.

81 changes: 0 additions & 81 deletions devlog/_plan/260901_merge_train_round3/070_outcome.md

This file was deleted.

118 changes: 118 additions & 0 deletions devlog/_plan/260901_remote_hub_restack/000_research.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Remote hub 스택 재스택 — 리서치

측정 시각 2026-09-01, base `origin/dev@15b0f701e`.

## 대상

7단계 스택. 베이스만 `dev`를 향하고 나머지는 직전 단계의 head 브랜치를 향한다.

| PR | 브랜치 | base | 커밋 | 파일 | draft |
| --- | --- | --- | --- | --- | --- |
| #2771 | codex/remote-hub-design | dev | 9 | 12 | no |
| #2772 | codex/remote-hub-p1 | design | 5 | 14 | no |
| #2776 | codex/remote-hub-p2 | p1 | 6 | 32 | yes |
| #2777 | codex/remote-hub-p3 | p2 | 11 | 34 | no |
| #2781 | codex/remote-hub-p4 | p3 | 8 | 48 | yes |
| #2786 | codex/remote-hub-p5 | p4 | 8 | 19 | no |
| #2789 | codex/remote-hub-p6 | p5 | 17 | 95 | yes |

전부 `Ingwannu`의 CHANGES_REQUESTED가 걸려 있다. 포크 지점은
`8b1b65b8d`이고 그 이후 `dev`는 336커밋 전진하면서 1075개 파일을 건드렸다.

## 충돌 표면 — 실측

시험 워크트리에서 `rebase --onto`를 단계별로 순차 실행해 측정했다.
design 단계는 문서 전용이라 충돌 없이 통과한다(`f17605021`). p1부터 걸린다.

| 단계 | 단계 파일 | dev와 겹치는 파일 |
| --- | --- | --- |
| design | 12 | 0 |
| p1 | 14 | 12 |
| p2 | 32 | 15 |
| p3 | 34 | 18 |
| p4 | 48 | 17 |
| p5 | 19 | 5 |
| p6 | 95 | 58 |

p1의 실제 충돌 3파일: `src/server/catalog-download.ts`,
`src/server/index.ts`, `src/server/management/model-routes.ts`. 세 파일 모두
`f6367639c feat(server): add least-privilege GET /v1/catalog for remote Codex
clients (#2979)`가 마지막으로 건드렸다. 이건 우연이 아니다 — #2979는 이 스택이
제안한 `/v1/catalog`를 별도 PR로 먼저 랜딩시킨 것이다. 즉 p1의 카탈로그 델타는
상당 부분 이미 dev에 있다. 재스택할 때 재구현이 아니라 **중복 제거**가 필요하다.

## 반복 후보 충돌원

`dev`가 포크 이후 스택 파일에 남긴 관련 랜딩:

- `f6367639c` (#2979) — `/v1/catalog` 최소권한 라우트. p1 카탈로그 델타와 직접 중복.
- `f83368dfd` (#3057) — entitlement 삼상태. `src/server/index.ts` 공유.
- `c3da277bc` (#2891) — entitlement roster 클라이언트 버전. `model-routes.ts` 공유.
- i18n 9개 로케일 파일 — p4/p6가 전부 건드리고 dev도 계속 건드린다. 텍스트 추가 충돌이라
기계적이지만 건수가 많다.

## 블로커 재분류

리뷰 7건을 원인별로 다시 묶으면 세 종류뿐이다.

### (1) stale 아티팩트 — 재스택이 곧 해소

`tests/release-version-line.test.ts:108` 실패가 #2772/#2777/#2786에 공통으로
걸려 있다. 정확히 말하면 `:108`은 "뒤처짐" 분기가 아니라 **동일(equality)**
분기다(`:99-108`): 트리 버전이 최고 릴리스 태그와 같은데 이 커밋이 그 태그가
가리키는 커밋이 아니면 거절한다. 스택의 `package.json`은 `2.34.0`이고 당시
최고 태그가 `v2.34.0`이었다.

현재 `origin/dev`는 `2.40.0`, 최고 태그는 `v2.39.0`이므로 지금 리베이스하면
해소된다. p1은 `package.json`을 수정하지 않으므로 dev 값이 그대로 온다.
**다만 자동 소멸을 가정하지 않는다** — `v2.40.0`이 dev 전진보다 먼저 태깅되면
재발한다. 리베이스된 head마다 `bun test tests/release-version-line.test.ts`를
포커스드로 돌려 확인한다. **게이트는 건드리지 않는다.**

### (2) 구조적 보류 — 자동화는 통과, 사람 리뷰는 별개

`#2776`/#2781/#2789는 "중간 스택 head라 최종 승인 불가"라는 보류다.
`AGENTS.md:278-281`과 `.github/workflows/enforce-pr-target.yml:533-557`은
열린 부모 head를 타깃하는 stacked child에 대해 wrong-base 게이트를 실제로
면제한다. 저자가 `lidge-jun`(push 권한)이라 기여자 readiness 체크리스트
(`enforce-pr-target.yml:740-746`)도 적용되지 않는다.

**그러나 이건 자동화 게이트만 통과시킨다.** 리뷰어의 CHANGES_REQUESTED는
draft 해제로도 CI 그린으로도 해제되지 않는다. `MAINTAINERS.md:57-61`은
비저자 메인테이너 승인과 보안 리뷰를 요구하고, Ingwannu가 유일한 비저자
메인테이너다. 우리가 도달할 수 있는 종료선은 **재리뷰 요청 가능 상태**이며,
승인 자체는 외부 의존이다.

### (3) 실질 결함 — 코드/문서 수정 필요

- #2771 문서 계약 4건 (아래 010).
- `gui/tests/api-auth-memory.test.ts:23` — #2777에 보고됐지만 **소유 단계는 p2**다.
- `tests/cli-headless-parity.test.ts:287` 미선언 `/api/machine/*` 7개 —
#2786에 보고됐지만 **소유 단계는 p4**다.
- `tests/update-stop-first.test.ts:225`, `tests/loopback-listener-admission.test.ts:196`,
privacy 게이트 — p5.
- 미해결 인라인 리뷰 스레드 **33건**(P1 6건 포함). 전수는 `003` 원장 참조.

### 소유 단계 실측

"어느 PR에서 실패가 보고됐는가"와 "어느 단계가 그 결함을 도입했는가"는 다르다.
diff로 측정했다:

- `/api/machine/` 추가 라인: p1~p3 = 0, **p4 = 49**, p5 = 0, p6 = 2.
라우트를 도입한 건 p4다.
- `gui/tests/api-auth-memory.test.ts`를 건드리는 단계: **p2**와 p4. p3은 0.

상류에서 고쳐야 한다. 하류에서 고치면 그 사이 단계들은 자기 head에서 빨간 채로
남고, 그 위에 다음 단계를 쌓게 된다.

**단계 초록 불변식:** 각 단계는 자기 head에서 초록이어야 다음 단계를 그 위에 쌓는다.

(3)만 실제 작업이다. (1)은 재스택의 부산물이고 (2)는 절차 + 외부 의존이다.

## 제약

- 푸시는 `--no-verify` (사용자 지시). `prepush`가 전체 스위트를 부르므로 로컬에서
돌 수 없다.
- 로컬 전체 스위트 금지. 판정은 exact-head CI.
- 머지 금지. "머지 가능한 상태까지"가 종료선이다.
- `dev`/`main`/`preview` 직접 푸시 금지.
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# 감사 라운드 1 — 종합

감사자: 읽기전용 레인(gpt-5.6-sol high). verdict **FAIL**, 블로커 10건.
아래는 각 건에 대한 판정과 로드맵 수정 내역이다. 수용/반박을 명시한다.

## A1 (High) — DONE 정의가 머지 가능 상태가 아니다 · 수용

080의 종료선은 CI 그린 + 체인 정합 + draft 해제까지였다. 그런데 7개 PR 전부
`CHANGES_REQUESTED`이고 `MAINTAINERS.md`는 비저자 메인테이너 승인과 보안
리뷰를 요구한다. CI가 초록이어도 리뷰 상태가 걸려 있으면 머지 버튼은 막힌다.

수정: 080의 종료선에 "각 PR `reviewDecision`이 `CHANGES_REQUESTED`가 아닐 것"과
"스레드 33개 해소"를 추가한다. 다만 승인 자체는 우리가 만들 수 없으므로,
우리 종료선은 **재리뷰 요청 가능 상태**까지다. 승인 획득은 외부 의존이며
그 지점에서 막히면 BLOCKED으로 보고한다.

## A2 (High) — 미해결 리뷰 스레드 33개 누락 · 수용, 가장 큰 누락

로드맵이 리뷰 본문만 읽고 인라인 스레드를 안 봤다. 실측 결과:
`#2771`: 18, #2772: 1, #2776: 2, #2777: 3, #2781: 4, #2786: 2, #2789: 3.
P1 등급이 6건 섞여 있다. 별도 원장 `003_review_thread_ledger.md`로 분리했다.

## A3 (High) — stacked 면제의 효력 과대 해석 · 수용

`AGENTS.md:278-281` + `enforce-pr-target.yml:533-557`의 면제는 실재한다.
저자가 `lidge-jun`(push 권한)이라 기여자 체크리스트도 적용되지 않는다.
그러나 이건 **자동화만** 통과시킨다. 사람 리뷰의 CHANGES_REQUESTED는 그대로다.
030/050/070의 "draft 해제하면 해소" 서술을 "자동화 게이트는 통과, 리뷰는 별도"로
정정한다.

## A4 (High) — "dev wins"가 /v1/catalog 계약을 훼손할 수 있다 · 수용

감사자가 실제 차이를 열거했다: dev(#2979)는 GET+HEAD, `x-api-key` 허용,
256 MiB 캡, 507. p1은 GET only, `x-api-key` 거부, 32 MiB, 503, 그리고
`x-opencodex-key-id`와 프로토콜 메타데이터를 **단독으로** 갖는다.

"dev wins"를 통째로 적용하면 p1 고유 기여가 조용히 사라진다. 020을 병합 매트릭스로
교체한다.

## A5 (High) — 블로커 2건이 한 단계씩 늦게 배정됐다 · 수용, 실측 확인

직접 측정했다:

- `/api/machine/` 추가 라인 수: p1~p3 = 0, **p4 = 49**, p5 = 0, p6 = 2.
즉 라우트를 도입한 건 p4다. 060(wp6/p5)이 아니라 050(wp5/p4)이 고쳐야 한다.
- `gui/tests/api-auth-memory.test.ts`를 건드리는 단계: **p2**와 p4. p3은 0.
040(wp4/p3)이 아니라 030(wp3/p2)이 고쳐야 한다.

원칙도 함께 채택한다: **각 단계는 자기 head에서 초록이어야 다음 단계를 그 위에 쌓는다.**
상류에서 고치면 하류 리베이스는 이미 깨진 것을 옮기는 셈이 된다.

## A6 (High) — 다섯 번째 설계 결함(D5) 누락 · 수용

`080_phase6_hardening.md` 8.3 응답 규칙이 "safe content type, cache control,
ETag ... 만 보존"이라고 적어, 릴레이된 세션/부트스트랩/관리 응답에 validator가
살아남는 것을 허용한다. D2와 같은 결함이 릴레이 경로에 한 번 더 있는 것이다.
D5로 추가하고 구현은 릴레이를 처음 갖는 wp5/p4에 배정한다.

## A7 (High) — D4 해법이 미명세 · 수용

"애매하면 재개"로는 부족하다는 지적이 맞다. `pendingOperation`은 어느 파일이
새 시크릿을 담았는지 식별하지 못한다. 계약을 구체화한다: probe 이전에 후보
identity를 비교한다 → 두 후보가 동일하면 교체 이전 상태이므로 절대 commit하지
않는다 → abort/restore는 확인된 권위가 있을 때만 → abort 불확실 시 증거를 보존한다.

## A8 (High) — D1의 HTTPS 업그레이드에 신뢰 앵커가 없다 · 수용

평문 부트스트랩이 HTTPS 엔드포인트를 "알려주는" 구조는 on-path 공격자가 다른
유효한 HTTPS origin을 끼워넣을 수 있다. 업그레이드 대상이 의도한 허브인지
증명할 수단이 없으면 업그레이드는 보안이 아니라 의식이다.

채택: 비-loopback HTTP를 전면 거부하는 쪽을 기본으로 한다. 사전에 알려진 HTTPS
origin이 있는 경우에 한해 동일 호스트 scheme 업그레이드만 허용하고, 정상
인증서 검증을 요구하며 리다이렉트에서 권위를 파생하지 않는다.

## A9 (Medium) — 체인 검증이 부모 계보를 증명하지 못한다 · 수용

`origin/dev`가 조상인지만 보면, 부모를 건너뛰고 dev 위로 직접 리베이스된
자식도 통과한다. 각 엣지를 `git merge-base --is-ancestor origin/<parent>
origin/<child>`로 확인하고 양쪽 OID를 기록한다.

## A10 (Medium) — release-version 결론이 조건부로만 옳다 · 수용

감사자가 정확히 짚었다: `:108`은 "뒤처짐"이 아니라 **동일(equality)** 분기다.
과거 실패는 트리 버전이 `v2.34.0` 태그와 같은데 그 커밋이 아니었기 때문이다.
지금 리베이스하면 해소되지만, `v2.40.0`이 dev 전진보다 먼저 태깅되면 재발한다.
"자동 소멸"을 "리베이스된 head마다 포커스드 체크 필수"로 바꾼다.

감사자가 `bun test tests/release-version-line.test.ts` 3 pass와
`bun run privacy:scan` 통과를 현재 트리에서 확인했다. privacy 실패도 상속된
staleness였다는 뜻이며, 충돌 해소 후 재발하는지만 보면 된다.

## 반박 없음

10건 전부 수용한다. D2(no-store)와 D3(Origin verbatim)는 감사자도 타당하다고
했고, 바텀업 리베이스 골격도 유지된다. 바뀐 것은 단계 소유권과 종료 게이트다.
Loading
Loading