diff --git a/REPORT.md b/REPORT.md index 4b1f708c..da5f36e3 100644 --- a/REPORT.md +++ b/REPORT.md @@ -30,6 +30,44 @@ (잠금은 「있으면 검사」라 「없으면 침묵」이다). 판단 재료 = 워크로그 `2026-09-04-…json` `proposals[0]`. - ★**고지**: 열린 **PR #19** 와 `REPORT.md`·`STATE.md` **상단이 겹친다** — 나중에 착지하는 쪽이 인접 충돌한다. +## [2026-09-03] S5~S7 「새 충돌」 재측정 + 「base 병기」를 §5 상시 규칙으로 채택 (rustjava-upstream-sync-remeasure-s5-s7-and-lock-restore-basis) +- 무엇을: PR #18 이 `--merge` 로 착지해 `merge-base origin/main upstream/main` 이 **`3296139c`** 로 + 전진한 «뒤» 기준으로 S5~S7 을 다시 쟀고, ★**세 base 를 «병기»** 했다(계획 기준 `03438b0` · 복원 전 + `3a59776` · 복원 후 `8c1238b`). 같은 컷 `ba5797b` 가 base 에 따라 ★**19 · 112 · 4**(28배 차)로 갈린다. + ⇒ 그래서 「**충돌 수를 적을 때 base 를 반드시 병기한다**」를 `docs/upstream-sync-approach.md` §5 의 + **상시 규칙으로 채택**했다(문안 신설). ★**직전 반려의 근인이 정확히 이 병기 누락**이고, S2·S4 회신은 + 각자는 정확했는데 «한 표»로 모으는 순간 기준이 섞였다 — **개별 회신의 정확성으로는 막히지 않는다.** +- 왜: §5 표의 S5~S7 「0·0·+3」은 **계보가 전진한다는 전제** 위의 수인데 그 전제가 S1~S4 내내 깨져 있었다. + 이제 처음으로 참이 됐으므로 그 위에서 다시 재야 티켓 size/timeout 이 맞는다. + ★**재측정 결과 «새 충돌»(복원 후)**: **S5 +3** · **S6 +0** · **S7 +1**. S5 는 「충돌 0 물량」이 **아니다**. + ★★**그 +3 을 만든 것은 upstream 이 아니라 «우리가 앞 회차에 남긴 로컬 분기»다** — + `string.rs`(우리 **+8/−28**) · `test_timer.rs`(우리 **+8/−1** = **S4 가 넣은 500→2000ms 여백**) · `Cargo.lock`(재생성). + ★**방향 정본 = `git diff --numstat `**(2026-09-04 정정 — 초판 `+28/−8`·`+1/−8` 은 역순 출력이라 폐기). + ★**S7 은 diff 32만 줄대인데 새 충돌 1건**(`thread.rs`) ⇒ 「물량이 크면 충돌도 크다」는 성립하지 않는다. +- 사용자 영향: ★**코드 변경 0 · 문서 전용**(런타임 동작 무변경). 얻는 것은 **남은 회차의 크기를 실제 수로** + 잡는 것과, 다음 회차가 같은 «기준 혼합» 반려를 반복하지 않는 것이다. +- 검증: `git merge-tree --write-tree --name-only ` 의 2번째 줄~첫 빈 줄. ★**이 파싱으로 §5 첫 표 + `0·1·2·2·7·16·17·17·17·19` 가 그대로 재현된다**(= 방법 자체의 검증). ★**ⓑ↔ⓒ 차이가 «계보뿐»임을 통제**: + ⓒ 트리를 ⓑ 계보에 얹은 합성 커밋(`git commit-tree 4788ef2f -p 3a59776`)이 **45·61·112 로 동일**. +- ★**「예측은 하한」은 «절대적이지 않다» — S7 에서 처음 깨졌다**(예측 +3 ↔ 실측 ⓐ+2 · ⓒ+1). + 원인 3건 전부 실측: ⑴`Cargo.lock` **이중 계상**(S5 에서 이미 충돌) ⑵`class_format_error.rs` 는 표의 **경로가 틀렸고**, + ★**우리 쪽이 `3296139` 와 바이트 동일**(블롭 `0dbd369a`)이라 upstream **+4/−3** 이 깨끗이 적용된다 + ⑶`throwable.rs` 도 **같은 술어**다(우리 0줄 ↔ upstream +81/−29) + ⇒ ★**S3 의 설계 판단(upstream 오류 분류 채택)이 뒤 회차의 충돌을 «지웠다».** + ★★**[2026-09-04 정정] 초판 ⑵의 「`3296139..ba5797b` upstream 변경 0」은 «거짓»이고 «0 인 쪽이 반대»였다** — + 실측 `diff --numstat 3296139 ba5797b` = **`4 3`** · `diff --numstat 3296139 origin/main` = **0줄**. + ⇒ ★**「upstream 이 안 건드리는 파일」로 읽으면 «영구 무충돌»이지만, 참인 술어로는 «우리가 손대는 순간 충돌»한다.** + 결론(S7 예측 과대 = ⓐ +2)은 **불변**이다. +- ★**후속 (1) — S8 이 필요하다. 그리고 남은 회차 중 제일 크다.** 「7회차」는 더 이상 upstream 헤드에 닿지 않는다: + `ba5797b..upstream/main` **12커밋**(★**증분** — 누적 `3296139..ba5797b` 는 18 로 다른 수다) · + ⓒ 누적 충돌 ★**11**(S7 의 4 대비 +7). 성격이 다르다 — + `java_runtime/` → **`rustjava-runtime/`** · `test_data/` → **`test-data/`** **개명 스윕**이라 + 새 7건이 ★**우리 고유 산출물에 꽂힌다**: `rustjava-runtime/src/charset.rs` · + `test-data/UnsupportedCharset.class`·`.txt` · ★**`test-data/src/UnsupportedCharset.java`**(★`.java` 만 `src/` 아래 — + 2026-09-04 경로 정정) · `test-data/TimeApi.class`·`.txt` · `test_string.rs`. + ★개명 충돌은 3-way 가 rename 을 놓치면 픽스처가 «삭제 대 수정»으로 **조용히 사라진다** ⇒ **별도 판정 회차**로 잡아라. +- ★**후속 (2)** — S5 티켓의 성격을 「물량」 → **「설계 판단 1건 포함」**으로 바꿔 발권하라(`string.rs`). + ## [2026-08-27] upstream 동기 근인 확정 — 게이트③ `--squash` 가 계보를 버린다 (rustjava-upstream-sync-squash-defeats-convergence) - 무엇을: S1~S4(PR #11·#13·#16·#17)가 **전건 `merged=true`** 인데도 `merge-base origin/main upstream/main` 이 fork 시점 **`62cf0c6a`** 그대로이고 behind **33** 이 줄지 않던 근인을 확정했다. 근인은 게이트③ diff --git a/STATE.md b/STATE.md index 9d5fccc0..7a8b243e 100644 --- a/STATE.md +++ b/STATE.md @@ -1,9 +1,6 @@ # STATE ## 진행중 -- [rustjava-upstream-sync-remeasure-s5-s7-and-lock-restore-basis] ★**PR #18 착지 뒤 기준 S5~S7 재측정 + - 「충돌 수에 base 병기」를 §5 상시 규칙으로 채택**(PR **#19** 대기). 같은 컷 `ba5797b` 가 - **19 · 112 · 4** 로 갈린다 · 새 충돌 **S5 +3 · S6 +0 · S7 +1** · ★**S8 이 필요하다**(개명 스윕). - [rustjava-upstream-sync-squash-defeats-convergence] ★**S1~S4 가 착지하고도 fork 가 upstream 에 한 걸음도 가까워지지 않은 근인을 확정하고 계보를 기록했다.** 근인 = 게이트③ 제품 repo **`--squash`**. 증명은 **머지커밋 부모 수**다 — `6bfe97c4`·`11ef5010`·`4bb796de`·`3a597768` **전건 1개**(커밋 7·10·15·21이 @@ -26,6 +23,24 @@ (25번째 run, 앞선 24건 전부 red). **PR 대기 — 게이트③ 미착지.** ## 완료 +- [rustjava-upstream-sync-remeasure-s5-s7-and-lock-restore-basis] ★**PR #18 착지 «뒤» 기준으로 S5~S7 재측정 + + 「충돌 수에 base 병기」를 §5 상시 규칙으로 채택.** ★**코드 변경 0 · 문서 전용.** + 세 base 병기: 같은 컷 `ba5797b` 가 **19**(계획 `03438b0`) · **112**(복원 전 `3a59776`) · **4**(복원 후 `8c1238b`) — + ★**28배 차이. base 없는 충돌 수는 검증 불가다.** + ★**새 충돌(복원 후)**: **S5 +3** · **S6 +0** · **S7 +1**. ★**S5 는 「충돌 0 물량」이 아니다** — + 그 3건은 `Cargo.lock`(재생성) · `string.rs`(★**설계 판단**) · `test_timer.rs`(**S4 가 넣은 2000ms 여백**)이고 + ★★**전부 upstream 이 아니라 «우리가 앞 회차에 남긴 로컬 분기»가 만든다.** + ★**「예측은 하한」이 S7 에서 처음 깨졌다**(예측 +3 ↔ ⓐ+2 · ⓒ+1) — `Cargo.lock` 이중 계상 · + `class_format_error.rs` 경로 오기 · ★**그 파일과 `throwable.rs` 둘 다 «우리 쪽»이 `3296139` 와 바이트 동일**이라 + upstream 변경(**+4/−3** · **+81/−29**)이 깨끗이 적용된다(S3 가 수렴시켰다). + ★★**[2026-09-04 정정] 초판이 `class_format_error.rs` 를 「upstream 변경 0」으로 적은 것은 «거짓»이고 «0 인 쪽이 반대»였다** — + `diff 3296139 ba5797b` = **+4/−3** · `diff 3296139 origin/main` = **0줄**(블롭 `0dbd369a`). + ⇒ ★**「upstream 이 안 건드린다」가 아니라 «우리가 손대는 순간 충돌한다»** 이다. + ★**부수 발견 — S8 이 필요하고 남은 것 중 제일 크다**: `ba5797b..upstream/main` **12커밋** · ⓒ 누적 **11**(+7) · + `java_runtime/`→`rustjava-runtime/` · `test_data/`→`test-data/` **개명 스윕**이라 우리 픽스처에 꽂힌다. + ★게이트③ 완료: PR #19 — ★★**`--merge` 착지**(★`--squash` 아님 · 등재 repo). + ★착지 «전» `REPORT.md`·`STATE.md` 위치 충돌 2건을 **합집합**으로 해소했다(PR #20 이 먼저 착지 · 코드 충돌 0). + 머지커밋 sha 는 회신 `merged:` 참조. - [rustjava-worklog-mandate-decision-and-local-gate] ★**워크로그 작성을 DoD «의무»로 결정 + 형식 잠금을 로컬 DoD 4번째 명령으로 편입.** ★**코드 변경 0 · 새 도구 0 · CI 워크플로 무접촉.** ★**먼저 쟀다**: 규약 착지(`b3a4cf4` · 2026-08-26) 이후 착지 **4회차 중 3건(75%)** 작성 · @@ -86,9 +101,19 @@ ## 다음 -### ①(최우선) upstream 동기화 — ★**S4 착지 대기(2026-08-27)**. 정본 = `docs/upstream-sync-approach.md` +### ①(최우선) upstream 동기화 — ★**S1~S4 착지 완료 · 계보 복원 완료(2026-09-03)**. 정본 = `docs/upstream-sync-approach.md` -★**S4(`3296139` · 물량 회차)까지 머지 완료 · PR 대기 중이다. 다음은 S5(`c4665b0` · Java 1.2 API 확장).** +★★**[2026-09-03 갱신] 구판 「S4 착지 대기」는 낡았다** — PR #17(S4)·#18(계보 기록)이 **전건 머지**됐고 +★**#18 은 `--merge` 로 착지해** `merge-base origin/main upstream/main` = **`3296139c`** · behind **30** · +열린 PR **0**. ⇒ ★**「앞 회차가 착지하면 뒤 회차의 기준선이 바뀐다」가 이제 처음으로 참이다.** + +★**다음은 S5(`c4665b0` · Java 1.2 API 확장). 단 「충돌 0 물량」이 «아니다»** — 2026-09-03 재측정(base = 현 `main` +`8c1238b` · `merge-base 3296139c`)으로 **새 충돌 3건**: `Cargo.lock`(재생성) · +`java_runtime/src/classes/java/lang/string.rs`(★**설계 판단** · upstream `3296139`→`c4665b0` **+285/−31** ↔ +우리 `3296139`→`origin/main` **+8/−28**) · +`java_runtime/tests/classes/java/util/test_timer.rs`(**S4 가 넣은 500→2000ms 여백을 다시 얹는 기계 작업**). +**S6 새 충돌 0 · S7 새 충돌 1**(`thread.rs`). ★상세·근거·세 base 대조표 = `docs/upstream-sync-approach.md` §5 「[2026-09-03 재측정]」. +★★**충돌 수를 적을 때는 base 를 반드시 병기하라 — §5 상시 규칙이다.** **S4 실측(2026-08-27)**: 착수 시 `merge-base origin/main upstream/main` = ★**`62cf0c6`**(최초 공통조상) · `1f356ae`·`af4f6f8`·`822504b` 가 `origin/main` 의 조상 **전건 NO** — ★**스쿼시 3회가 족보를 원점으로 되돌렸다.** @@ -117,9 +142,13 @@ green 전건 rc=0 · `cargo test --all` **261 passed / 0 failed / 1 ignored**(S3 ★**대가**: 감도가 내려간다 — red 문턱 1회전 **~167ms → ~667ms**(약 4배 둔화). 「5.6배 저하」는 여전히 red, 「2.4배 저하」는 이제 통과한다. 그 상한을 테스트 주석에 박았다. -★**「예측은 하한」이 이제 3회 연속 실측됐다**: S3 +9 예측 ↔ 11 · S4 **0 예측 ↔ 2**. +★~~**「예측은 하한」이 이제 3회 연속 실측됐다**~~ → ★★**[2026-09-03 정정] 하한은 «절대적이지 않다» — S7 에서 처음 깨졌다** +(예측 `+3` ↔ 실측 계획기준 **+2** · 복원 후 **+1**). 초과는 «우리 로컬 분기»가 만들고(S5 `0↔+3`), +미달은 «앞 회차가 수렴시켜서» 난다(S3 가 upstream 오류 분류를 채택해 `throwable.rs` 충돌이 사라졌다). +⇒ ★**티켓 size/timeout 은 여전히 하한 쪽으로 잡되, 「하한이다」를 근거로 쓰지 마라.** ★**`thread.rs` 는 S1·S3·S4 «세 회차 연속» 충돌**한다 — upstream 이 `ThreadStartProxy::call` 을 반복 재작성하기 때문이다. -⇒ **S5~S7 도 그 파일은 「또 충돌한다」를 기본값으로 잡아라.** 해소 전략은 불변이다: +★★**[2026-09-03 정정] 「S5~S7 도 기본값으로 잡아라」는 «절반» 맞았다** — 실측상 **S5·S6 은 충돌하지 않고 S7 에서만** 다시 열린다. +해소 전략은 불변이다: **upstream 본문을 뼈대로 취하고 `#[tracing::instrument]` 한 줄만 PR #4 의 수동 span 으로 치환**한다. ### ②`wie-ktf-hardening` 잔존분 — 2026-08-15 재판정으로 **4건 → 2건** @@ -258,8 +287,10 @@ green 전건 rc=0 · `cargo test --all` **261 passed / 0 failed / 1 ignored**(S3 | `feat/rustjava-upstream-sync-s3` | PR #16 의 head — 게이트③ 집행 중 | 머지와 함께 자동 삭제(`deleteBranchOnMerge`) | | `wie-ktf-hardening` | 보존 판정(2026-07-25) | 위 ②로 **잔존 가치가 2건까지 줄었다** — 브리프 ③-2 가 그 2건을 새 브랜치로 옮겨 심으면 ★**보존 근거가 소멸**한다 | -⇒ ★**다음은 S4(`3296139`)** — 남은 upstream 커밋 **26**. 계획서 예측 **새 충돌 0**이나 -★**예측은 하한이다**(S3 가 +9 예측에 11 이었다). +⇒ ~~★**다음은 S4(`3296139`)** — 남은 upstream 커밋 **26**~~ → ★★**[2026-09-03 갱신] 다음은 S5(`c4665b0`)** — +남은 upstream 커밋 **30**(`ba5797b` 뒤로 **12** 가 더 붙었다 · 헤드 `bd42427`). 열린 PR **0** · 원격 브랜치 = `main` · `wie-ktf-hardening`. +★**「7회차」로는 헤드에 닿지 않는다 — S8 발권이 필요하고, 그것이 남은 회차 중 제일 크다** +(ⓒ 누적 충돌 **11** · `java_runtime/`→`rustjava-runtime/` · `test_data/`→`test-data/` **개명 스윕**이 우리 픽스처에 꽂힌다). - ★PR 발권 시 `--repo Jun025/RustJava` 명시(2026-07-22 upstream 오발행 사고 재발 방지). - ★upstream 발신(PR·이슈·코멘트·push)은 **티켓이 명시 허가할 때만**. 기본은 조회뿐. diff --git a/docs/upstream-sync-approach.md b/docs/upstream-sync-approach.md index 1d5c59bc..7a3287b3 100644 --- a/docs/upstream-sync-approach.md +++ b/docs/upstream-sync-approach.md @@ -214,9 +214,12 @@ upstream 은 여기서만 `UTF-8`/`EUC-KR` 하드코딩을 유지한다 ⇒ 그 | **S2** | `af4f6f8` (#177) | 1 | 62f +3,245/−366 | **+5** (`io.rs`·`input_stream_reader.rs`·`unsupported_encoding_exception.rs`·`loader.rs`·`test_input_stream_reader.rs`) | ★**charset / PR #5** | 설계 | | **S3** | `822504b` (#180) | 1 | 69f +2,127/−356 | **+9** (`classfile/*` 4 · `string.rs` · `test_string.rs` · `class_definition.rs` · `src/runtime.rs` · `test_utils`) | ★**오류 분류 / PR #3** | 설계 | | **S4** | `3296139` (#184) | 8 | 50f +4,418/−187 | **0** | GlobalRef · CLI classpath · monitor | 물량 | -| **S5** | `c4665b0` (#190) | 6 | 171f +33,138/−1,058 | **0**(`Cargo.lock`만) | Java 1.2 API 확장 | 물량 | -| **S6** | `95ebc5c` | 11 | 142f +17,593/−483 | **0** | regex · Formatter · logging · LinkedHashMap | 물량 | -| **S7** | `ba5797b` (#201) | 1 | 319f +20,118/−5,729 | **+3** (`class_format_error.rs`·`throwable.rs`·`Cargo.lock`) | 접근 플래그 · 가상 디스패치 스윕 | 물량+ | +| **S5** | `c4665b0` (#190) | 6 | 171f +33,138/−1,058 | ~~**0**(`Cargo.lock`만)~~ → ★**+3** | Java 1.2 API 확장 | 물량 | +| **S6** | `95ebc5c` | 11 | 142f +17,593/−483 | ~~**0**~~ → ★**+0** | regex · Formatter · logging · LinkedHashMap | 물량 | +| **S7** | `ba5797b` (#201) | 1 | 319f +20,118/−5,729 | ~~**+3** (`class_format_error.rs`·`throwable.rs`·`Cargo.lock`)~~ → ★**+1** (`thread.rs`) | 접근 플래그 · 가상 디스패치 스윕 | 물량+ | + +★**취소선 칸은 2026-08-16 계획 기준(base `03438b0`)의 사료다 — 지우지 마라.** 화살표 뒤 수는 +**2026-09-03 재측정**(base = 현 `main` `8c1238b`)이고, 근거·전 기준 대조는 아래 **[2026-09-03 재측정]** 블록에 있다. ★**「새 충돌」은 «해당 컷에서 처음 충돌하는 파일 수»다.** 앞 회차가 착지하면 뒤 회차의 기준선이 바뀌므로 **각 회차 착수 시 재측정이 필수**다(§0 의 교훈 그대로). @@ -260,6 +263,116 @@ upstream 은 여기서만 `UTF-8`/`EUC-KR` 하드코딩을 유지한다 ⇒ 그 > 까지 끌어올렸다(behind 33 → 18). ★**단 이 커밋 자체가 `--squash` 로 착지하면 무의미하다** — > 게이트③ 예외 판정은 총괄 소관(`REPORT.md` 후속 추천 참조). +### ★★[상시 규칙 · 2026-09-03 채택] 충돌 수를 적을 때는 «base» 를 반드시 병기한다 + +**형식**: `<수>(base · merge-base )`. ★**병기 없는 충돌 수는 문서·회신·티켓 어디에도 쓰지 않는다.** + +★★**[2026-09-04 보강 — 게이트② 지적] `diff` 를 인용할 때는 «방향»도 못박는다.** +초판은 base 만 못박고 **방향을 안 못박았다** — 그래서 같은 표 안에서 「우리」 열이 역순 +(`diff `)으로 실려 **부호가 뒤집혔다**(★이 리니지의 반려 근인 「기준을 섞었다」와 **같은 종**이다). +⇒ **정본 방향을 하나로 고정한다**: +- **우리 쪽 분기** = `git diff --numstat ` (예: `3296139` → `origin/main`) +- **upstream 변경** = `git diff --numstat ` (예: `3296139` → `c4665b0`) + +★**둘 다 «왼쪽이 merge-base»** 다 — 그래야 `+`/`−` 가 「그 쪽이 base 에 무엇을 더했나」로 **같은 뜻**을 갖는다. +★`--numstat` 열 순서는 `추가 삭제 경로` 다. + +★**근거는 「좋은 습관」이 아니라 실측이다** — 같은 컷 `ba5797b` 가 base 에 따라 이렇게 갈린다: + +| base | merge-base | `ba5797b` 누적 충돌 | +|---|---|---| +| `03438b0`(2026-08-16 계획 시점 `main`) | `62cf0c6a` | **19** | +| `3a59776`(PR #18 «직전» `main`) | `62cf0c6a` | ★**112** | +| `8c1238b`(현 `main`) | `3296139c` | ★**4** | + +⇒ ★★**「충돌 4건」과 「충돌 112건」은 «둘 다 참»이고, base 가 없으면 어느 쪽도 검증할 수 없다**(28배 차). + +★**이 규칙이 막는 것은 가정이 아니라 «이미 일어난 사고»다.** 직전 반려의 근인이 정확히 이 병기 누락이었다 — +S2 회신(복원 후 5)과 S4 회신(복원 전 20)은 ★**각자는 정확했는데** 둘을 «한 표»로 모으는 순간 기준이 섞여 +「우상향 계열」이라는 **없는 사실**이 만들어졌다. ⇒ 개별 회신의 정확성으로는 막히지 않는다. **집계 시점에 깨진다.** + +★**병기가 필요한 base 축은 둘이다**(하나로는 부족하다): ⑴**복원 전** = 계보 미기록 상태(`merge-base` 가 +fork 시점) ⑵**복원 후** = 계보 기록 뒤(`merge-base` 가 직전 컷). ★**둘 다 적어라** — 전자는 «계보 미수렴의 +비용», 후자는 «다음 회차의 실제 작업량»이고 **용도가 다르다**. + +> ★★**[2026-09-03 재측정 — PR #18 이 `--merge` 로 착지한 «뒤». 위 블록이 요구한 「전량 재측정」의 집행 결과다.]** +> +> **선행 확인**: `git merge-base origin/main upstream/main` = ★**`3296139cc7ce63822941db5180bd19a8545367e4`**(= S4 컷) · +> `git rev-list --count origin/main..upstream/main` = **30** · PR #18 머지커밋 **`8c1238b`** 부모 **2개**. +> ⇒ ★**계보가 실제로 전진했다** — 위 블록이 「거짓이었다」고 적은 전제(「앞 회차가 착지하면 뒤 회차의 +> 기준선이 바뀐다」)가 ★**이 회차부터 처음으로 참이다.** +> +> **측정 명령**(전 회차 동일): `git merge-tree --write-tree --name-only ` 의 **2번째 줄부터 첫 빈 줄 앞까지**를 센다 +> (그 뒤는 `Auto-merging` 정보 블록이라 세면 안 된다 — 이 파싱으로 위 §5 첫 표 `0·1·2·2·7·16·17·17·17·19` 가 **그대로 재현**된다 = 방법 검증). +> +> | 컷(회차) | ⓐ계획 기준 `03438b0` | ⓑ★복원 «전» `3a59776` | ⓒ★복원 «후» `8c1238b`(현 `main`) | +> |---|---|---|---| +> | `3296139`(S4) | 누적 **16** | 누적 **10** | 누적 ★**0** | +> | `c4665b0`(**S5**) | 누적 **17** · 새 **+1** | 누적 ★**45** | 누적 **3** · 새 ★**+3** | +> | `95ebc5c`(**S6**) | 누적 **17** · 새 **+0** | 누적 ★**61** | 누적 **3** · 새 ★**+0** | +> | `ba5797b`(**S7**) | 누적 **19** · 새 **+2** | 누적 ★**112** | 누적 **4** · 새 ★**+1** | +> +> ★ⓑ의 `merge-base` 는 `62cf0c6a`(fork 시점) · ⓒ는 `3296139c`. ★**ⓑ와 ⓒ의 차이는 «계보뿐»임을 통제했다** — +> ⓒ의 트리를 ⓑ의 계보 위에 얹은 합성 커밋(`git commit-tree 4788ef2f -p 3a59776`)으로 재면 **45·61·112 로 동일**하다. +> ⇒ ★**문서 4파일 diff 는 이 수에 영향이 없고, 갈리는 원인은 100% `merge-base` 다.** +> +> **ⓒ 기준 충돌 파일**(= 다음 회차가 실제로 여는 것): +> **S5** `Cargo.lock` · `java_runtime/src/classes/java/lang/string.rs` · `java_runtime/tests/classes/java/util/test_timer.rs` +> **S6** (S5 와 동일 3건 · 신규 0) **S7** +`java_runtime/src/classes/java/lang/thread.rs` +> +> ★★**ⓒ 의 새 충돌은 «upstream 이 만드는 것»이 아니라 «우리가 앞 회차에 남긴 로컬 분기»가 만든다** — 이번 재측정의 핵심이다: +> `string.rs`(우리 **+8/−28** vs `3296139`) · `test_timer.rs`(우리 **+8/−1** = **S4 가 넣은 500→2000ms 여백**). +> ★**방향은 위 상시 규칙대로 `diff ` 다**(초판의 `+28/−8`·`+1/−8` 은 역순 출력이라 **폐기**). +> 둘 다 ⓐ 기준에는 **없던** 파일이다(그때 우리 `main` 은 그 자리가 merge-base 와 동일했다). +> ⇒ ★**「upstream 물량이 크면 충돌도 크다」가 아니다** — S7 은 diff 가 32만 줄대인데 새 충돌 **1건**이다. +> +> ★**예측 대 실측 — ★같은 기준끼리 짝지었다**(§5 표의 예측은 ⓐ에서 나온 수이므로 ⓐ와 짝짓는다): +> S5 예측 `0`(`Cargo.lock`만) ↔ ⓐ실측 **+1**(`Cargo.lock`) = **일치**(표기 차이) · +> S6 `0` ↔ **+0** = 일치 · S7 `+3` ↔ ⓐ실측 ★**+2** = **예측이 과대**. +> S7 이 빗나간 이유는 셋이고 **전부 실측된다**: +> ⑴`Cargo.lock` 은 **S5 에서 이미 충돌**한다 ⇒ S7 의 «새»가 아니다(표가 **이중 계상**했다). +> ⑵표가 적은 `classfile/src/class_format_error.rs` 는 ★**경로가 틀렸다** — 실제 파일은 +> `java_runtime/src/classes/java/lang/class_format_error.rs` 이고, ★**우리 쪽이 `3296139` 와 바이트 동일** +> (블롭 `0dbd369a`)이라 upstream 의 **+4/−3** 이 깨끗이 적용된다. +> ★★**[2026-09-04 정정] 초판이 「`3296139..ba5797b` 에서 upstream 변경 0」이라고 적은 것은 «거짓»이고 «0 인 쪽이 반대»였다** — +> `git diff --numstat 3296139 ba5797b -- <그 경로>` 는 **`4 3`**(= +4/−3)이고, **0 줄인 것은 `3296139` → `origin/main`**(우리 쪽)이다. +> ⇒ ★**이 구별이 계획에 직결된다**: 「upstream 이 안 건드리는 파일」로 읽으면 «영구 무충돌»이지만, 참인 술어로 읽으면 +> ★**우리가 그 파일을 손대는 «순간» 충돌한다** — 바로 아래 ⑶ 및 `string.rs`·`test_timer.rs` 가 그 기전의 실례다. +> ⑶`throwable.rs` 는 upstream 이 **+81/−29** 로 고쳤는데 ★**우리 쪽이 `3296139` 와 바이트 동일**이라 깨끗이 적용된다 +> ⇒ ★**S3 가 upstream 의 오류 분류 축을 «채택»해 수렴시킨 결과다** — 앞 회차의 설계 판단이 뒤 회차의 충돌을 **지웠다**. +> +> ★★**「예측은 하한이다」 — 대체로 맞지만 «절대적이지 않다». S7 에서 처음 깨졌다.** +> 각 회차를 «그 회차가 실제로 돈 base» 에서 보면: +> S1 `2`↔**2**(일치) · S2 `+5`↔**5**(복원 후 · 일치) · S3 `+9`↔**11**(초과) · S4 `0`↔**2**(복원 후 · 초과) · +> S5 `0`↔ⓒ**+3**(초과) · S6 `0`↔**+0**(일치) · **S7 `+3`↔ⓒ+1 · ⓐ+2** ★**미달**. +> ⇒ ★**하한으로 «쓰되» 근거로 삼지 마라.** 초과는 «우리 로컬 분기»가 만들고(S5), 미달은 «앞 회차가 수렴시켜서» 난다(S7). +> ★**티켓 size/timeout 은 여전히 하한 쪽으로 잡아라** — 미달은 공짜지만 초과는 회차를 넘긴다. +> +> **S5~S7 재조정 판정**(수만 바뀌고 순서·축은 불변): +> - **S5** = 「충돌 0 물량」이 **아니다.** `string.rs` 는 **설계 판단**(우리 charset/`value_range` 분기 ↔ upstream +285/−31)이 붙는다. +> `test_timer.rs` 는 **S4 여백(2000ms)을 upstream 재작성 위에 다시 얹는** 기계 작업이고, `Cargo.lock` 은 **재생성**이다. +> - **S6** = 진짜 「새 충돌 0」이다(S5 를 닫으면 남는 게 없다). +> - **S7** = `thread.rs` 1건. ★**STATE ①의 「`thread.rs` 는 S5~S7 도 「또 충돌한다」를 기본값으로 잡아라」가 «절반» 맞았다** — +> S5·S6 은 **충돌하지 않고** S7 에서만 다시 열린다. 해소 전략은 불변(upstream 본문 + `#[tracing::instrument]` 한 줄만 수동 span 치환). +> - ★**착수 시 재측정 의무는 «남는다»** — 다만 근거가 바뀌었다. 이제 `merge-base` 는 전진하므로 이유는 「계보가 끊겨서」가 +> 아니라 ★**「upstream/main 이 계속 전진하기 때문」**이다(2026-08-16 `ba5797b` 였던 헤드가 지금 `bd42427`, behind **30**). +> +> ★★**부수 발견 — 「7회차」는 더 이상 upstream 헤드에 닿지 않는다. S8 이 필요하고, 그것이 남은 회차 중 «제일 크다».** +> 컷 간 커밋 수 실측(★**전부 «증분» = 앞 컷을 왼쪽 끝점으로 둔 구간**): +> `3296139..c4665b0` **6** · `c4665b0..95ebc5c` **11** · `95ebc5c..ba5797b` **1** · ★**`ba5797b..upstream/main` 12**(합 **30** = behind). +> ★**초판은 뒤 셋을 `..95ebc5c` 처럼 왼쪽 끝점을 생략해 적어 «`3296139..` 누적»으로 오독될 수 있었다**(정정 2026-09-04). +> 참고로 누적은 `3296139..95ebc5c` **17** · `3296139..ba5797b` **18** 이다 — **증분과 다른 수다**. +> 그 12커밋 구간의 ⓒ 기준 누적 충돌 = ★**11**(S7 의 4 대비 **+7**)이고, 성격이 앞 회차들과 **다르다**: +> `java_runtime/` → **`rustjava-runtime/`** · `test_data/` → **`test-data/`** 로 **크레이트·디렉터리가 개명**됐다. +> ⇒ 새로 걸리는 7건이 ★**우리 고유 산출물에 정확히 꽂힌다**: `rustjava-runtime/src/charset.rs`(PR #5) · +> `test-data/UnsupportedCharset.class` · `test-data/UnsupportedCharset.txt` · ★**`test-data/src/UnsupportedCharset.java`**(PR #5 픽스처) · +> `test-data/TimeApi.class` · `test-data/TimeApi.txt`(PR #2 픽스처) · `java_runtime/tests/classes/java/lang/test_string.rs`. +> ★★**[2026-09-04 정정] 초판의 `test-data/UnsupportedCharset.{java,class,txt}` 는 «경로 오기»다** — `.java` 만 +> `test-data/src/` 아래에 있다. ★**S8 의 첫 조치가 `--find-renames` 대응표 고정이라 이 목록의 경로는 정확해야 한다** +> (★이 회차가 §5 에서 정정한 결함이 정확히 «경로 오기»였다 — 같은 자리를 두 번 밟았다). +> ★**개명 충돌은 내용 충돌보다 위험하다** — 3-way 가 rename 을 놓치면 우리 픽스처가 «삭제 대 수정»으로 나타나 **조용히 사라질 수 있다.** +> ⇒ S8 은 「물량」이 아니라 **별도 판정 회차**로 잡아라(발권 전 `--find-renames` 로 대응관계를 먼저 고정). + ★**S1~S3 이 이 동기화의 «전부»다** — 세 회차가 판단을 다 쓰고, 각각 **한 축씩만** 다룬다. 검수자가 한 회차에서 읽어야 하는 것은 **우리 해소분**이지 upstream 원본 diff 가 아니다: diff --git a/docs/worklog/2026-09-03-upstream-sync-s5-s7-remeasure.json b/docs/worklog/2026-09-03-upstream-sync-s5-s7-remeasure.json new file mode 100644 index 00000000..9b0b9f4a --- /dev/null +++ b/docs/worklog/2026-09-03-upstream-sync-s5-s7-remeasure.json @@ -0,0 +1,59 @@ +{ + "schema": 1, + "date": "2026-09-03", + "title": "S5~S7 「새 충돌」 재측정(세 base 병기) + 「충돌 수에 base 병기」를 §5 상시 규칙으로 채택", + "services": [ + "RustJava" + ], + "taskId": "rustjava-upstream-sync-remeasure-s5-s7-and-lock-restore-basis", + "summary": "PR #18 이 --merge 로 착지해 merge-base origin/main upstream/main 이 3296139c 로 전진한 뒤 기준으로 S5~S7 을 다시 쟀고, 세 base 를 병기했다(ⓐ계획 기준 03438b0 · ⓑ복원 전 3a59776 · ⓒ복원 후 8c1238b). 같은 컷 ba5797b 가 base 에 따라 19 · 112 · 4 로 갈린다(28배). 새 충돌(ⓒ) = S5 +3 · S6 +0 · S7 +1 이고, S5 는 「충돌 0 물량」이 아니다. 그 3건(Cargo.lock · string.rs · test_timer.rs)은 전부 upstream 이 아니라 우리가 앞 회차에 남긴 로컬 분기가 만든다 — test_timer.rs 는 S4 가 넣은 500→2000ms 여백 그 자체다. 예측 대 실측은 예측이 나온 기준(ⓐ)끼리 짝지었다: S5 0↔+1 일치 · S6 0↔+0 일치 · S7 +3↔+2 예측 과대. 「예측은 하한」은 S7 에서 처음 깨졌다 — Cargo.lock 이중 계상 · class_format_error.rs 경로 오기 · class_format_error.rs 와 throwable.rs 는 둘 다 우리 쪽이 3296139 와 바이트 동일이라 upstream 변경(+4/−3 · +81/−29)이 깨끗이 적용된다(S3 가 upstream 오류 분류를 채택해 수렴시켰다). 판정: 「충돌 수를 적을 때 base 를 반드시 병기한다」를 docs/upstream-sync-approach.md §5 상시 규칙으로 두었다.", + "changes": [ + "docs/upstream-sync-approach.md §5 — 「[상시 규칙 · 2026-09-03 채택] 충돌 수를 적을 때는 base 를 반드시 병기한다」 절 신설(형식 · 19/112/4 근거표 · 병기해야 할 두 축) + 「[2026-09-03 재측정]」 블록 신설(세 base 대조표 · ⓒ 충돌 파일 목록 · 예측 대 실측 · S5~S7 재조정 판정 · S8 부수 발견).", + "docs/upstream-sync-approach.md 「제안 — 7회차」 표 — S5~S7 「새 충돌」 칸을 취소선 + 화살표로 정정하고(사료 보존) 표 아래에 「취소선 칸은 2026-08-16 계획 기준의 사료다 — 지우지 마라」 표지 추가. 2026-08-27 정정 블록은 무접촉.", + "STATE.md — 진행중 항목 신설 · ① 절의 「S4 착지 대기」·「다음은 S4」·「예측은 하한 3회 연속」·「thread.rs 는 S5~S7 도 기본값」 네 곳을 취소선/정정 표지로 갱신.", + "REPORT.md — [2026-09-03] 요약 3줄 + 검증 + 후속 추천 2건 append.", + "docs/worklog/2026-09-03-upstream-sync-s5-s7-remeasure.{md,json} 신설." + ], + "deploy": { + "sha": "", + "urls": [] + }, + "verification": "선행 조건 실측: gh pr list -R Jun025/RustJava --state open → 0건 · PR #18 머지커밋 8c1238b 부모 2개 · git merge-base origin/main upstream/main = 3296139cc7ce63822941db5180bd19a8545367e4 · git rev-list --count origin/main..upstream/main = 30. 측정: git merge-tree --write-tree --name-only 의 2번째 줄~첫 빈 줄 앞까지를 센다(그 뒤 Auto-merging 정보 블록을 세면 안 된다. ★[2026-09-04 정정] 초판의 「148 → 실제 3」은 두 base 를 섞은 짝이다 — 오파싱 148 은 base 3a59776(ⓑ)에서만 나오고 그 base 의 참값은 45 다(같은 오파싱을 ⓒ 8c1238b 에 돌리면 15/참값 3 · ⓐ 03438b0 이면 58/참값 17). 정확한 문장은 「base 3a59776 에서 148(참값 45)」이고, 파싱 결론 자체는 참이다). ★방법 검증: 계획서 §5 첫 표의 base 03438b0 로 같은 파싱을 돌리면 0·1·2·2·7·16·17·17·17·19 가 한 자리도 안 틀리고 재현된다. 결과 — ⓐ(base 03438b0 · merge-base 62cf0c6a): 3296139=16 · c4665b0=17 · 95ebc5c=17 · ba5797b=19. ⓑ(base 3a59776 · merge-base 62cf0c6a): 10 · 45 · 61 · 112. ⓒ(base 8c1238b · merge-base 3296139c): 0 · 3 · 3 · 4. ★ⓑ↔ⓒ 차이가 계보뿐임을 통제: ⓒ 트리를 ⓑ 계보에 얹은 합성 커밋 git commit-tree 4788ef2f -p 3a59776(ref 미생성)로 재도 45·61·112 로 동일 ⇒ 문서 4파일 diff 영향 0. S7 예측 미달 근거: ★[2026-09-04 정정] 초판이 class_format_error.rs 를 「3296139..ba5797b 에서 upstream 변경 0」이라 적은 것은 거짓이고 0 인 쪽이 반대였다 — 실측 git diff --numstat 3296139 ba5797b -- java_runtime/src/classes/java/lang/class_format_error.rs → 4 3(=+4/−3)이고, 0 줄인 것은 git diff --numstat 3296139 origin/main -- 같은 경로다(블롭 0dbd369a3d906dce6d7bfce470f20606eaf4acf1 로 3296139 와 origin/main 이 동일). ⇒ 충돌하지 않는 이유는 「우리 쪽이 merge-base 와 바이트 동일」이다. throwable.rs 도 같은 술어다 — 우리 git diff --numstat 3296139 origin/main 0줄(블롭 30ace64c 동일)인데 upstream 3296139→ba5797b 은 +81/−29. ★결론(S7 예측 과대 = ⓐ +2)은 불변이다. ★[2026-09-04 정정] 우리 쪽 numstat 방향 — 정본은 git diff --numstat 다: string.rs +8/−28 · test_timer.rs +8/−1(초판의 +28/−8·+1/−8 은 역순 diff origin/main 3296139 출력이라 폐기). upstream 열은 방향이 옳았다(3296139→c4665b0 = string.rs +285/−31 · test_timer.rs +626/−46) ⇒ 한 표 안에서 방향이 섞였던 것이고, 그래서 §5 상시 규칙에 diff 방향 토큰을 추가했다. 구간 커밋 수는 전부 증분이다: 3296139..c4665b0 6 · c4665b0..95ebc5c 11 · 95ebc5c..ba5797b 1 · ba5797b..upstream/main 12 = 합 30(누적은 3296139..95ebc5c 17 · 3296139..ba5797b 18 로 다른 수다). S8 축: ⓒ 누적 11 · java_runtime→rustjava-runtime · test_data→test-data 개명 · ★충돌 경로 실측 전문 11건 = Cargo.lock, java_runtime/src/classes/java/lang/string.rs, java_runtime/tests/classes/java/lang/test_string.rs, java_runtime/tests/classes/java/util/test_timer.rs, rustjava-runtime/src/charset.rs, rustjava-runtime/src/classes/java/lang/thread.rs, test-data/TimeApi.class, test-data/TimeApi.txt, test-data/UnsupportedCharset.class, test-data/UnsupportedCharset.txt, test-data/src/UnsupportedCharset.java(★.java 만 src/ 아래 — 초판의 UnsupportedCharset.{java,class,txt} 는 경로 오기). 락: python3 scripts/check-worklog-json.py rc=0. ★코드(.rs) 변경 0 이므로 cargo 축은 트리 입력 불변으로 담보된다.", + "issues": [ + "★S5 는 「충돌 0 물량」이 아니다 — ⓒ 기준 새 충돌 3건이고 그중 string.rs 는 설계 판단이다(upstream 3296139→c4665b0 +285/−31 ↔ 우리 3296139→origin/main +8/−28). S5 티켓을 「물량」으로 발권하면 size/timeout 이 처음부터 틀린다(S4 가 정확히 그렇게 틀렸다).", + "★「예측은 하한이다」가 절대적이지 않음이 처음 실측됐다 — S7 예측 +3 ↔ 실측 ⓐ+2 · ⓒ+1. 초과는 우리 로컬 분기가 만들고(S5 0↔+3) 미달은 앞 회차가 수렴시켜서 난다(S3 가 upstream 오류 분류를 채택). 하한으로 쓰되 근거로 삼지 마라.", + "★계획서 §5 표의 S7 「+3」은 Cargo.lock 을 S5·S7 에 이중 계상했고, class_format_error.rs 의 경로도 틀렸다(classfile/src/ 가 아니라 java_runtime/src/classes/java/lang/). 취소선으로 사료를 남기고 정정했다.", + "★「7회차」로는 upstream 헤드에 닿지 않는다 — ba5797b 뒤로 12커밋(헤드 bd42427 · 2026-08-31)이 더 붙었고 ⓒ 누적 충돌 11(S7 의 4 대비 +7)이다. 그 구간이 java_runtime/→rustjava-runtime/ · test_data/→test-data/ 개명 스윕이라 새 7건이 우리 고유 산출물에 꽂힌다: rustjava-runtime/src/charset.rs · test-data/UnsupportedCharset.class · test-data/UnsupportedCharset.txt · test-data/src/UnsupportedCharset.java(★.java 만 src/ 아래다) · test-data/TimeApi.class · test-data/TimeApi.txt · java_runtime/tests/classes/java/lang/test_string.rs. 개명 충돌은 3-way 가 rename 을 놓치면 픽스처가 「삭제 대 수정」으로 조용히 사라진다.", + "★옛 워크로그 .json(2026-08-27-upstream-sync-squash-convergence.json)의 수는 고치지 않았다 — 그 안의 수는 S2·S4 값이고 지금도 정확하며(이번 회차는 S5~S7 을 쟀다), 요구 ③ 사료 보존과도 정합한다. 대신 그 파일 proposals[1] 을 adoptedProposals 로 처분해 cockpit 패널에서 내렸다.", + "★.json 소비자는 proposals[]·adoptedProposals·declinedProposals 만 읽는다 — verification·issues·summary 에 적은 수는 cockpit 에 도달하지 않는다(사람 축이다). 이번 정정의 실물은 docs/upstream-sync-approach.md §5 · REPORT.md · STATE.md 에 있다.", + "S5~S7 을 실제로 수행하지 않았다 — 이 회차는 재측정과 문서다(티켓 non-goal). merge-tree 는 워킹트리·ref 를 만지지 않는 읽기 전용 측정이다.", + "머지하지 않았다 — 게이트②·③은 별 세션이다. upstream(dlunch/RustJava) 발신 0.", + "★[2026-09-04 게이트² 반려 처분] 측정 22셀은 전건 정확했고 «그 수를 설명하는 문장» 5건을 고쳤다: ⑴class_format_error.rs 의 「upstream 변경 0」은 거짓이고 0 인 쪽이 우리였다(major) ⑵우리 쪽 numstat 방향 반전 ⑶148 이 base 3a59776 의 오파싱인데 ⓒ의 참값 3 과 짝지어졌다 ⑷UnsupportedCharset.java 경로 ⑸구간 커밋 표기의 왼쪽 끝점 생략. 표·결론은 바꾸지 않았다.", + "★[게이트③ 2026-09-04] PR #19 를 ★--merge 로 착지시켰다(★--squash 아님 — rustjava 는 contracts/upstream-sync-repos.conf 등재 repo 라 스쿼시가 merge-base 를 fork 시점으로 되돌린다). 검수 핀 aafb5313(불이동) · 착지 «전» PR #20 이 먼저 들어와 REPORT.md·STATE.md 에 위치 충돌 2건이 났고 합집합으로 해소했다(코드 파일 충돌 0 · 해소면 밖 변경 0 — approach.md 와 이 워크로그 쌍은 승인 형상과 바이트 동일)." + ], + "proposals": [ + { + "title": "S8 을 신설하고 「개명 스윕 판정 회차」로 발권하라 — ba5797b 뒤 12커밋이 우리 픽스처를 조용히 지울 수 있다", + "plainSummary": "원본 저장소가 폴더 이름을 통째로 바꿨다(java_runtime → rustjava-runtime, test_data → test-data). 우리가 직접 만든 테스트 자료가 바로 그 폴더 안에 있어서, 평소처럼 합치면 「지워진 파일을 우리가 고쳤다」는 형태로 나타나 자칫 조용히 사라질 수 있다.", + "userBenefit": "우리가 PR #2·#5 에서 만든 회귀 잠금 픽스처(TimeApi · UnsupportedCharset)와 charset.rs 가 동기화 중에 유실되지 않는다. 유실되면 이미 고친 패닉 3지점이 아무도 모르게 다시 열린다.", + "why": "계획서 §5 의 「7회차」는 2026-08-16 헤드(ba5797b)까지만 덮는데, 지금 헤드는 bd42427 이고 그 사이 12커밋이 더 있다(behind 30). 그 구간의 누적 충돌은 base 8c1238b(merge-base 3296139c) 기준 11 로 S7 의 4 대비 +7 이고, 새로 걸리는 7건이 전부 우리 고유 산출물이다: rustjava-runtime/src/charset.rs · test-data/UnsupportedCharset.class · test-data/UnsupportedCharset.txt · test-data/src/UnsupportedCharset.java(★.java 만 src/ 아래다) · test-data/TimeApi.class · test-data/TimeApi.txt · java_runtime/tests/classes/java/lang/test_string.rs. 원인은 크레이트·디렉터리 개명이라 앞 회차들과 성격이 다르다.", + "tradeoff": "⑴별도 판정 회차로 잡으면 회차가 하나 늘지만 rename 대응관계를 먼저 고정할 수 있다(git diff --find-renames). ⑵S7 뒤에 「물량」으로 붙이면 충돌 11건을 한 회차에 만나고, 그중 5건이 바이너리 픽스처(.class)라 3-way 가 무력해 수동 판정이 필요하다. ⑶미루면 upstream 이 더 전진해 개명 이후 커밋이 쌓이고 대응관계가 더 흐려진다.", + "effort": "M — 개명 대응표 고정 + 픽스처 5건 경로 이전 판정 + charset.rs·test_string.rs 내용 충돌 해소 + 4종 green.", + "target": "docs/upstream-sync-approach.md §5(S8 행 추가) · rustjava-upstream-sync-s8 티켓" + }, + { + "title": "S5 티켓의 성격을 「물량」에서 「설계 판단 1건 포함」으로 바꿔 발권하라", + "plainSummary": "다음 동기화 회차가 「손댈 것 없는 단순 작업」으로 계획돼 있는데, 실제로는 우리가 고친 문자열 처리 코드와 원본의 대규모 개편이 정면으로 겹친다. 판단이 필요한 작업이다.", + "userBenefit": "티켓의 크기·시간이 처음부터 맞아서 회차가 넘어가지 않는다. S4 가 「충돌 0 물량」으로 발권됐다가 실제로 20충돌을 만난 전례가 있다.", + "why": "2026-09-03 재측정(base 8c1238b · merge-base 3296139c) 결과 S5 의 새 충돌은 0 이 아니라 3 이다: Cargo.lock(재생성) · java_runtime/src/classes/java/lang/string.rs(우리 3296139→origin/main +8/−28 ↔ upstream 3296139→c4665b0 +285/−31 = 설계 판단) · java_runtime/tests/classes/java/util/test_timer.rs(S4 가 넣은 500→2000ms 여백을 upstream 재작성 위에 다시 얹는 기계 작업). ★그 3건은 upstream 물량이 아니라 우리가 앞 회차에 남긴 로컬 분기가 만든다 — ⓐ 계획 기준에는 없던 파일이다.", + "tradeoff": "⑴성격을 바꿔 발권하면 size 가 S→M 이 되고 검수도 「해소분 0 증명」이 아니라 실제 hunk 검토가 된다. ⑵그대로 「물량」으로 두면 착수 세션이 설계 판단을 만나고, 계획서가 그것을 예고하지 않은 상태가 된다. ⑶string.rs 를 upstream 판본으로 통째 채택하면 판단이 사라지지만 PR #5 의 charset 배선이 되돌아갈 위험이 있어 그것 자체가 판정 사항이다.", + "effort": "XS — 티켓 문안과 size 조정. 실제 해소는 S5 회차 몫.", + "target": "rustjava-upstream-sync-s5 티켓 · docs/upstream-sync-approach.md §5" + } + ], + "resolvedIssues": [], + "adoptedProposals": [ + "2026-08-27-upstream-sync-squash-convergence#p1" + ], + "declinedProposals": [] +} diff --git a/docs/worklog/2026-09-03-upstream-sync-s5-s7-remeasure.md b/docs/worklog/2026-09-03-upstream-sync-s5-s7-remeasure.md new file mode 100644 index 00000000..9efbe704 --- /dev/null +++ b/docs/worklog/2026-09-03-upstream-sync-s5-s7-remeasure.md @@ -0,0 +1,212 @@ +# [2026-09-03] S5~S7 「새 충돌」 재측정 + 「base 병기」 상시 규칙 채택 + +**티켓**: `rustjava-upstream-sync-remeasure-s5-s7-and-lock-restore-basis` +**성격**: 문서 전용 · 코드 변경 **0** · upstream 발신 **0** · 머지 **0** + +--- + +## 왜 지금인가 — 선행 조건이 충족됐다 + +직전 회차(`…-squash-defeats-convergence-fix`)가 회신 안에 남긴 후속 2건을 집행한다. +그 회차는 「**PR #18 이 `--merge` 로 착지한 뒤**」를 선행 조건으로 달았고, 그것이 충족됐다: + +| 축 | 값 | 확인 방법 | +|---|---|---| +| PR #18 | **MERGED** · 머지커밋 `8c1238b` · 부모 **2개** | `gh pr list -R Jun025/RustJava --state open` → **0건** | +| `merge-base origin/main upstream/main` | ★**`3296139cc7ce63822941db5180bd19a8545367e4`** | S4 컷까지 전진 | +| behind | **30** | `git rev-list --count origin/main..upstream/main` | + +⇒ ★**계보가 실제로 전진했다.** 계획서 §5 가 전제하고 S1~S4 내내 깨져 있던 +「앞 회차가 착지하면 뒤 회차의 기준선이 바뀐다」가 **이 회차부터 처음으로 참**이다. + +--- + +## 측정 방법 — ★먼저 «방법 자체»를 검증했다 + +``` +git merge-tree --write-tree --name-only +``` +출력의 **2번째 줄부터 첫 빈 줄 앞까지**가 충돌 파일 목록이다. 그 뒤는 `Auto-merging` 정보 블록이라 +**세면 안 된다**(초기 시도가 그 블록까지 세서 `c4665b0` 를 잘못 읽었다). +★★**[2026-09-04 정정] 초판의 「148 → 실제 3」은 «두 base 를 섞은» 짝이다** — 하필 「base 를 섞지 마라」가 주제인 절에서 그랬다. +오파싱 **148** 은 ★**base `3a59776`(ⓑ)에서만** 나오고 **그 base 의 참값은 45** 다. 같은 오파싱을 +base `8c1238b`(ⓒ)에 돌리면 **15**(참값 3) · base `03438b0`(ⓐ)면 **58**(참값 17)이다. +⇒ 정확한 문장은 ★**「base `3a59776` 에서 148(참값 45)」** 이다. **파싱 결론(정보 블록을 세면 안 된다)은 그대로 참이다.** + +★**검증**: 계획서 §5 첫 표의 base(`03438b0` = 2026-08-16 당시 `main`)로 이 파싱을 돌리면 +**`0 · 1 · 2 · 2 · 7 · 16 · 17 · 17 · 17 · 19`** 가 **한 자리도 안 틀리고 재현**된다. +⇒ 아래 수는 «다른 방법으로 잰 다른 수»가 아니라 **같은 자로 잰 다른 base** 다. + +--- + +## 재측정 — ★세 base 병기 + +| 컷(회차) | ⓐ계획 기준 `03438b0`
(merge-base `62cf0c6a`) | ⓑ복원 **전** `3a59776`
(merge-base `62cf0c6a`) | ⓒ복원 **후** `8c1238b` = 현 `main`
(merge-base `3296139c`) | +|---|---|---|---| +| `3296139`(S4) | 누적 **16** | 누적 **10** | 누적 ★**0** | +| `c4665b0`(**S5**) | 누적 **17** · 새 **+1** | 누적 ★**45** | 누적 **3** · 새 ★**+3** | +| `95ebc5c`(**S6**) | 누적 **17** · 새 **+0** | 누적 ★**61** | 누적 **3** · 새 ★**+0** | +| `ba5797b`(**S7**) | 누적 **19** · 새 **+2** | 누적 ★**112** | 누적 **4** · 새 ★**+1** | + +★**ⓑ↔ⓒ 의 차이가 «계보뿐»임을 통제했다** — ⓒ 의 트리를 ⓑ 의 계보 위에 얹은 합성 커밋 +(`git commit-tree 4788ef2f -p 3a59776` · ref 미생성)으로 재면 **45 · 61 · 112 로 동일**하다. +⇒ PR #18 이 함께 실은 문서 4파일 diff 는 이 수에 **영향이 0** 이고, 갈리는 원인은 **100% `merge-base`** 다. + +**ⓒ 기준 충돌 파일**(= 다음 회차가 실제로 여는 것): + +| 회차 | 파일 | +|---|---| +| S5 | `Cargo.lock` · `java_runtime/src/classes/java/lang/string.rs` · `java_runtime/tests/classes/java/util/test_timer.rs` | +| S6 | (S5 와 동일 · **신규 0**) | +| S7 | +`java_runtime/src/classes/java/lang/thread.rs` | + +### ★★핵심 — ⓒ 의 새 충돌은 «upstream 이 만드는 것»이 아니다 + +S5 의 3건은 전부 **우리가 앞 회차에 남긴 로컬 분기**가 만든다: + +★**방향을 못박는다**(2026-09-04 보강 · 두 열 다 **왼쪽이 merge-base**): +우리 = `git diff --numstat 3296139 origin/main` · upstream = `git diff --numstat 3296139 c4665b0`. + +| 파일 | 우리 쪽 분기 `3296139`→`origin/main` | upstream `3296139`→`c4665b0` | 성격 | +|---|---|---|---| +| `string.rs` | **+8/−28** | **+285/−31** | ★**설계 판단** | +| `test_timer.rs` | **+8/−1**(= S4 가 넣은 500→2000ms 여백) | +626/−46 | 기계(여백 재적용) | +| `Cargo.lock` | — | — | 재생성 | + +★★**[2026-09-04 정정] 초판의 「우리 +28/−8 · +1/−8」은 «역순 출력»이었다**(`diff origin/main 3296139`). +★**같은 표의 upstream 열은 방향이 옳았다** ⇒ ★**한 표 안에서 방향이 섞였다 — 이 리니지의 반려 근인(「기준을 섞었다」)과 같은 종이다.** +실물 검산: `test_timer.rs` 우리 쪽 diff 의 `+` 는 **8줄**(주석 7 + `2000i64` 1) · `−` 는 **1줄**(`500i64`) ⇒ **+8/−1**. +크기는 옳으므로 「설계 판단」 결론과 후속 추천 2(size S→M)는 **유효하다**. +★그래서 §5 상시 규칙에 **diff 방향 토큰을 추가**했다(초판은 base 만 못박고 방향을 안 못박았다). + +둘 다 ⓐ 기준에는 **없던** 파일이다(2026-08-16 당시 우리 `main` 은 그 자리가 merge-base 와 동일했다). +⇒ ★**「upstream 물량이 크면 충돌도 크다」는 성립하지 않는다** — S7 은 diff 가 32만 줄대인데 새 충돌 **1건**이다. + +--- + +## 예측 대 실측 — ★같은 기준끼리 짝지었다 + +§5 표의 예측은 **ⓐ에서 나온 수**이므로 ⓐ와 짝짓는다: + +| 회차 | 예측 | ⓐ 실측 | 판정 | +|---|---|---|---| +| S5 | `0`(`Cargo.lock`만) | **+1**(`Cargo.lock`) | 일치(표기 차이) | +| S6 | `0` | **+0** | 일치 | +| S7 | `+3` | ★**+2** | ★**예측이 과대** | + +S7 이 빗나간 이유 3건 — **전부 실측된다**: + +1. `Cargo.lock` 은 **S5 에서 이미 충돌**한다 ⇒ S7 의 «새»가 아니다. 표가 **이중 계상**했다. +2. 표가 적은 `classfile/src/class_format_error.rs` 는 ★**경로가 틀렸다.** 실제 파일은 + `java_runtime/src/classes/java/lang/class_format_error.rs` 이고, ★**우리 쪽이 `3296139` 와 바이트 동일** + (블롭 `0dbd369a`)이라 upstream 의 **+4/−3** 이 깨끗이 적용된다. + ★★**[2026-09-04 정정] 초판의 「`3296139..ba5797b` 에서 upstream 변경 0」은 «거짓»이고 «0 인 쪽이 반대»였다**: + `git diff --numstat 3296139 ba5797b -- <경로>` → **`4 3`** · `git diff --numstat 3296139 origin/main -- <경로>` → **0줄**. + ⇒ ★**충돌하지 않는 진짜 이유는 「upstream 이 안 건드렸다」가 아니라 «우리 쪽이 merge-base 와 바이트 동일하다»** 이다. + ★**이 구별이 계획에 직결된다** — 전자로 읽으면 «영구 무충돌»이지만, 참인 술어로는 + ★**우리가 그 파일을 손대는 «순간» 충돌한다**(= 이 회차가 `string.rs`·`test_timer.rs` 에서 발견한 바로 그 기전). + ★**결론(S7 예측 과대 = ⓐ +2)은 무해하고 검수자가 독립 확인했다 — 바뀌지 않았다.** +3. `throwable.rs` 는 upstream 이 **+81/−29** 로 고쳤는데 ★**우리 쪽이 `3296139` 와 바이트 동일**이라 깨끗이 적용된다. + ⇒ ★**S3 가 upstream 의 오류 분류 축을 «채택»해 수렴시킨 결과다 — 앞 회차의 설계 판단이 뒤 회차의 충돌을 «지웠다».** + +### ★★「예측은 하한이다」 — 대체로 맞지만 «절대적이지 않다». S7 에서 처음 깨졌다 + +각 회차를 «그 회차가 실제로 돈 base» 에서 보면: + +| 회차 | 예측 | 실측 | | +|---|---|---|---| +| S1 | 2 | **2** | 일치 | +| S2 | +5 | **5**(복원 후) | 일치 | +| S3 | +9 | **11** | 초과 | +| S4 | 0 | **2**(복원 후) | 초과 | +| S5 | 0 | ⓒ **+3** | 초과 | +| S6 | 0 | **+0** | 일치 | +| **S7** | **+3** | ⓒ **+1** · ⓐ **+2** | ★**미달** | + +⇒ ★**하한으로 «쓰되» 근거로 삼지 마라.** 초과는 «우리 로컬 분기»가 만들고, 미달은 «앞 회차가 수렴시켜서» 난다. +★**티켓 size/timeout 은 여전히 하한 쪽으로** — 미달은 공짜지만 초과는 회차를 넘긴다. + +--- + +## 판정 ② — 「base 병기」를 §5 **상시 규칙으로 «둔다»** + +**형식**: `<수>(base · merge-base )` · 병기 없는 충돌 수는 **문서·회신·티켓 어디에도 쓰지 않는다.** + +★**두기로 한 이유 — 「좋은 습관」이 아니라 실측이다.** 같은 컷 `ba5797b` 가 base 에 따라 +**19 · 112 · 4** 로 갈린다(**28배**). 「충돌 4건」과 「충돌 112건」은 ★**둘 다 참**이고, base 가 없으면 +**어느 쪽도 검증할 수 없다.** + +★★**대안(「안 둔다」)을 실제로 검토했고 기각했다.** 「각 회차가 정확히 쓰면 된다」로는 막히지 않는다 — +직전 반려의 실제 형태가 그것이다: S2 회신(복원 후 **5**)과 S4 회신(복원 전 **20**)은 ★**각자는 정확했는데** +둘을 «한 표»로 모으는 순간 기준이 섞여 「우상향 계열」이라는 **없는 사실**이 만들어졌다. +⇒ ★**깨지는 지점이 «작성»이 아니라 «집계»라서, 작성 규율로는 도달하지 못한다.** 규칙이 붙어야 할 곳은 +«수를 적는 자리» 전부다. + +★**병기해야 할 축은 둘이다**(하나로는 부족): ⑴**복원 전** = 계보 미기록(= 「계보 미수렴의 비용」) +⑵**복원 후** = 계보 기록 뒤(= 「다음 회차의 실제 작업량」). **용도가 다르므로 둘 다 적는다.** + +--- + +## 사료 보존 방식(요구 ③) + +**덮어쓰지 않았다.** 두 가지를 함께 썼다: + +- §5 「제안 — 7회차」 표의 S5~S7 「새 충돌」 칸 = ★**취소선 + 화살표** + (`~~0(Cargo.lock만)~~ → ★+3`). 표 바로 아래에 **「취소선 칸은 2026-08-16 계획 기준의 사료다 — 지우지 마라」** 표지. +- 2026-08-27 정정 블록 **아래에 새 블록 추가**(`[2026-09-03 재측정]`). 기존 블록은 **1바이트도 안 건드렸다.** + +--- + +## `.json` 축 도달 여부(요구 ④) + +★**닿는다 — 단 «수정»이 아니라 «처분 기록»으로 닿는다.** + +- 이번 재측정은 `2026-08-27-upstream-sync-squash-convergence.json` 의 **`proposals[1]`** + (= ref `2026-08-27-upstream-sync-squash-convergence#p1`, 「S5~S7 의 「새 충돌」을 재측정할지 결정하라」) + **그 자체의 집행**이다. ⇒ 이 회차의 `.json` `adoptedProposals` 에 그 ref 를 실었다. + `AGENTS.md` 규약대로 **cockpit 「후속 작업 추천」 패널에서 그 카드가 내려간다.** +- ★**옛 `.json` 본문의 수는 «고치지 않았다»** — 그 파일의 `verification`·`proposals[*]` 에 있는 수는 + **S2·S4 값이고 지금도 정확**하다(이번 회차가 잰 것은 S5~S7 이라 겹치지 않는다). + 겹치는 문장은 `proposals[1].why` 의 「지금 재면 또 낡은 수가 된다」뿐인데, 그것은 ★**그 시점에 참이었고 + 이번 회차가 그 조건(착지 후)을 충족해 집행한 것**이라 정정 대상이 아니다. 요구 ③(사료 보존)과도 정합한다. +- ★**닿지 «않는» 축도 적어 둔다**: 옛 `.json` 을 읽는 소비자는 `proposals[]` 만 본다 + (`date`·`ref`·7필드 · `adoptedProposals`/`declinedProposals`). ⇒ **`verification`·`issues`·`summary` 에 적은 + 수는 cockpit 에 «애초에 도달하지 않는다»** — 사람이 읽는 축이다. 그래서 이번 정정의 실물은 + **`docs/upstream-sync-approach.md` §5 · `REPORT.md` · `STATE.md`** 에 있다. +- 락: `python3 scripts/check-worklog-json.py` **rc=0**. + +--- + +## 부수 발견 — ★S8 이 필요하고, 남은 회차 중 «제일 크다» + +「7회차」는 더 이상 upstream 헤드에 닿지 않는다. 컷 간 커밋 수 실측: + +★**전부 «증분» 구간이다**(앞 컷이 왼쪽 끝점): +`3296139..c4665b0` **6** · `c4665b0..95ebc5c` **11** · `95ebc5c..ba5797b` **1** · ★**`ba5797b..upstream/main` 12** (합 **30** = behind) +★★**[2026-09-04 정정] 초판은 뒤 셋을 `..95ebc5c` 처럼 왼쪽 끝점을 생략해 «`3296139..` 누적»으로 오독될 수 있었다.** +누적은 `3296139..95ebc5c` **17** · `3296139..ba5797b` **18** 로 **증분과 다른 수다**(수 자체는 증분으로 옳았고 합 30 도 맞다). + +그 12커밋 구간의 ⓒ 기준 누적 충돌 = ★**11**(S7 의 4 대비 **+7**)이고 성격이 앞 회차들과 **다르다** — +`java_runtime/` → **`rustjava-runtime/`** · `test_data/` → **`test-data/`** 로 **크레이트·디렉터리가 개명**됐다. +새로 걸리는 7건이 ★**우리 고유 산출물에 정확히 꽂힌다**(★**경로 실측 전문** — S8 이 그대로 인계받는다): + +`rustjava-runtime/src/charset.rs`(PR #5) · `test-data/UnsupportedCharset.class` · `test-data/UnsupportedCharset.txt` · +★**`test-data/src/UnsupportedCharset.java`**(PR #5 픽스처) · `test-data/TimeApi.class` · `test-data/TimeApi.txt`(PR #2 픽스처) · +`java_runtime/tests/classes/java/lang/test_string.rs` + +★★**[2026-09-04 정정] 초판의 `test-data/UnsupportedCharset.{java,class,txt}` 는 «경로 오기»다** — `.java` 만 +`test-data/src/` 아래다. ★**S8 의 첫 조치가 `--find-renames` 대응표 고정이므로 이 목록의 경로는 정확해야 한다** +(★이 회차가 §5 에서 정정한 결함이 정확히 «경로 오기»였는데 같은 자리를 두 번 밟았다). + +★**개명 충돌은 내용 충돌보다 위험하다** — 3-way 가 rename 을 놓치면 우리 픽스처가 «삭제 대 수정»으로 나타나 +**조용히 사라질 수 있다**. ⇒ S8 은 「물량」이 아니라 **별도 판정 회차**로 잡고, 발권 전 `--find-renames` 로 +대응관계를 먼저 고정하라. + +--- + +## 경계 준수 + +머지 **0** · 새 PR **1**(base `main` · ★**스택 PR 아님**) · force-push **0** · 리베이스 **0** · +`main` 직접 push **0** · 브랜치 삭제 **0** · ★**upstream(`dlunch/RustJava`) 발신 0**(전 `gh` 호출 `-R Jun025/RustJava` · +`git push` 대상 `origin` 단독) · ★**S5~S7 을 실제로 수행하지 않았다**(`merge-tree` 는 워킹트리·ref 를 만지지 않는 읽기 전용 측정) · +`wie-ktf-hardening` 무접촉 · 코드(`.rs`) 변경 **0** · 맨 `grep` **0**(`/usr/bin/grep`).