Skip to content

Latest commit

History

History
689 lines (663 loc) · 77.4 KB

File metadata and controls

689 lines (663 loc) · 77.4 KB

REPORT

[2026-09-05] behind 를 «재는» 예약 워크플로 신설 (rustjava-upstream-behind-measure-scheduled-workflow)

  • 무엇을: .github/workflows/upstream-behind.yml1개 신설. 주 1회 upstream 을 read-only fetchrev-list --count 를 찍고 Job Summary + annotation 으로 보고한다. ★코드(.rs) 0줄 · scripts/ 무접촉.
  • 왜: 2026-09-04 판정이 트리거를 behind ≥ 20 으로 못박았는데 ★그 수를 «재는 주체»가 없었다 (rev-list --count 를 가진 파일 0건). 임계만 있고 관측이 없으면 「아무도 안 챙긴다」가 그대로 남는다.
  • 사용자 영향: 런타임·CI 게이트 무변경(새 워크플로는 예약 전용이라 PR 검사에 들어가지 않는다). ★다음 동기 회차의 시점이 «사람 기억»에서 «주간 관측»으로 옮겨졌다.
  • 검증: ★한 번 돌려 오늘의 값을 냈다 — behind 0 · merge-basebd42427 = upstream HEAD ⇒ 임계 미만. 무회귀: check-dod-ci-parity.pyrc=0 · check-worklog-json.pyrc=0.
  • ★★알림 방식을 «실측으로» 골랐다(이 회차 결정의 대부분): ⒜red 는 여기서 안 듣는다 (선례 rust-audit 최근 20 run 중 19 failure · ★대응 티켓 0건 · coverage 리니지도 만성 red 를 «green 으로» 끝냈다) 이고 예약 red 는 main tip check-run 을 오염시킨다(★단 PR 은 막지 않는다 — 확인했다) · ⒞이슈는 ★이 fork 가 issues 비활성이라 불가 ⇒ ★⒝ 가 «남은 것»이고 그 수동성은 재개 조건으로 잰다.
  • 후속 추천: ⑴behind ≥ 207일 이상인데 회차가 안 열리면 알림 방식을 다시 열어라(세는 명령은 §5-B ⒠). ⑵★임계 20 과 「발권은 사람이 한다」는 이 회차가 건드리지 않았다 — 바꾸려면 새 결정이다.

[2026-09-05] 워크로그 «부재» 기계 강제 판정 — 넣지 않는다 (rustjava-worklog-absence-machine-enforcement-decision)

  • 무엇을: 채택 제안 2026-09-04-worklog-mandate-and-local-gate#p0 에 대한 판정이다. ★결론: 워크로그 «부재»를 잡는 기계 강제를 지금은 넣지 않는다check-worklog-json.py 의 「존재하는 .json 만 검사한다」 설계와 «소급 금지»를 그대로 둔다. ★검사기 무접촉 · .rs 0줄 · backfill 0.
  • 왜: ★★의무화 회차가 «데이터를 보기 전»에 등록한 두 임계가 «둘 다» 발화하지 않았다. 그 문서가 정한 재측 시점(「2026-09-04 이후 열 번째 착지 회차」)에 ★실제로 도달했고(실측 11), ⒜ 미작성 1 / 15(임계 ≥2 미달 · ★그 1건은 규약보다 먼저 갈라진 PR #13 이라 0 / 14 = 100%) · ⒝ 열린 카드 13(임계 <5 미달 — 의무가 카드를 늘렸다). ⇒ ★**데이터를 본 뒤 기계를 넣는 것은 «골대 옮기기»**다. 등록한 규칙을 지켰다.
  • 사용자 영향: 없다(CI·DoD·검사기 무변경). 회차 절차가 지금 그대로 유지된다.
  • 검증: 창·분모를 밝혀 전수로 쟀고(git rev-list --first-parent b3a4cf4..origin/main), ★정상 참작도 인용이 아니라 실측했다(PR #13 createdAt 2026-08-23 ↔ 규약 착지 2026-08-26). ★술어를 둘로 재서(느슨/엄격) 같은 14 임을 확인했고, ★문서에 박은 재개 조건 명령을 실행해 값 1 을 확인했다. 무회귀: check-worklog-json.pyrc=0 · check-dod-ci-parity.pyrc=0.
  • 약점을 숨기지 않는다: 「100%」는 단일 집행 주체의 습관일 수 있고(리니지 13개지만 git author 는 하나), 정본 술어는 느슨하며, ★실패는 여전히 조용하다 ⇒ 「위험이 없다」가 아니라 「임계가 아직 발화하지 않았다」이다.
  • 후속 추천: ⑴재개는 엄격 술어 값이 2 이상일 때만(오늘 1) ⑵재개 시 설계는 이미 적어 뒀다 — ★baseline sha 를 쓰지 말고 «PR diff 로 조건부» 판정하라(의무가 조건부이므로 검사도 조건부여야 한다).

[2026-09-04] upstream 동기 «정기 축» 판정 — 격차 기반 behind ≥ 20 (rustjava-upstream-sync-cadence-decision)

  • 무엇을: 채택 제안 2026-09-04-sync-contract-stale-assets-decision#p0 에 대한 판정이다. ★결론: 동기 회차는 origin/main..upstream/main 이 «20 이상»일 때 연다 — 시간(격주·월간) 기반은 기각. ★신설 0(검사기·크론·워크플로) · .rs0줄 · ★S9 미개시(behind 0). 바뀐 것은 docs/upstream-sync-approach.md§5-B 뿐이다.
  • 왜: ★★전제를 «먼저» 재서 «반증»했다. 회차 커밋 수 ↔ 충돌의 상관계수 ★부호가 «음»이다. ★★[게이트② 정정] 초판 표는 base·(델타/누적) 병기가 없어 기준이 섞여 있었다 ⇒ 정본을 «누적»으로 통일해 다시 계산했다: A 초판(혼재) r=−0.169 · 합 28 · B S4 만 정정 r=−0.134 · 합 30 · ★C 정본 «전부 누적» r=−0.155 · 합 33. ★세 열 모두 부호가 음이고 「많은4 < 적은4」가 유지된다(정본 C: 37커밋 → 148커밋 → 19) ⇒ ★판정 불변. ★단 r 은 n=8 비무작위 표본이라 «비례하지 않는다»는 «부호 판정»으로만 쓴다.누적 충돌도 포화한다(고정 base: 7커밋 16 → 33커밋 19) ⇒ ★충돌을 만든 것은 «양»이 아니라 «무엇이 왔는가»다. ★그래도 「아무것도 안 한다」로 가지 않았다 — 반증된 것은 «비용이 격차에 비례한다»는 기전이고, 제안이 지목한 «아무도 챙기지 않는다»는 위험은 그대로 참이라서 축은 두되 임계를 포화점 뒤에 놓았다.
  • 사용자 영향: 런타임 무변경. ★다음 동기를 «언제» 여는지가 처음으로 정해졌다 — 그 전엔 아무 기준이 없었다.
  • 검증: behind 0(요구값) · merge-basebd42427 = upstream HEAD · S1~S8 회차별 커밋/충돌 전수 · 게이트② 사이클 전수(reports/*.review.md 줄1 — 8회차 중 7회가 1사이클) · upstream 12개월 144커밋/51주(주당 중앙 1 · ★0인 주 37%) · 도달 시간 behind 20 = 중앙 44일 (★상수로 인용하지 마라 — 게이트② 재측 41일 · 차이는 창 정의에서 온다 ±3일 · 결론 영향 0).
  • 비용: 회차당 새 충돌 중앙 2.5(09) · 티켓 3건 · 연 **68회** ⇒ 연 18~24 티켓.
  • 방아쇠: 기계가 «재고» 사람(총괄)이 «발권» 한다. 재는 자리 권고 = 이 repo 의 예약 워크플로 (선례 rust-audit.yaml 이 이미 schedule: cron · upstream 은 read-only fetch 라 발신 0). ★구현은 별건.
  • 후속 추천: ⑴behind 를 «재는» 워크플로 1개(발권은 사람 유지) ⑵★**「8회차가 들었다」를 «격차 33 의 비용»으로 인용하지 마라** — 그 덩어리의 상당 부분은 스쿼시로 계보가 접힌 비용이고 merge_strategy: merge 로 이미 닫혔다.

[2026-09-04] 형제 repo 파리티 락 필요성 조사 — 둘 다 «조건부 필요», 검사기는 포팅 불가 (rustjava-dod-ci-parity-sibling-repo-survey)

  • 무엇을: 채택 제안 2026-09-04-dod-ci-parity-lock#p1 에 대한 ★읽기 전용 조사 + 판정이다. wie·qtsDoD 정본 위치 · CI 검사 집합 · 대칭차를 각각 실측하고, ★이력으로 실익까지 쟀다. ★형제 repo 변경 0(git·PR·파일 수정 전부 0 — gh api /contents 로만 읽었다) · 구현 0.
  • 왜: ★같은 처방이 그대로 맞는지 «먼저» 재라는 것이 제안 문면이었고, 재보니 ★맞지 않았다.wie 는 DoD 정본이 AGENTS.md 이고 CI 의 4번째 게이트(cargo test)가 ★**if: 로 갈린 2 step + 블록 스칼라라 우리 파서의 「조건부 = OS 축 = 제외」 규칙이 ★거짓 red** 를 만든다. qts 는 DoD 가 ★**make 타깃 이름이라 Makefile 간접층이 있고, ★toolchain 매트릭스가 없어 축 B 가 성립하지 않으며**, gitleaks 는 ★action 이라 못 본다.
  • 사용자 영향: 없다(이 repo 무변경). ★형제 repo 에 «측정된» 개선 경로 둘이 생겼다wie 이력 9/34(26%) · qts 이력 10/60(17%) 이 각각 «한 줄»로 로컬에 들어온다.
  • 검증: wierust.yml 최근 200 run(성공 166 · 실패 34) 실패 전수 분해 — stable-only clippy 24 · ★beta-only clippy 9 · windows test 1. qtsci.yml 최근 실패 60건 전수 분해ruff format --check 포함 38 · ★그것만 10 · ruff check 7 · phase0-only 0. ★문서 실측: 문자열 betawie 규범 문서에 0건 · 문자열 formatqts 규범 문서에 0건.
  • ★★일반 사실 하나: 세 repo 가 전부 이 어긋남을 갖고 있었고 ★어긋난 자리가 전부 규범 문서에 «적혀 있지 않았다» ⇒ ★**「사람이 문서를 최신으로 유지한다」가 세 repo에서 «각각» 실패했다** — 기계 대조의 일반 근거다.
  • 후속 추천: ⑴wie four gates 에 cargo +beta clippy --all -- -D warningsqtsmake lintuv run ruff format --check . ⑶★락 포팅은 그 «뒤»(락은 어긋남을 «막는» 것이지 «고치는» 것이 아니다). ★셋 다 그 repo 레인 소관이라 여기서 고치지 않았다 — 축과 합격선만 워크로그에 적었다.

[2026-09-04] 파리티 락 «교차곱» 확장 판정 — 넓히지 않는다 (rustjava-dod-ci-parity-cross-product-decision)

  • 무엇을: 채택 제안 2026-09-04-dod-ci-parity-lock#p0 에 대한 판정이다. ★결론: 교차곱으로 넓히지 «않는다» (부분 확장 fmt@beta 만도 기각). ★검사기 로직 변경 0 · .rs 0줄 · rust.yml 무접촉 · DoD 블록 무접촉 — 바뀐 것은 docs/upstream-sync-approach.md §4 의 판정 절과 검사기 docstring 1블록뿐이다.
  • 왜: ★비용과 실익을 «각각» 실측했다(추정 0).비용 — 무변경 재실행 19s → 38s(2.00×) ↔ ★소스 1줄 편집 후 89s → 326s(3.66×). 제안 문면의 「두 배」는 «무변경»에서만 참이고, 회차는 언제나 «편집 후»에 돌린다. 지배항은 cargo +beta test --all215s(같은 편집에서 stable test 66s 의 3.3배). 실익 — CI 에만 있는 조합은 3개로 비어 있지 않지만, ★★**rust.yml 이력 76 run(성공 73 · 실패 3) 전수 분해에서 그 3개가 «새로» 잡았을 사건은 0건**이다. 이 저장소의 beta 전용 실패는 전건 cargo clippy --all 이고 그 한 줄은 DoD 가 이미 +beta 로 덮는다. ⇒ +237s/회차를 내고 얻는 것이 0.
  • 사용자 영향: 없다(런타임·CI·DoD 무변경). 회차 소요가 지금 그대로 유지된다.
  • 검증: 벽시계 실측 3세트(warm · 편집 후 · 콜드) · CI 이력 전수 분해 · 재개 조건 명령을 실행해 오늘의 값 0 확인 · 측정용 소스 편집은 git checkout 으로 복구 · check-dod-ci-parity.pyrc=0(대칭차 0 유지).
  • 재고 나서야 보인 것 둘: ⑴rustfmtbeta 에 미설치cargo +beta fmt 는 오늘 그대로 rc=1 — 교차곱을 채택했다면 모든 머신이 rustup component add 를 선행해야 했다 ⑵★툴체인 교대 축출은 «없다» — 「두 배」의 흔한 기전(서로 캐시를 밀어낸다)이 이 저장소엔 없고, 대가는 시간이 아니라 디스크다(target 46G).
  • 후속 추천: ⑴재개 조건이 발화하면 그 step «하나만» 넣고 비용표를 다시 재라(이 표는 «그때의 값»이다). ⑵★「비용이 싸졌다」는 재개 사유가 아니다 — 실익이 0 인 동안에는 싸도 넣지 않는다.

[2026-09-04] 로컬 DoD ↔ CI 매트릭스 «기계 대조» 신설 (rustjava-local-dod-vs-ci-matrix-mechanical-check)

  • 무엇을: scripts/check-dod-ci-parity.py 신설 + rust.yml job dod_parity 배선 + DoD 블록에 그 줄 추가. ★**CLAUDE.md DoD 코드블록**과 .github/workflows/rust.yml 을 «각각 파싱해» 대칭차를 낸다 — 축 A(명령 집합) · 축 B(toolchain 집합). 오늘 둘 다 0 이라 계약대로 rc=1(막는다) 로 켰다.
  • 왜: …-going-stale 리니지가 다섯 회차 내내 「전건 동기」를 주장했고 매번 «또 한 자리»가 나왔다 (게이트②에서 6건째). ★전부 같은 종류 — 「로컬 DoD 가 CI 검사 몇 개를 재현하는가」가 rust.yml 과 어긋난 채 문서에 굳었다. ⇒ ★사람 손 대조로는 다섯 번 실패했다. ★★그런데 «낡은 문자열 스캐너»는 만들지 않았다 — 게이트② 검수자가 「F1 은 «수»가 아니라 «말»이라 문자열 검사기로도 안 잡힌다」를 실측으로 세웠기 때문이다. ⇒ 문서의 문장이 아니라 ★**문서가 틀리는 «원인»**을 잡는다.
  • 사용자 영향: 런타임 동작 무변경(.rs 변경 0). 회차가 DoD 를 축약하거나 CI 가 검사·매트릭스 차원을 늘렸는데 DoD 를 안 고치면 ★그 PR 이 그 자리에서 red 다 — 종전엔 «사람이 축을 돌려야» 드러났다.
  • 검증: ★개악 5건 전건 red · 무개악 green — ⒜DoD wasm32 줄 제거 ⒝CI - run: cargo doc --no-deps 추가 ⒞매트릭스 nightly 추가 ⒟DoD +beta 줄 제거 ⒠rust-toolchain.toml 신설(축 B 매핑 붕괴 가드). DoD 7줄 전건 rc=0 · cargo test --all554 / 0 / 1(새 red 0).
  • 한계를 숨기지 않는다 — 검사기가 «그 자리에서 함께» 찍는다: ⒜OS 축(조건부 step)은 로컬 재현 불가라 여전히 CI 가 유일한 그물 ⒝두 축을 «교차곱»으로 보지 않는다 — CI 는 cargo 검사 4종을 stable·beta 둘 다 치는데 DoD 는 clippy 만 이중이다. ★**이것은 2026-09-04 결정이 «고른 값»**이고(로컬 cargo +beta test = 두 번째 toolchain 전면 재빌드 · lint 를 지는 축은 clippy 뿐), 넓히는 것은 «새 결정»이다.
  • 후속 추천: ⑴교차곱(모든 검사 × 모든 toolchain)까지 넓힐지 — ★비용을 먼저 재고 결정하라. ⑵같은 형태의 파리티 락이 형제 repo(wie·qts)에도 필요한지 판정.

[2026-09-04] 「우리 자산이 낡는다」 상시 조항 판정 — 넣지 않고 «구멍 하나»를 막았다 (rustjava-sync-contract-standing-clause-for-our-assets-going-stale)

  • 무엇을: 운영자 채택 제안 ★(2026-09-04-upstream-sync-s6#p1 · …-s7#p1 · ★…-s8#p0)에 대한 결정이다. (★**[fix3 정정] 초판은 「둘」** — 같은 제안의 세 번째 판이 도착해 adoptedProposals세 ref 다.) ★결론: 상시 조항을 «넣지 않는다». 대신 ★로컬 DoD 가 CI 의 «매트릭스»를 재현하지 않던 것을 고쳤다 — CLAUDE.md DoD 가 이제 CI 명령 5줄 + toolchain 축 1줄 = «6줄»을 축약 없이 싣는다. ★코드(.rs) 변경 0 · 규범 문서 2파일(CLAUDE.md · docs/upstream-sync-approach.md) + 기록 문서 4 (REPORT.md · STATE.md · 워크로그 .md/.json). ★**[게이트② 정정] 초판은 「CI 검사 5종 중 wasm32 clippy 한 줄」이라 적었다** — 계수 «1» 시절 문면이고, 계수 2 정정 후에는 두 축(target · toolchain)이라 DoD 도 6줄이다. ★★**[후속 정정] 그 «6줄»도 낡았다 — 파리티 검사기가 더해져 «7줄»이다.** ⇒ ★줄 수는 이제 문장이 아니라 scripts/check-dod-ci-parity.py 가 센다(CI job dod_parity).
  • 왜: ★목록 문서화로 시작하지 않고 «먼저 셌다»(티켓이 그렇게 요구했다). 우리 자산 8건을 ★돌연변이로 깨뜨려 무엇이 잡는지 실측했다 — 경로 문자열·setProperty 서술자·charset 라우팅· ClassFormatError 종류 단정은 cargo test RED, 수동 span 은 clippy RED, double_must_use allow 는 깨져도 무해, 워크로그 스크립트는 로컬 DoD 와 CI 둘 다 잡는다. ⇒ ★★**[게이트② request-changes 정정] 「아무것도 없음」은 «2개»다**(② CI --exclude · ⑦ double_must_use allow). 초판이 ⑦을 «비하중» 자리에서 재 「무해」로 적었으나, ★9곳 전건 삭제로 재측정하면 stable 0 · ★beta RED(rc=101 · 진단 6건) ⇒ ⑦의 그물도 CI 만이다. ⇒ ★**「1개면 그 하나를 고쳐라」 규칙은 적용되지 않는다.** ★★게다가 그 1개도 «조용히» 실패하지 않는다 — cargo 가 warning: excluded package(s) … not found 를 찍고 빌드가 깨진다 ⇒ ★문제는 «침묵»이 아니라 «늦음»(push 후 CI 에서만)이고, ★근인은 「자산 목록이 없다」가 아니라 «로컬 DoD 가 CI «매트릭스»를 재현하지 않는다» 였다 — ②는 빠진 - run: 줄(target 축) · ⑦은 빠진 toolchain 축(beta) ⇒ ★한 근인의 두 얼굴이다. ⇒ ★결론은 그대로 「넣지 않는다」이나 논거가 바뀌었다: 근인 하나를 고치면 둘 다 그물을 얻는다 (DoD 에 cargo +beta clippy 를 넣자 ⑦이 로컬에서 RED(rc=101 · 진단 6건)로 잡힌다 · 실측).
  • 사용자 영향: 런타임 동작 무변경. 회차가 로컬에서 CI 와 같은 6줄(★toolchain 축 포함)을 돌리게 되어 ★**「로컬 green 인데 CI red」 부류가 이 축에서 사라진다**(S5·S7·S8 이 실제로 그 부류였다).
  • 검증: DoD 6줄을 문면 그대로 실행 — 전건 rc=0(★cargo +beta clippy --all -- -D warningsrc=0 포함) · cargo test --all554 / 0 / 1(baseline 동수 · 새 red 0). ★돌연변이는 전부 복구했고 .rs 변경은 0이다.
  • ★★사료 — 「세 번」·「두 방향」을 확정하되 결론은 «한 조항으로 못 덮는다»: S3(문구 단정 3건 · 테스트) · S5(io 5곳 · 테스트) · S6(regex 3곳 · 정독) = ⑴신규/판본 교체 · S7(우리 테스트 5곳 · 컴파일) = ⑵공용 API 변경 · S8(rust.yml·경로 4곳 · CI만/테스트) = ⑶개명. ⇒ ★잡는 그물이 각각 다르므로, 조항 하나로 덮으면 이미 그물이 있는 여섯 자리에까지 사람 확인을 얹게 된다 (★세는 법: 돌연변이 표 8행 − 그물이 「CI 만」인 2행(② · ⑦) = 6 · 명령은 docs/upstream-sync-approach.md §4. ★**[게이트② 정정] 초판의 「다섯」은 계수 «1» 시절의 파생 수였다** — 계수가 2 가 되며 6이 맞다).
  • ★★재개 조건(결정에 재개 조건이 없으면 «영구 종결»로 읽힌다): 「CI 가 치는 검사 중 로컬 DoD 에 없는 것이 1건이라도 생기면 다시 연다」 · ★세는 명령을 docs/upstream-sync-approach.md §4 에 박았고, 정정으로 «축이 둘»이 됐다 (축① - run: 줄 · ★축② toolchain 매트릭스) · ★오늘의 값 = 축① 0 · 축② 0(착수 시 축① 5 · 축② 1). ★세 돌연변이로 각 축이 «자기 자리»에서만 반응함을 실측했다.
  • ★★**[정정] 초판 후속 추천 3번을 «철회한다»** — 「double_must_use allow 가 이제 지워도 통과한다」는 비하중 돌연변이에서 나온 거짓이다. ★9곳을 전건 지우면 beta clippy 가 RED 다(rc=101 · 진단 6건) ⇒ ★지우지 마라.
  • 후속 추천: ⑴게이트③은 --merge(등재 repo). ⑵★upstream 동기 «정기 축» 판정은 아직 열려 있다 (S8 워크로그 proposals[1] · behind 0 인 지금이 적기다) — 이 회차는 그것을 «건드리지 않았다». ⑶★C7 고지: DoD 블록 «개악»과 OS 축 3종은 이 대조가 못 잡는다 — 회차가 두 축을 «실제로 돌렸는지» 적어라.

[2026-09-04] upstream 동기 S8 — 컷 bd42427 개명 스윕 · ★behind 0 (rustjava-upstream-sync-s8-rename-sweep-decision)

  • 무엇을: upstream bd42427 까지 12커밋(crates.io 공개 준비 개명 스윕)을 --merge 로 흡수하고 충돌 8건을 해소했다. ★★**merge-baseba5797bbd42427 · behind 12 → ★0** · 부모 2개 ⇒ ★★★upstream 을 «완전히» 따라잡았다(2026-08-16 계획 착수 시 behind 33 → 오늘 0).
  • 왜: 운영자 채택 제안 2026-09-03-upstream-sync-s5-s7-remeasure#p0 — 「개명이 우리 픽스처를 조용히 지울 수 있다」. ★**이 회차의 산출은 코드가 아니라 «판정»**이었다: 어느 픽스처가 어디로 가는가.
  • 사용자 영향: 크레이트 이름이 공개용으로 바뀐다(java_runtimerustjava-runtime · jvm_rustjvm-bytecode · java_class_protojvm-class-proto · java_constantsjvm-types · test_utilstest-utils · test_data/test-data/). ★런타임 동작 변경 0 · 우리 자산 전수 생존.
  • 검증: stable 4종 + ★beta 2종 rc=0 · cargo test --all554 / 0 / 1 · beta 도 554 동수 · ★증감 0 이고 그것이 맞다(upstream 테스트 함수도 547 → 547 — 개명 스윕이라 추가 0) · #[ignore]1 → 1 · 우리 테스트 함수 558 → 558.
  • ★★두려워한 형태(modify/delete)가 «0건»이었다. git 이 CONFLICT (file location) + AU 로 처리해 우리 고유 6건을 새 경로로 이미 옮겨 두고 «이동 확인»만 요구했다 ⇒ 처분은 「간다」 전건이고 ★**origin/main 블롭 ↔ 새 경로 해시가 6건 전부 동일**(바이트 보존) · ★픽스처 수 5 → 5. ★「남는다/버린다」는 0 — 여섯 다 우리 것이고 upstream 판본으로 대체된 것이 없다.
  • ★★대신 개명이 «우리 자산 2건»을 낡게 만들었다 — 「우리 자산이 낡는」 5회째이고 «대상»이 처음이다: ⑴.github/workflows/rust.yml--exclude test_utils옛 크레이트 이름이라 wasm32 셀이 깨진다 (★실측: 옛 이름 rc=101 ↔ 새 이름 rc=0) ⑵tests/test_class_format.rs(PR #3)의 "test_data/"4곳. ★둘 다 «우리 파일»이라 충돌이 «날 수가 없다» — 개명 대응표를 그대로 적용했고 upstream 코드는 무접촉. ⇒ ★이제 이 형태의 방향이 셋이다: ⑴upstream 신규 파일 ⑵공용 API 변경 ⑶★개명. ★⑶은 컴파일이 «절반만» 잡는다 — 경로 문자열은 런타임, CI 설정은 CI 에서만 드러난다.
  • ★**Cargo.lock 하강을 차단했다**(계약6⒞가 «또» 잡았다): --theirs+build 가 tracing0.1.44 → 0.1.41 · tracing-subscriber · syn 을 내렸다. ★**tracing 하강은 PR #4(언프리즈)를 되돌리는 것이라 S5 와 같은 처방(origin/main lock 에서 재생성)으로 ★내려간 것 0 · tracing 0.1.44 유지**.
  • 후속 추천: ⑴게이트③은 반드시 --merge(등재 repo). ⑵★behind 0 이 됐으므로 다음 동기 회차는 «upstream 이 움직일 때»다 — 정기 축이 필요하면 별건 판정. ⑶★**「우리 자산이 낡는」 축의 계약화**가 이제 다섯 회차 미처분이고, 이번에 **세 번째 방향(개명)**이 드러났다.

[2026-09-04] upstream 동기 S7 — 컷 ba5797b 머지 + §5 서식에 «델타/누적» 축 (rustjava-upstream-sync-s7-and-fix-the-conflict-count-format)

  • 무엇을: upstream ba5797b(#201 가상 디스패치 해석 · 1커밋 · 319파일 +20,118/−5,729)을 --merge 로 흡수하고 충돌 1건을 해소했다. 함께 ★**§5 「충돌 수」 정본 서식을 <수> <델타|누적>(base <sha> · merge-base <sha>) 로 고쳤다.** ★**merge-base95ebc5cba5797b** · behind 13 → 12 · 부모 2개 ⇒ ★★계획 7회차(S1~S7) 완주.
  • 왜: ⑴S6 이 「예측 0 ↔ 실측 1」로 갈렸고 검수자가 근인을 서식의 구멍으로 지목했다 — base 만 병기하면 ★**「3 → 3」과 「0」이 둘 다 규칙을 지킨다.** ⑵S7 이 충돌 수를 «새로» 적는 회차라 ★그 서식을 이번에 고치는 것이 가장 쌌다(같은 순간에 만난다). ★착수 재측정은 신 서식으로 적었다: 컷 ba5797b = 누적 1 · 델타 +1(base 3e02f8c · merge-base 95ebc5c). ★**「예측대로였다」가 아니라 「재서 1 이었다」.** string.rs 는 집합에서 빠졌다(S6 해소 뒤 무접촉) ⇒ ★누적은 줄어들 수도 있다 — 그래서 누적을 델타로 대신할 수 없다.
  • 사용자 영향: ★가상 메서드 디스패치 해석이 JVM 규격에 맞게 고쳐진다invoke_virtual 이 «선언 클래스»를 받아 상속·오버라이드 해석이 정확해지고, 전 클래스에 접근 플래그(PUBLIC/PRIVATE)가 부여된다. ★우리 자산 변경 0(charset 라우팅 7곳 · setProperty 서술자 · 수동 span · double_must_use allow 7곳 · 픽스처 4).
  • 검증: stable 4종 + ★beta 2종 rc=0 · cargo test --all554 / 0 / 1 · beta 도 554 동수 · ★시험 수 증감 0 이고 그것이 맞다 — upstream 테스트 함수도 95ebc5c547ba5797b547 (78개 테스트 파일을 +14,730/−3,536 로 만지지만 시그니처 스윕이지 추가가 아니다) · ★약화 0: #[ignore]1 → 1 · 우리 테스트 함수 558 → 558 · 단언 삭제 0 · 「해소분 0」 = ba5797b 대비 삭제 파일 0 · 다른 파일 52건 전수 우리 자산 · Cargo.lock내려감 0 · 올라감 0 · 추가 0 · 제거 0.
  • ★★**thread.rs 는 «직교»다 — 「어느 쪽이 이기나」가 아니다.** upstream(+23/−10)은 invoke_virtual 에 «선언 클래스» 인자를 더했고, 우리(+50/−42 · ★의미 변경은 3줄이고 나머지는 들여쓰기)는 그 호출들을 감싸는 수동 span(PR #4 · #[tracing::instrument] 금지)이다 ⇒ 의미가 겹치지 않는다. 우리 구조를 뼈대로 upstream 새 인자 3곳을 얹었다(S1·S3·S4 와 같은 전략 · 4회째).
  • ★★**「충돌 0으로 들어온」 파손 «4회째» — 그런데 축은 «처음»이다.** upstream 이 공용 API 시그니처를 바꾸자 ★우리 고유 테스트 5곳(PR #5 자산)이 구식 4인자로 남아 컴파일 실패(E0061×5). ★우리 줄이라 upstream 이 안 건드렸고 ⇒ 충돌이 «날 수가 없다». ⇒ ★S3·S5·S6 과 «반대 방향»이다(그쪽은 upstream 신규 파일이 우리 규격을 안 지킨 것) — ★그래서 「신규 파일을 훑는다」로는 못 잡고, 이번에 잡은 것은 «컴파일»이다. 처분은 upstream 자신의 관용구를 그대로 채택(&x.class_definition().name() · "java/lang/String") · 단언 무접촉.
  • 후속 추천: ⑴게이트③은 반드시 --merge(등재 repo · merge_strategy: merge 필수). ⑵★S8 — 남은 behind 12 가 «개명 스윕»(java_runtime/rustjava-runtime/ · test_data/test-data/)이고 우리 픽스처에 꽂힌다. 총괄 보류분 2026-09-03-upstream-sync-s5-s7-remeasure#p0이 회차는 집행하지 않았다. ⑶★**「우리 자산이 낡는」 축을 계약에 넣을지 판정하라** — 이번 4회째로 두 방향이 다 확인됐다 (upstream 신규 파일 ↔ upstream 시그니처 변경). 후자는 컴파일이 잡지만 전자는 안 잡는다.

[2026-09-04] upstream 동기 S6 — 컷 95ebc5c 머지 (rustjava-upstream-sync-s6-cut-95ebc5c)

  • 무엇을: upstream 95ebc5c(11커밋 · 142파일 +17,593/−483)을 --merge 로 흡수하고 충돌 1건을 해소했다. ★**merge-base origin/main upstream/mainc4665b095ebc5c** · behind 24 → 13 · 머지커밋 부모 2개.
  • 왜: 운영자 채택 제안 2026-09-04-upstream-sync-s5#p0. ★**「새 충돌 0」을 «전제»로 쓰지 않고 다시 쟀다.** ★★그 0 은 «델타»였다 — 「풀 것이 없다」가 아니다. 옛 base 8c1238b 에서 누적 3 → 3(새로 나타난 파일 0)이고, 새 base a0b5d3c(merge-base c4665b0)에서 누적 1이다. 둘 다 참이다. string.rs 는 S5 의 설계 판단으로 우리 분기(+8/−28)가 남아 upstream 이 그 파일을 만지는 한 (이 구간 +402/−121) 계속 열린다. ⇒ ★**§5 에 한 줄 보탰다: base 와 «함께» «델타/누적»도 밝혀라.**
  • 사용자 영향: java.util.regex(Pattern·Matcher)·Formatter·Locale 이 들어온다 — String.format·정규식 API 가 처음으로 동작한다. ★우리 자산 변경 0(charset 4종 · setProperty 서술자 · 수동 span · ClassFormatError 분류 · 픽스처 전건 생존).
  • 검증: stable 4종 rc=0 · ★beta 2종 rc=0(S5 가 물린 자리를 미리 확인) · cargo test --all554 passed / 0 failed / 1 ignored(S5 427 → +127 · 새 red 0) · beta 도 554 동수 · 「해소분 0」 = 95ebc5c 대비 삭제 파일 0 · 다른 파일 50건 전수가 우리 fork 고유 자산.
  • 해소: string.rs 충돌면은 import 한 곳뿐이라 합집합으로 풀었다 — 우리 charset::Charset + upstream 의 재구조화 classes::java::{lang, util::{Formatter, Locale, regex}}. Charset 라우팅 4곳 생존 · ★S5 가 버린 decode_str/encode_str 재유입 0.
  • ★★계약4⒝ 정독이 「충돌 0으로 들어온」 파손 1건을 «테스트를 돌리기 전에» 잡았다 — 이 형태 «세 번째»다. upstream 이 이 구간에 새로 넣은 java/util/regex/test_pattern_syntax_exception.rsSystem.setProperty)Ljava/lang/Object;3곳 부른다(우리는 PR #5 에서 JDK 규격대로 String). ★신규 파일이라 충돌이 «날 수가 없다»merge-tree 가 원리적으로 못 보는 자리다. 서술자만 맞췄다(S5 가 5곳에 적용한 확립된 처분). ★전례: S3 3건 → S5 5곳 → S6 3곳.
  • ★**Cargo.lock: S5 를 문 자리를 먼저 봤다 — ★내려간 크레이트 0건**(async-trait0.1.92 유지) · 올라간 3 · 추가 regex · 제거 2.
  • 후속 추천: ⑴게이트③은 반드시 --merge(merge_strategy: merge 필수 — 등재 repo). ⑵S7(컷 ba5797b · 95ebc5c..ba5797b1커밋) — 같은 base 에서 누적 2건(string.rs·thread.rs)이나 ★S6 착지로 base 가 또 바뀌므로 착수 시 다시 재라. ⑶★**「충돌 목록에 없는 파손」 축을 계약에 넣을지 판정하라 — 이제 3회째다**(S5 워크로그 proposals[1]).

[2026-09-04] upstream 동기 S5 — 컷 c4665b0 머지 (rustjava-upstream-sync-s5-with-remeasured-conflicts)

  • 무엇을: upstream c4665b0(#190 Java 1.2 runtime API 확장) 까지 6커밋(171파일 +33,138/−1,058)을 머지했다. 재측정된 충돌 3 해소 — Cargo.lock재생성 · string.rs설계 판단 · test_timer.rsupstream 채택. ★**merge-base origin/main upstream/main3296139cc4665b0** · behind 30 → 24 · 머지커밋 부모 2개.
  • 왜: §5 「[2026-09-03 재측정]」이 예고한 3건을 닫아 다음 회차(S6)의 기준선을 만든다. ★착수 시 재측정 결과가 그 표와 일치했다(그 사이 #19·#20 이 착지했으나 둘 다 문서 회차라 수가 안 바뀌었다).
  • 사용자 영향: Java 1.2 런타임 API 가 대폭 넓어진다String.copyValueOf 2종, compareTo(Object) 브리지, PrintStream/PrintWriter/BufferedReader·Writer 계열 계약 정비, Properties·Boolean·Integer·Long 파싱 경로, Timer 의 fixed-rate/fixed-delay·min-heap·overflow 처리. ★우리 자산 변경 0 — charset 4종 · System.setProperty 서술자 · ClassFormatError 4종 분류 · 수동 span · 픽스처 전건 생존.
  • 검증: green 4종 rc=0(fmt · clippy · wasm32 clippy · test --all) · cargo test --all427 passed / 0 failed / 1 ignored(S4 261 → +166) · ★「해소분 0」 = c4665b0 대비 삭제 파일 0 · 다른 파일 47건 전수가 우리 fork 고유 자산 · git grep 'tracing::instrument\|tracing-attributes' 실사용 0(주석 1건) · tests/test_class_format.rs4/4.
  • ★★**string.rs — 진짜 판단은 「어느 쪽을 취하나」가 아니라 「upstream 이 «되살린» 것을 버릴 것인가」였다.** upstream 이 copyValueOf 2종을 신설하며 decode_str/encode_str 하드코딩 charset 표를 되살렸는데, 그 표를 쓰던 4개 호출부는 충돌 없이 자동병합돼 우리 Charset 라우팅을 유지했다. ⇒ 통째로 취했으면 표 2함수가 dead code 로 남아 S3 완료조건(「charset.rs 배선으로 dead code 0」)을 깼다. ★충돌면은 «표»에 났는데 의미가 갈린 곳은 «충돌하지 않은 호출부»였다 — 「union 자동병합 경계」의 실례다.
  • ★★**test_timer.rs — 「되얹기」 예측이 반증됐다.** upstream 이 우리 벽시계 테스트 2건을 manual clock + queued spawn + monitor notification 기반 결정성 스위트 12건으로 대체했다 (Thread.sleep 기반 단정 0건). ⇒ S4 의 500→2000ms 여백은 되얹을 자리가 사라졌다. ★★S4 가 남긴 「우리 테스트의 시간 의존」 별 축은 소멸했다 — 그 축으로 발권하지 마라.단 «왜 2000 이었는지»의 근거는 docs/upstream-sync-approach.md §5 착지 기록에 인용으로 보존했다.
  • ★★충돌 «목록에 없던» 파손 1건 — §4 가 경고한 형태가 실제로 났다. upstream 신규 io 테스트 3파일 5곳System.setProperty)Ljava/lang/Object; 로 부르는데 우리는 PR #5 에서 JDK 규격대로 )Ljava/lang/String; 으로 고쳐 뒀다 ⇒ ★충돌 마커 0줄인데 NoSuchMethodError 3건. 서술자만 String 으로 맞췄다. ★새 처분이 아니다test_boolean·test_integer·test_long 이 앞 회차에 이미 같은 처분을 받았고 이번엔 자동병합으로 통과했다. ★java/util/Properties.setPropertyObject 반환은 JDK 규격상 옳아 무접촉.
  • 후속 추천: ⑴게이트③은 반드시 --merge<id>-merge 티켓 frontmatter 에 merge_strategy: merge 필수 (rustjavacontracts/upstream-sync-repos.conf 등재 · 스쿼시가 merge-base 를 되돌린다). ⑵S6(컷 95ebc5c · 11커밋) — §5 예측 새 충돌 0이고 이번 S5 해소로 그 전제가 실제로 섰다. ★그래도 착수 시 재측정하라(upstream 헤드가 계속 전진한다). ⑶★S8 은 여전히 필요하고 제일 크다 — 개명 스윕(java_runtime/rustjava-runtime/)이 우리 픽스처에 꽂힌다.

[2026-09-04] 워크로그 의무화 «결정» + 형식 잠금을 로컬 DoD 안으로 (rustjava-worklog-mandate-decision-and-local-gate)

  • 무엇을: 운영자 채택 제안 2건을 한 회차로 처리했다. ⑴워크로그 작성을 DoD 의무로 «결정» (CLAUDE.md 1줄 + AGENTS.md 포인터) ⑵형식 잠금 python3 scripts/check-worklog-json.py 를 로컬 DoD 4번째 명령으로 편입. ★코드(.rs) 변경 0 · 새 도구 0 · CI 워크플로 무접촉.
  • 왜: ★먼저 쟀다 — 규약 자신이 착지한 b3a4cf4(2026-08-26) 이후 착지한 4회차 중 3건(75%)이 워크로그 쌍을 남겼고, 유일한 미작성(PR #13)은 부모가 정확히 b3a4cf4 라 규약을 알 수 없었던 회차다(알 수 있었던 회차만 세면 3/3). ★★관측이 높은데도 의무화를 고른 이유는 하나다 — 실패가 «조용하고 잠글 수 없다». 잠금은 존재하는 .json 검사하므로(규약 비소급 설계) 아예 안 쓴 회차는 어디서도 red 가 나지 않고 카드만 0 이 된다. 표본은 3건이고 전건 같은 리니지라 소형 회차 관측은 0 이다. ⇒ 대가 DoD 1줄로 무방비한 침묵을 닫았다. ★잠금 위치 실측: .github/workflows/rust.yml:63worklog_json job 단 1곳(ubuntu 1러너) — 6셀 매트릭스에도 로컬 3명령에도 없어 틀린 파일은 PR 을 열어야 빨개졌다.
  • 사용자 영향: 런타임 동작 무변경. 회차가 남긴 후속 추천이 cockpit 「후속 작업 추천」 패널에 빠짐없이 도달하고, 형식 오류를 push 전에 알게 된다.
  • 검증: ★변경 «적용 후» 4명령 전건 rc=0(재컴파일 회차 fmt 1.1s · clippy 11.5s · test --all 47.6s / 완전 캐시 회차 0.56s · 0.39s · 8.41s · 잠금 0.04s). ★3명령은 한 글자도 안 건드렸다 ⇒ 기존 검사의 오탐 위험은 구조적으로 0. ★대가(초) — 분모를 둘 다 적는다: 잠금 5회 0.10·0.04·0.13·0.13·0.08 ⇒ 중앙값 0.10s. 재컴파일 회차(60.2s) 대비 +0.17% · ★완전 캐시 회차(9.36s) 대비 +1.1%최악 약 1%.
  • ★**cargo test «안»으로 넣지 않았다 — 두 경로 다 기각**: serde_json 은 ★**Cargo.lock 에 없어** 새 의존성 + 6셀 빌드 비용이고(★스크립트 docstring 이 이미 같은 이유로 기각한 길) · python3 shell-out 은 python 없는 머신에서 cargo testred 로 만들어 「오탐 0」 절대 조건을 깬다.
  • ★★되돌릴 «수» — AGENTS.md §Round Worklog 에 측정 명령과 함께 박았다(취향으로 재론하지 말고 다시 재라): 2026-09-04 이후 10회차 착지 시점에 ⒜미작성 회차 ≥ 2(>20%) ⇒ 문안을 빼거나 기계 강제로 올려라 (★문서에만 둔 채 유지하지 마라 — 규칙은 있고 효력은 없는 상태가 가장 나쁘다) · ⒝열린 카드 < 5의무 자체를 재검토.
  • 후속 추천: 워크로그 미작성을 «기계»로 잡을지 판정하라 — 지금 의무는 문서에만 있다 (잠금은 「있으면 검사」라 「없으면 침묵」이다). 판단 재료 = 워크로그 2026-09-04-…jsonproposals[0].
  • 고지: 열린 PR #19REPORT.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/main3296139c 로 전진한 «뒤» 기준으로 S5~S7 을 다시 쟀고, ★세 base 를 «병기» 했다(계획 기준 03438b0 · 복원 전 3a59776 · 복원 후 8c1238b). 같은 컷 ba5797b 가 base 에 따라 ★19 · 112 · 4(28배 차)로 갈린다. ⇒ 그래서 「충돌 수를 적을 때 base 를 반드시 병기한다」를 docs/upstream-sync-approach.md §5 의 상시 규칙으로 채택했다(문안 신설). ★직전 반려의 근인이 정확히 이 병기 누락이고, S2·S4 회신은 각자는 정확했는데 «한 표»로 모으는 순간 기준이 섞였다 — 개별 회신의 정확성으로는 막히지 않는다.
  • 왜: §5 표의 S5S7 「0·0·+3」은 계보가 전진한다는 전제 위의 수인데 그 전제가 S1S4 내내 깨져 있었다. 이제 처음으로 참이 됐으므로 그 위에서 다시 재야 티켓 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 <merge-base> <ours>(2026-09-04 정정 — 초판 +28/−8·+1/−8 은 역순 출력이라 폐기). ★S7 은 diff 32만 줄대인데 새 충돌 1건(thread.rs) ⇒ 「물량이 크면 충돌도 크다」는 성립하지 않는다.
  • 사용자 영향: ★코드 변경 0 · 문서 전용(런타임 동작 무변경). 얻는 것은 남은 회차의 크기를 실제 수로 잡는 것과, 다음 회차가 같은 «기준 혼합» 반려를 반복하지 않는 것이다.
  • 검증: git merge-tree --write-tree --name-only <base> <cut> 의 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/main12커밋(★증분 — 누적 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**(★.javasrc/ 아래 — 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 이 줄지 않던 근인을 확정했다. 근인은 게이트③ 제품 repo --squash 다 — 네 머지커밋의 부모가 전건 1개이고(커밋 7·10·15·21이 각각 1로 접힘), 반면 브랜치 34a4235 는 부모 2개(c80638a+3296139)인 진짜 머지였다. ⇒ ★계보는 브랜치에 있었고 게이트③이 버렸다 — cherry-pick·브랜치 재작성 가설은 실측으로 기각. 처방(갈래 ⒞의 ⒜)으로 origin/main 위에 git merge -s ours 3296139 를 얹었다. 1f356ae·af4f6f8· 822504b 는 전부 3296139 의 조상이라 한 머지가 네 컷을 덮는다.
  • 왜: 내용은 이미 들어와 있는데 계보가 없어서 git 이 영원히 「33 뒤」라고 답했고, 그 결과 다음 회차가 앞 회차가 이미 닫은 충돌을 처음부터 다시 열었다.근거는 «충돌 총수»가 아니라 «재생분»이다 — 총수는 회차마다 기준(복원 전/후)이 달라 비교가 안 된다: ★S2 15 중 10 재생 → S4 20 중 18 재생(둘 다 계보가 끊긴 회차) · ★S3 는 계보가 온전해 재생 0. 기준을 단 회차별 표: S1 2(복원 불요) · S2 15 → 5 · S3 11(★계보 온전 · 복원 불요) · S4 20 → 2. ★★S3 는 이 병의 «반례»다merge-baseaf4f6f8 로 정상이었고 복원을 하지 않았다. 계획서 §5 는 S4 를 「새 충돌 0」으로 예측했는데 실측은 복원 전 20 · 복원 후 2어느 쪽으로 읽어도 빗나갔다. 그 표의 수는 base 가 전진한다는 전제 위의 수였고 그 전제가 깨져 있었다.
  • 사용자 영향: 제품 코드 변경 0 — 트리 오브젝트 SHA 가 origin/main동일(c4f57d10…)하므로 런타임 동작은 1바이트도 바뀌지 않는다. 얻는 것은 다음 동기 회차의 비용이다: merge-base62cf0c6a3296139c · behind 33 → 18 · S1~S4 컷 조상 0/4 → 4/4.
  • 검증: 트리 변경 0 근거 = 트리 SHA 동일(git diff 3a59776..c118d210줄). ★git diff --stat 빈 출력은 -s ours 에서 정의상 항상 참이라 근거로 쓰지 않았다(S4 워크로그 교훈). .rs 변경 0 이므로 cargo 4종은 트리 불변으로 담보된다. scripts/check-worklog-json.py rc=0.
  • 후속 추천 (1) — 총괄 몫. 이 세션은 손대지 않았다: 게이트③ 제품 repo --squash 규율에 «upstream 동기 PR 예외»를 넣을지 총괄이 판정하라 (~/orchestrator/ORCHESTRATOR.md 2곳 · ~/orchestrator/templates/merge-ticket.tpl 스니펫 1곳 — ★orchestrator 소관이라 RustJava 세션이 고치지 않는다). ★★이 PR 자체가 --squash 로 착지하면 위 처방이 그대로 무효가 된다 — 부모 2개가 1개로 접히며 3296139 조상 관계가 사라지고 merge-base62cf0c6a 로 되돌아간다. 반드시 gh pr merge --merge. ★회차마다 브랜치에 -s ours 를 다시 넣는 현행 방식은 러닝머신이다 — S4 의 c80638a 가 정확히 그 처방이었는데 PR #17 의 스쿼시에 함께 사라졌고, 이 리니지에서 네 번 반복됐다. ★★**wie 도 같은 함정 위에 있다 — behind 1067.** 예외 판정은 RustJava 단독 문제가 아니다.
  • 후속 추천 (2): S5~S7 의 「새 충돌」을 이 PR 이 --merge 로 착지한 «뒤» 재측정하라 — merge-base3296139 인 상태에서 잰 수라야 다음 회차의 실제 기준선이다(워크로그 #p1).

[2026-08-27] upstream 동기 S4 — 컷 3296139 머지 (rustjava-upstream-sync-s4)

  • 무엇을: upstream 3296139(#184 CLI classpath) 까지 8커밋을 머지했다(GlobalRef · CDC text API · monitor 인자 일반화 · classfile 오류 은닉 · tokio 1.53). 충돌 2 해소 — jvm/src/jvm.rs합집합(upstream load_bootstrap_class + 우리 double_must_use allow), java/lang/thread.rsupstream 의 GlobalRef 본문 + PR #4 의 수동 span이다. ★첫 조치는 git merge -s ours --no-ff 822504b — 그것이 충돌 20 → 2를 만들었다. ★무해성의 근거는 «git diff --stat origin/main HEAD 빈 출력»이 «아니다»-s ours 는 정의상 우리 트리를 유지하므로 그 출력은 항상 참이라 아무것도 증명하지 않는다. 근거는 ★**--diff-filter=D 0**(upstream 이 들여온 것 중 잃은 파일 0)와 충돌 2파일의 양방향 전문 대조다.
  • 왜: 스쿼시 착지 3회(#11·#13·#16)로 origin/main 의 upstream 조상이 ★최초 공통조상 62cf0c6 까지 되돌아가 있었다(1f356ae·af4f6f8·822504b 전건 조상 아님). 그대로 재면 git 이 앞 회차가 이미 해소한 자리를 통째로 재생해 20충돌을 낸다. 트리는 이미 동일하므로 부모만 기록해 base 를 복원했다. ★S2 회차가 세운 방법을 그대로 썼고, 이제 이 리니지에서 네 번째 적용이다.
  • 사용자 영향: JNI 스타일 전역 참조(GlobalRef)가 들어와 스폰된 스레드가 자기 this 를 GC 로부터 안전하게 붙든다. CLI 에 classpath 옵션이 생기고(-cp/-classpath), java.text 포맷팅 API (DateFormat·DecimalFormat·SimpleDateFormat·NumberFormat)가 추가된다. ★기존 동작 변경 0 — 우리 자산(charset 4종 · System.setProperty 서술자 · ClassFormatError 4종 분류 · 수동 span)은 전건 생존했다.
  • 검증: cargo fmt --all -- --check · cargo clippy --all -- -D warnings · cargo clippy --workspace --exclude test_utils --target wasm32-unknown-unknown -- -D warnings · cargo test --all4/4 rc=0 · 261 passed / 0 failed / 1 ignored(S3 216 → +45). 「해소분 0」 증명 = ★upstream 3296139 대비 삭제된 파일 0 · 다른 파일 39건 전수가 우리 fork 고유 자산 (원장·CI·worklog·charset·오류분류·tracing·픽스처·타이머 여백). 충돌 2파일은 양방향 원본 전문 대조로 소실을 전건 확인했고 의도 밖 0이다.
  • 타이머 테스트 여백 1건 — «회귀»가 아니다(★전 판본의 「들여온 upstream 회귀」 서술은 틀렸다): test_timer_periodic 은 ★컷 이전부터 500ms 창에서 기대 10회 대비 3~4회만 도는 만성 경계 테스트이고, 머신 부하가 걸리면 ★컷 양쪽이 «같은 비율로» 단정 아래로 떨어진다. ★측정 조건을 맞춰 교대 실행한 실측(★조건을 섞지 않는다): ⒜단독 실행 · 교대 10회4bb796d(컷 전) 3 3 3 3 4 4 4 4 3 4(mean 3.5) ↔ 3296139(컷 후) 4 3 4 3 4 3 4 3 4 3(mean 3.5) ⇒ ★차이 없음전 스위트 병렬 · 교대 8회 — 컷 전 4 4 4 4 3 4 3 4 ↔ 컷 후 4 3 3 6 4 4 4 4 ⇒ ★차이 없음사료가 그 자체로 반증이다: upstream 이 같은 자리를 넓힌 895d67d(2025-08-20ad8b477(2025-10-04)는 ★둘 다 이미 origin/main 의 조상이고, 근인으로 지목했던 e557673(GlobalRef)은 2026-07-18 이다 ⇒ ★이 테스트는 지목된 커밋보다 «11개월 앞서» 이미 만성 flaky 였다.전 판본이 틀린 이유는 «수»가 아니라 «조건»이다origin/main10/10(단독)과 순정 upstream 3/8 실패(병렬)를 나란히 놓았다. ★서로 다른 측정 조건의 수를 비교했다.처분은 그대로다(sleep 500 → 2000ms · run_count > 2불변 · #[ignore] 0 · 삭제 0) — 단 성격이 「가리는 여백」이 아니라 ★만성 경계 테스트에 정상 여백을 준 것이다. ★대가: 창을 넓히면 감도가 내려간다 — red 문턱이 1회전 ~167ms → ~667ms(약 4배 둔화)로, 돌연변이 「루프 sleep 16ms → 700ms(5.6배 저하)」는 여전히 red 지만 「→ 300ms(2.4배)」는 이제 통과한다. 그 상한을 주석에 박았다.
  • 후속 추천: ⑴게이트②CLAUDE.md DoD 상 ★머지는 검수자가 approve 와 «같은 턴»에 집행한다 (<id>-merge예외 경로다). ⑵S5(컷 c4665b0 · 171파일 +33,138) — ★착수 첫 조치는 git merge -s ours --no-ff 3296139(S4 도 스쿼시로 착지하면 족보가 또 끊긴다). ⑶★**thread.rs 는 S1·S3·S4 «세 회차 연속» 충돌한다** — S5~S7 도 기본값으로 잡아라. 전략은 불변 (upstream 본문 + 수동 span 1줄 치환). ⑷★**「타이머 성능 회귀」는 «없다» — 그 축으로 발권하지 마라** (위 문단 참조: 컷 전후가 조건 맞춘 실측에서 동일하고, upstream 이 이미 두 번 넓힌 자리다). ★남는 별 축은 «우리 테스트의 시간 의존»이다test_timer_periodic 이 벽시계에 의존하고 이번이 세 번째 여백 확장이며 red 문턱이 약 4배 둔해졌다. ★주인은 우리이고 upstream 발신은 «불요»다. 판단 재료 = worklog 2026-08-27-upstream-sync-s4.jsonproposals[0].

[2026-08-27] upstream 동기 S3 — 컷 822504b 머지 (rustjava-upstream-sync-s3)

  • 무엇을: upstream 822504b(#180 Harden JVM runtime correctness) 1커밋을 머지했다. 충돌 11 해소. classfile/{class,constant_pool,error,lib}.rs · jvm_rust/class_definition.rs · src/runtime.rs · test_utils/lib.rsupstream 채택(우리 ParseError 5변형 → upstream ClassFileError + ClassDefinitionError). java/lang/string.rsupstream 골격을 우리 charset::Charset 으로 라우팅해 중복 charset 표를 지웠고, test_string.rs양쪽 테스트 합집합, thread.rsupstream 본문 + PR #4 의 수동 span, AGENTS.md양쪽 절 합집합이다. 부수: tests/test_class_format.rs문구 단정 3건 삭제(종류 단정은 유지).
  • 왜: 계획서 §3-B 가 판정한 대로 Java 관측면에서 upstream 이 이긴다 — 우리 ParseError 는 Rust 변형이 5종이지만 Java 예외는 ClassFormatError1종뿐이고, upstream 은 ClassFormatError · UnsupportedClassVersionError · VerifyError · UnsupportedOperationException4종으로 나눈다. JVM 구현체에서 값이 큰 쪽은 관측면이다. PR #3 의 목적(「패닉 대신 ClassFormatError」)은 upstream 에서도 그대로 성립한다(미지원 상수풀 태그 → ErrorKind::SwitchInvalidFormat, 패닉 0). ★치른 값은 진단 문구다 — 「Truncated」·「tag 18」·「magic」이 전부 "Invalid class file" 로 평탄해졌고, §4-A 가 예고한 대로 tests/test_class_format.rs 3건이 충돌 마커 없이 그것 때문에 깨졌다.
  • 사용자 영향: 클래스파일 검증이 세분화된다 — 지원하지 않는 클래스파일 버전은 이제 UnsupportedClassVersionError, 바이트코드 검증 실패는 VerifyError, invokedynamicUnsupportedOperationException 으로 깔끔히 거부된다(구판은 인터프리터 todo!() 패닉까지 갔다). 대신 ClassFormatError 메시지는 원인별 문구를 잃고 "Invalid class file" 평문이 된다. ★charset 동작 변경 1건: 기본 charset 경로(new String(byte[])·getBytes())는 미지원 이름에도 더 이상 UnsupportedEncodingException 을 던지지 않고 UTF-8 로 폴백한다 — JDK 규격이 그렇다. 명시 charset 경로(new String(byte[],String)·getBytes(String))는 그대로 던진다. ISO-8859-1·US-ASCII 는 우리 Charset 이 정본으로 남아 계속 동작한다(종단 픽스처 green).
  • 검증: cargo fmt --all -- --check · cargo clippy --all -- -D warnings · cargo clippy --workspace --exclude test_utils --target wasm32-unknown-unknown -- -D warnings · cargo test --all4/4 rc=0 · 216 passed / 0 failed / 1 ignored(S2 191 → +25, 우리 테스트 유실 0). tests/test_class_format.rs4/4 · git grep 'tracing::instrument\|tracing-attributes'0건(§4-C 불변). 추가로 「base af4f6f8 이후 우리가 추가한 .rs 321줄이 머지 트리에 살아 있는가」를 기계로 전수 대조했고, 부재 81줄은 전건 의도한 해소였다(ParseError 기구 · thread.rs 구본문 · 완화한 문구 단정 3줄).
  • 후속 추천: ⑴게이트③ 순서 주의rustjava-upstream-sync-s2-merge(#13)가 먼저고 S3 PR 이 그 위다. ★#13 이 스쿼시로 착지하면 af4f6f8 조상이 다시 끊기므로, S3 PR 이 main 으로 리타깃된 뒤 S2 가 한 -s ours 를 다시 해야 할 수 있다(착지 후 merge-base 를 재라). ⑵S4(컷 3296139) — 계획서 예측 새 충돌 0. 검수는 「우리 해소분 0 증명 + green」. ⑶★계획서의 「새 충돌」 예측은 하한이다 — S3 는 +9 예측에 AGENTS.md·thread.rs2건이 더 붙었다. 전자는 계획서 이후 우리가 만든 파일이고, 후자는 앞 회차가 이미 닫은 파일의 재충돌이다. ⑷charset.rs dead-code red 축은 닫아도 된다 — S3 에서 오히려 upstream 중복 표를 흡수했다.

[2026-08-26] 회차 워크로그 .json + proposals 규약 이식 (rustjava-worklog-json-proposals-convention)

  • 무엇을: AGENTS.md 에 「Round Worklog docs/worklog/」 절(소비처가 읽는 키 표 · 소급 없음), scripts/check-worklog-json.py 잠금 6축, rust.ymlworklog_json job 1개(ubuntu 단일 러너), docs/worklog/ 개시 + 이 회차 .md/.json 한 쌍. Rust 코드 변경 0.
  • 왜: cockpit 「후속 작업 추천」 커버리지 6 repo 중 채워진 것이 2개뿐이고 RustJava 는 docs/worklog디렉터리 자체가 없어(2026-08-26 재실측 archiveErr: pathspec … did not match) 구조적으로 0건이었다. qts 회차가 만든 규약을 복제했다 — 새 스키마·새 기구 0.
  • 사용자 영향: 착지 후 RustJava 의 후속 제안이 cockpit 화면에 처음 뜬다(이 회차 2건). 회차마다 워크로그 2파일 작성 부담이 는다.
  • 후속 추천: ★규약을 심었다 ≠ 카드가 계속 는다. 이 repo 회차 기록 정본은 REPORT.md 라 워크로그 작성이 DoD 에 없다 — 의무화 여부는 미결(짝 .jsonproposals[0]). 잠금이 cargo test 밖 CI job 이라 로컬 DoD 3명령으로는 안 돈다(proposals[1]).

[2026-08-25] beta clippy double_must_use red 해소 (rustjava-ci-beta-clippy-double-must-use-red)

  • 무엇을: Cargo.lockasync-trait 0.1.89→0.1.92, #[async_recursion]7지점에 국소 #[allow(clippy::double_must_use)], rust.yml matrix 에 fail-fast: false 1줄. 기능 변경 0.
  • 왜: rustup run beta cargo clippy --all -- -D warningsorigin/main(코드 무변경)과 열린 PR 양쪽에서 동일하게 13건 red 였다 ⇒ ★코드가 아니라 부동 beta 채널이 움직였다(1.99.0-beta.1, 2026-08-17). 13건 전부note: this error originates in the attribute macro … — 우리 소스에 #[must_use] 를 쓴 지점은 0건이고 async_trait 7 + async_recursion 6 의 매크로 확장이 찍은 것이다. 0.1.92 의 async-trait 은 그 push(#[must_use]) 를 삭제해 7건이 사라지고, async-recursion1.1.1 이 최신이라 올릴 곳이 없어 그 7지점(6+jvm_rust 1)만 국소 억제했다 — crate/워크스페이스 전역 억제는 쓰지 않았다.
  • 사용자 영향: 없음(런타임 동작 무변경). main 과 열린 PR 전건을 막던 게이트③ 병목이 풀린다.
  • 후속 추천: ★열린 PR 은 자동으로 green 이 되지 않는다 — 이 PR 착지 후 각 PR 의 CI 재실행이 필요하다 (PR #13 upstream-sync-s2 는 이미 게이트② approve 상태라 재실행만 남는다).

[2026-08-24] upstream 동기 S2 — 컷 af4f6f8 머지 (rustjava-upstream-sync-s2)

  • 무엇을: upstream af4f6f8(#177 CLDC 1.1 core API) 1커밋을 머지했다. 63파일 +3,217/−383. 충돌 5 해소 — io.rs·unsupported_encoding_exception.rs·loader.rs 는 upstream 이 상위집합이라 그쪽을 취했고, input_stream_reader.rs우리 Charset(UTF-8·EUC-KR·ISO-8859-1·US-ASCII 4종)을 정본으로 유지한 채 upstream 의 멀티바이트 경계 처리(decode_length·end_of_input)만 얹었으며, test_input_stream_reader.rs양쪽 테스트 합집합(우리 3 + upstream 4 = 7건 전부 통과)이다. 부수 2건: ⑴Throwable::getMessage조용한 중복 제거 ⑵loader.rs 에서 --theirs 가 지운 ClassFormatError::as_proto() 등록 1줄 복원.
  • 왜: ★PR #11(S1)이 스쿼시로 착지해 upstream 조상이 끊겨 있었다.origin/main 의 코드 트리는 S1 머지 결과와 바이트 동일(git diff 0bd4f80 origin/main -- '*.rs' '*.toml' '*.lock' 빈 출력)인데 git 의 merge-base 는 여전히 62cf0c6 라, merge-tree1f356ae 의 6커밋을 통째로 재생하며 충돌 15건을 냈다 — S1 이 이미 해소한 자리들이었다. git merge -s ours 1f356ae(트리 무변경)로 부모만 기록해 base 를 복원하니 충돌 5건, 즉 S1 이 예고한 파일 5개와 정확히 일치했다.
  • 사용자 영향: CLDC 1.1 코어 API 가 들어온다(InputStreamReader.ready()·2인자 생성자, OutputStreamWriter, PrintStream 확장, CLDC 예외 계층, java.util.Date/Random/Calendar 보강). ★기존 charset 동작은 그대로다 — ISO-8859-1/US-ASCII 는 upstream 인라인 판본에 없지만 우리 것이 살아남아 계속 동작하고, PR #5 의 종단 픽스처(test_data/UnsupportedCharset, ISO-8859-1 aéb)도 green 이다. ★단 2인자 생성자 (InputStream, String) 는 미지원 charset 을 «생성 시점»에 던진다(upstream 신규 · JDK 규격). 1인자 생성자는 JDK 가 UnsupportedEncodingException 을 선언하지 않으므로 기존대로 read() 시점에 던진다 — 그래서 픽스처를 재컴파일하지 않고도 양쪽 테스트가 다 산다(이 맥에 JDK 부재).
  • 검증: cargo fmt --all -- --check · cargo clippy --all -- -D warnings · cargo clippy --workspace --exclude test_utils --target wasm32-unknown-unknown -- -D warnings · cargo test --all4/4 rc=0 · 191 passed / 0 failed / 1 ignored(S1 169 → +22, 우리 테스트 유실 0). 추가로 「base 1f356ae 이후 우리가 추가한 260줄이 머지 트리에 살아 있는가」를 기계로 전수 대조했고, 부재 2건은 의도한 해소임을 확인했다(디코드 호출 1줄 = upstream 인자 채택 · io.rspub use 1줄 = rustfmt 재배치).
  • 후속 추천: ⑴게이트③ rustjava-upstream-sync-s2-merge. ⑵S3(컷 822504b · 오류 분류 축) — ★착수 전 git merge-base origin/main upstream/main 을 확인하고 af4f6f8 가 아니면 -s ours 로 조상을 먼저 복원하라(스쿼시 머지가 매 회차 이 문제를 재생산한다). S1 이 예고한 classfile/src/error.rs 재작성 ↔ 우리 ParseError 5변형 충돌이 거기서 터진다. ⑶charset.rs dead-code red 예측은 S2 에서 발동하지 않았고 앞으로도 발동 가능성이 낮다 — 호출자가 5 → 7건으로 늘었다. S3 의 string.rs 접촉 시 한 번 더 확인하면 이 축은 닫아도 된다.

[2026-08-17] coverage 상시 red 해소 (rustjava-coverage-workflow-codecov-token-red)

  • 무엇을: .github/workflows/coverage.ymlfail_ci_if_errortruefalse 로 내리고 이유·복구법을 주석으로 박았다. 변경 파일 1개(워크플로) + 문서 2개.
  • 왜: coverage보고를 시작한 이래 24/24 전건 red 였다(2026-07-22~08-17). 근인은 단 하나 — ★이 저장소는 fork 라 upstream 의 시크릿을 상속하지 않는다.gh secret list빈 목록이고 secrets.CODECOV_TOKEN 이 빈 문자열로 전개돼 업로더가 Token length: 0{"message":"Token required - not valid tokenless upload"} 로 죽었다. fail_ci_if_error: true 가 그 업로드 실패를 job 실패로 승격시켜 왔다. ★상수 red 는 신호가 아니다 — 진짜 회귀가 섞여도 안 보이고, 실제로 upstream 동기 매 회차가 「선재 인프라라 머지 차단 아님」이라는 특례 문구를 손으로 달아야 했다.
  • 사용자 영향: 없음(코드 무변경). CI 신호만 회복된다. ★빌드 검사는 약해지지 않는다Generate code coverage 는 별도 run: 스텝이고 continue-on-error 가 없어 빌드/테스트가 깨지면 여전히 job 이 red 다. 비치명이 된 것은 codecov.io 로의 «발행»뿐이고 그 오류 문구는 스텝 로그에 그대로 남는다.
  • 후속 추천: CODECOV_TOKEN 을 이 fork 에 등재하면 업로드까지 복구된다 — ★human-step(시크릿 발급·등재는 사람 몫). 등재 전까지는 codecov.io 에 데이터가 쌓이지 않는다(단, 토큰이 없던 지금까지도 쌓인 적이 없다).

[2026-08-17] upstream 동기 S1 — 컷 1f356ae 머지 (rustjava-upstream-sync-s1-tracing-cut-1f356ae)

  • 무엇을: upstream 1f356ae(#173~#179 · 5커밋)를 머지했다. 충돌 2 해소 — lang.rs양쪽 병합(우리 class_format_error + upstream 의 Java 1.2 wrapper 9종), thread.rsupstream 뼈대 + PR #4 수동 span 재적용(#[tracing::instrument] 한 줄만 치환, Cargo.toml 2개 무접촉). 66파일 +5,235 / −151.
  • 왜: 접근안 §6 이 정한 7회차 중 첫 회차이고 축은 tracing 이다. upstream thread.rs 를 그대로 취하면 attributes 피처가 꺼진 tracing 에 속성 매크로가 걸려 컴파일이 깨지고, 피처를 되살리면 PR #4 가 통째로 되돌아간다. 뼈대만 취하고 span 만 수동으로 되돌려 둘 다 피했다. ★충돌 목록 밖에서 하나가 더 깨졌다: 우리 PR #5 가 JDK 규격에 맞게 고친 System.setProperty 서술자(…)Ljava/lang/String; — 실제 javac 바이트코드가 그렇다)와 upstream 의 구판(…)Ljava/lang/Object;)이 어긋나, upstream 이 새로 들여온 wrapper 테스트 3건이 NoSuchMethodError 로 죽었다. 우리 서술자를 유지하고 upstream 테스트 호출부 6곳을 고쳤다.
  • 사용자 영향: 없음(동작 변경 0). Java 1.2 wrapper 클래스 9종 (Boolean/Byte/Character/Double/Float/Long/Number/Short · ClassNotFoundException)과 Thread.currentThread() 동일객체 반환이 들어왔다. cargo test --all169 passed / 0 failed / 1 ignored (기준선 149 → +20, 전부 upstream 신규 + 우리 기존분).
  • 후속 추천: S2(컷 af4f6f8 · charset 축 · 새 충돌 +5). ★착수 시 충돌 재측정 필수 · ★우리 프로덕션 서술자/시그니처 변경이 upstream 신규 테스트와 어긋나는지를 S1 과 같은 방식으로 훑어라.

[2026-08-16] upstream 동기화 접근안 확정 (rustjava-upstream-sync-approach-plan)

  • 무엇을: 격차를 오늘 값으로 다시 재고(10 앞섬 / 33 뒤처짐 · 충돌 17 → 19파일), 충돌 19파일을 처분 어휘 4종으로 분류한 표와 단계 분할안을 docs/upstream-sync-approach.md 로 확정했다. 머지 실행 0 · 충돌 해소 0 · 코드 변경 0(문서만).
  • 왜: 충돌의 성격이 「어느 쪽 구현을 남기는가」라 머지 도중 즉흥 결정이 불가능했다. 실제로 실측해 보니 선행 전제 2건이 틀렸다 — ⑴add/add 두 파일은 의미 차이 0이라 «정면 충돌»이 아니고 진짜 설계 결정은 classfile/src/error.rs 하나뿐이며 ⑵charset 퇴행 범위는 string.rs 가 아니라 input_stream_reader.rs 하나다(upstream 이 동일 charset 집합을 독립 구현했고 기본 경로에선 더 옳다).
  • 사용자 영향: 아직 없다(문서 전용). 다만 ★충돌 목록에 없는 파일 3곳이 조용히 깨진다는 것을 머지 전에 잡았다 — tests/test_class_format.rs 3건 실패 · thread.rs×Cargo.toml tracing 함정 (그대로 취하면 컴파일 파괴, 되살리면 PR #4 되돌림) · charset.rs dead code 로 clippy red.
  • 후속 추천: rustjava-upstream-sync-s1(컷 1f356ae · 새 충돌 2 · tracing 축) 발권. ★구판 -32-commits 단일 티켓은 폐기 — 컷별 실측상 19충돌 중 16이 앞쪽 7커밋에 몰려 있어 커밋 수 분할은 무의미하다. S1S3(설계) → S4S7(물량) 순서로 7회차.

[2026-08-15] upstream 격차 재실측 + 잔존분 재판정 (rustjava-lane-restart-upstream-sync-precondition)

  • 무엇을: origin/mainupstream/main 격차를 오늘 값으로 다시 재고(9 앞섬 / 32 뒤처짐 — 구판 「20 뒤처짐」은 낡았다), 선행조건이던 upstream agent/runtime-api-gaps 의 상태를 확정하고, wie-ktf-hardening 유효 잔존을 4건 → 2건으로 재판정해 STATE.md ## 다음 을 전면 갱신했다. 코드 변경 0(문서만).
  • 왜: 이 레인이 25시간 무배차로 멈춰 있었고 근인이 낡은 ## 다음 이었다. 특히 선행조건으로 걸려 있던 agent/runtime-api-gaps 는 「미머지」가 아니라 PR #190 으로 2026-07-25 04:59Z 스쿼시 머지(c4665b0)돼 브랜치까지 삭제된 상태였다 — 즉 잔존분 판정 기준이 통째로 바뀌어 있었는데 아무도 다시 재지 않았다. 재판정 결과 Timer·StringBuffer 2건·BAIS·Class.forName· Integer.byteValue/shortValue 는 upstream 이 삼켰고, System.arraycopyString.<init>([B)/([C) 의 null 가드 2건만 유효하게 남았다.
  • 사용자 영향: 런타임 동작 변화 없음. 다음 회차 작업이 무효 6건을 중복 구현하는 낭비가 사라졌다.
  • 후속 추천: ①rustjava-upstream-sync-32-commits(P1·L) — 충돌 예상 17파일 실측 완료. ★머지 시 upstream 의 input_stream_reader.rs(UTF-8/EUC-KR 하드코딩)를 그대로 취하면 우리 PR #5 의 charset 일반화가 퇴행하니 test_data/UnsupportedCharset 로 잠그고 진행할 것. ②그 뒤 null 가드 2건(형제 String.<init>([BII) 포함) — 원인은 ClassInstanceRef::derefunwrap() 이라 전역 수리가 불가하고 진입부 가드가 정답이다. ③invokedynamic todo!() + 상수풀 태그 15~18 미지원은 ★아직 미해결이다(양쪽 브랜치에서 실측 확인). 「이미 처리됐다」는 통설을 STATE 에서 정정했다.
  • [2026-08-16 게이트② 반려 반영] 같은 PR 위에 문서 4곳을 고쳤다(코드 여전히 0). ⒜★**「열린 PR 0」이 거짓이었다** — 실측 2건(#9 · ★**#8 [rustjava-claude-md-prune] 이 11일째 좌초 · .review.md 부재**). ⑤를 실측 표로 교체하고 #8 처분 브리프를 목록 맨 위에 넣었다. ⒝★invokedynamic 은 upstream jvm_rust/src/verifier.rsUnsupportedFeature거부한다 ⇒ ①머지로 패닉 축이 소멸하므로 「한 티켓으로 묶는 이유」를 다시 썼다. ⒞null 가드 형제 열거를 전수 7건으로 확대(([BLjava/lang/String;)·([BIILjava/lang/String;)·(Ljava/lang/String;)· (Ljava/lang/StringBuffer;) 추가). ⒟★system.rs 는 충돌 목록에 없다 — 선행 근거를 string.rs 하나로 정정.

[2026-07-25] 원격 잔존 브랜치 위생 판정 (2026-07-25-rustjava-branch-hygiene)

  • 무엇을: 포크(Jun025/RustJava)에 남아 있던 원격 브랜치 2건을 실측 대조로 판정했다. dependabot/cargo/tracing-attributes-0.1.31 은 삭제하고, wie-ktf-hardening 은 혼재 판정으로 보존 + 커밋별 판정표를 제출했다. 코드 변경은 없다.
  • 왜: dependabot 브랜치는 PR #4(fa92ef9)가 tracing-attributes 직접 의존을 통째로 제거해 패치 대상 라인 자체가 사라졌다 — 머지해도 적용되지 않는 죽은 패치다. wie-ktf-hardeninggit cherry 가 12커밋 전부를 미반영(+)으로 표시했지만, 실제로는 내용이 upstream 에 스쿼시 머지(#174·#175·#176·#177·#180·#182)돼 있었고 우리 origin/main 이 upstream 보다 20커밋 뒤처져 있어 생긴 착시였다. 12건 중 8건 반영/대체, 4건만 유효 잔존.
  • 사용자 영향: 원격 브랜치 목록이 main + 판정 보류 1건으로 정리됐다. 런타임 동작 변화 없음.
  • 후속 추천: ① origin/mainupstream/main 20커밋 동기화가 선행돼야 한다(그래야 잔존분이 4건으로 확정되고, upstream 이 GlobalRef(#182)로 다르게 푼 스레드 루팅과의 이중 적용을 피한다). ② 이후 잔존 4건(Timer 1회성 schedule, StringBuffer.insert, append([CII) null→NPE, arraycopy·String.([B)([C)·BAIS.([B) null 가드 + Integer.byteValue/shortValue)만 추려 PR 1건 — 전부 호스트 프로세스를 죽이는 실제 패닉이라 upstream 상납 가치도 있다. ③ 착수 전 upstream agent/runtime-api-gaps(미머지, +33k lines) 중복 여부 확인.

[2026-07-22] 미지원 charset 패닉 → UnsupportedEncodingException (rustjava-unsupported-charset-exception)

  • 무엇을: String.getBytes(charset)/new String(byte[], charset)/InputStreamReader.read()unimplemented!() 패닉을 java.io.UnsupportedEncodingException(신설, IOException 하위) throw 로 전환하고, String↔Reader 의 지원 charset 목록을 공용 charset::Charset 으로 일원화했다.
  • 왜: charset 이름은 자바 코드가 넘기는 완전한 사용자 입력인데 미지원 이름 한 줄에 호스트 프로세스가 죽었다. Reader 쪽은 ISO-8859-1 조차 못 받는 String 쪽과의 불일치도 있었다.
  • 사용자 영향: "hi".getBytes("UTF-16") 류가 이제 try/catch 로 잡히는 자바 예외가 되고, file.encoding=ISO-8859-1 후 InputStreamReader 도 정상 동작한다. 부수 교정: System.setProperty 반환 시그니처를 JDK 규격(...)Ljava/lang/String;)으로 수정, Throwable.getMessage() 신설.
  • 후속 추천: ① Charset 공용화를 계기로 UTF-16/Shift_JIS 등 실제 인코딩 추가는 별건 티켓으로. ② InputStreamReader 가 read 마다 스트림 디코더를 새로 만들어 버퍼 경계의 multibyte 부분 시퀀스가 유실될 수 있는 기존 문제(EUC-KR)가 남아 있다 — 별건 조사 권장.

[2026-07-22] tracing-attributes 상한 핀 제거 (rustjava-tracing-attributes-pin-removal)

  • 무엇을: 워크스페이스 유일의 #[tracing::instrument](thread.rs, "java thread" span)를 tracing::info_span! + Instrument 수동 span 으로 대체하고, java_runtimetracing-attributes <0.1.29 직접 의존 핀과 workspace tracingattributes 피처를 제거. Cargo.lock 은 tracing 계열만 국소 갱신(tracing 0.1.41→0.1.44, subscriber 0.3.20→0.3.23, tracing-attributes 그래프에서 소멸). wasm32 clippy CI 의 누락 커버리지도 교정 (--workspace --exclude test_utils — test_utils 는 tokio rt-multi-thread 라 wasm 불가).
  • 왜: 한 줄의 attribute macro 가 no_std 빌드를 깨는 탓(tokio-rs/tracing#3388)에 tracing 계열 전체가 동결됐고 dependabot PR 이 해석 불가로 계속 죽었음.
  • 사용자 영향: tracing 계열 업데이트 재개 가능(보안 패치 포함). span 출력("java thread{id=N}" 이름·필드·레벨·타깃)은 실행 대조로 동일함을 확인 — 관측 회귀 0.
  • 후속 추천: ① dependabot 재시도 유도(다음 주기에 자동), ② javac 21 익명 내부 클래스 파싱 실패(Malformed) 원인 조사 별건, ③ wasm32 에서 test_utils 대체 테스트 전략 검토.

[2026-07-22] 클래스파일 파싱 실패 → ClassFormatError 전파 (rustjava-classfile-parse-error-propagation)

  • 무엇을: ClassInfo::parseOptionResult<_, ParseError> 로 바꿔 실패 원인(절단/매직 불일치/미지원 상수풀 태그 N/기타 손상)을 담고, from_classfileunwrap()/assert_eq! 를 제거해 define_class 에서 기존 예외 관례(jvm.exception)대로 java.lang.ClassFormatError 로 올림. java/lang/ClassFormatError 런타임 클래스(부모 LinkageError) 신설.
  • 왜: 손상되거나 미지원 항목(javac 9+ 가 기본으로 심는 invokedynamic 계열 태그 15~18)을 가진 class 파일을 여는 순간 Rust 패닉으로 프로세스(임베딩 호스트 포함)가 즉사했음. "클래스 못 찾음" 은 예외인데 "못 읽음"만 패닉인 비대칭.
  • 사용자 영향: 잘못된 class 파일이 진단 가능한 자바 예외(원인 메시지 포함)로 보고되고 프로세스는 살아남음. 미지원 태그는 명확히 거절(구현 아님). tests/test_class_format.rs 4케이스(절단/태그 18/매직/못찾음 대조군)가 회귀 잠금.
  • 후속 추천: ① invokedynamic/MethodHandle 실제 지원(별건 대형), ② 상수풀 인덱스 참조 (.get().unwrap() 계열) 손상 대응(별건), ③ UnsupportedClassVersionError 도입 검토(major version 기반).

[2026-07-22] 시간 API 패닉 제거 + 회귀 잠금 (rustjava-runtime-time-todo-impl)

  • 무엇을: src/runtime.rsRuntimeImpl 에서 now()/sleep()/r#yield()todo!() 를 실제 구현(UNIX epoch ms·tokio::time::sleep·tokio::task::yield_now)으로 교체하고, test_utilsTestRuntime::r#yieldtodo!() 도 동형으로 구현. 루트 Cargo.toml tokio 에 time 피처 추가.
  • 왜: 배포 바이너리가 System.currentTimeMillis()·Thread.sleep()·new Date() 등 시간 API 를 부르는 순간 Rust 패닉으로 즉사했으나, 테스트 코퍼스가 해당 API 를 0건 사용해 CI 가 초록이었음.
  • 사용자 영향: 시간 API 를 쓰는 모든 자바 프로그램이 이제 정상 동작. test_data/TimeApi 픽스처(currentTimeMillis/yield/sleep/Date, 결정론적 단언)가 RuntimeImpl 경로 통합 테스트로 상시 회귀 감시.
  • 후속 추천: ① jvm_rust/src/interpreter.rs:629 의 잔여 todo!() 제거(별건), ② Timer/Object.wait 경로도 픽스처 확장, ③ 픽스처 .java 소스 보관 체계(현재 .class+.txt 만 커밋하는 관례).