Skip to content

upstream 동기 계보 복원 — 근인 = 게이트③ --squash (behind 33 → 18, 트리 변경 0) [rustjava-upstream-sync-squash-defeats-convergence] - #18

Merged
Jun025 merged 18 commits into
mainfrom
feat/rustjava-upstream-lineage-record
Aug 27, 2026
Merged

upstream 동기 계보 복원 — 근인 = 게이트③ --squash (behind 33 → 18, 트리 변경 0) [rustjava-upstream-sync-squash-defeats-convergence]#18
Jun025 merged 18 commits into
mainfrom
feat/rustjava-upstream-lineage-record

Conversation

@Jun025

Copy link
Copy Markdown
Owner

★★이 PR 은 반드시 gh pr merge --merge 로 착지해야 한다 — --squash 면 통째로 무효다

부모 2개가 1개로 접히는 순간 3296139 조상 관계가 사라지고 merge-base62cf0c6a 로 되돌아간다.
게이트③ 규율 예외 판정은 총괄 소관이다(REPORT.md 후속 추천 (1)).


증상 — S1~S4 가 «착지했는데도» fork 는 한 걸음도 upstream 에 가까워지지 않았다

값 (2026-08-27 재실측)
git merge-base origin/main upstream/main62cf0c6a (2026-06-28) = ★fork 시점 그대로
S1~S4 컷이 origin/main 조상인가0/4 (upstream/main 조상은 4/4)
git rev-list --count origin/main..upstream/main33
착지 PR#11(7커밋)·#13(10)·#16(15)·#17(21) — 전부 merged=true
회차별 충돌 수S1 2 → S2 5 → S3 11 → S4 20 ★단조증가

내용은 들어와 있다(charset.rs·test_data/UnsupportedCharset.* 실재). 들어오지 않은 것은 계보다.

근인 확정 — 머지커밋 부모 수

PR #11 merged=true pr_commits=7 merge_commit=6bfe97c4 parents=1
PR #13 merged=true pr_commits=10 merge_commit=11ef5010 parents=1
PR #16 merged=true pr_commits=15 merge_commit=4bb796de parents=1
PR #17 merged=true pr_commits=21 merge_commit=3a597768 parents=1

4/4 부모 1개 = squash. 7·10·15·21 커밋이 각각 1커밋으로 접혔다.

가설 반증 시도 → 실패했다(= 가설이 맞다)

「cherry-pick 으로 만든 브랜치라 애초에 계보가 없었던 것 아닌가」를 직접 확인했다:

$ git cat-file -p 34a4235 | grep '^parent'
parent c80638a… # 우리 쪽
parent 3296139… # ★upstream 컷
$ git merge-base --is-ancestor 3296139 feat/rustjava-upstream-sync-s4 && echo YES
YES

⇒ ★브랜치는 부모 2개인 진짜 머지였다. 계보를 버린 것은 게이트③ --squash 다.

★같은 브랜치의 c80638a(「record upstream cut 822504b as merged (tree unchanged)」)는
S4 가 이미 손으로 넣은 -s ours 계보 기록인데 그것도 함께 지워졌다.
브랜치 처방만으로는 회차마다 무효화된다 — 이 리니지에서 네 번 반복됐다.

처분 — 갈래 ⒞ 중 ⒜ 를 집행

origin/main(3a59776) 위에서 git merge -s ours 3296139.
1f356ae·af4f6f8·822504b 는 전부 3296139 의 조상이므로 한 머지가 네 컷을 덮는다.

트리 변경 0 증명 — 트리 오브젝트 SHA 동일:

tree BEFORE (3a59776): c4f57d10bce2087cebe2e1156f716f6ba8f75335
tree AFTER (c118d21): c4f57d10bce2087cebe2e1156f716f6ba8f75335
git diff 3a59776..c118d21 → 0 lines

git diff --stat 빈 출력은 -s ours 에서 정의상 항상 참이라 근거로 쓰지 않았다(S4 워크로그 교훈).

merge-base vs upstream/main62cf0c6a (2026-06-28)3296139c (2026-07-19 dlunch#184)
behind3318
S1~S4 컷 조상0/44/4

⒝(향후 upstream 동기 PR 만 --merge)는 총괄 소관이라 여기서 고치지 않았다.
⒟(기각)는 택하지 않았다 — 「부모 수 4/4=1」과 「브랜치 부모 2개」가 동시에 성립하는 설명은 스쿼시뿐이다.

변경 — 제품 코드 0

REPORT.md
STATE.md
docs/upstream-sync-approach.md # §5 전제 정정
docs/worklog/2026-08-27-upstream-sync-squash-convergence.{md,json}

git diff --name-only origin/main HEAD -- '*.rs'0.
.rs 변경 0 이고 계보 커밋의 트리 SHA 가 origin/main 과 동일하므로 cargo 4종은 트리 불변으로 담보된다.
scripts/check-worklog-json.py rc=0.

§5 정정 요지

표의 「새 충돌」은 base 가 전진한다는 전제 위의 수였다. 예측 대 실측: S1 2↔2 · S2 +5↔5 ·
S3 +9↔11 · S4 0↔20. ⇒ S5~S7 의 「0」도 같은 전제 위의 수이므로 하한으로 읽고,
회차 착수 시 merge-base 를 먼저 재고 전진해 있지 않으면 merge-tree 로 전량 재측정한다.
(S3 워크로그 #p0 제안 채택)

하지 않은 것

머지 0 · upstream(dlunch/RustJava) 발신 0 · force-push 0 · history rewrite 0 · reset --hard 0 ·
~/orchestrator 무접촉. upstream/main 헤드까지 -s ours 하지 않았다 — S5~S7 내용은 실제로
없으므로 그것까지 얹으면 거짓 주장이 되고 남은 물량이 조용히 사라진다.

dependabotBotand others added 18 commits July 13, 2026 19:56
Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.25.0 to 1.25.1.
- [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md)
- [Commits](Lokathor/bytemuck@v1.25.0...v1.25.1)
---
updated-dependencies:
- dependency-name: bytemuck
dependency-version: 1.25.1
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Replace runtime panics with the matching Java exceptions
An unwrap audit found panics reachable from ordinary Java code:
- File.length() returns 0 for a missing file; isDirectory/isFile lose
their guard-then-unwrap shape
- FileImpl (native runtime) maps open/read/write/seek failures to
IOError instead of panicking, so FileInputStream and RandomAccessFile
guards actually produce FileNotFoundException; FileOutputStream gains
the same guard
- File I/O operations (read/write/seek/available/length/setLength)
throw java.io.IOException on failure via a shared helper
- Class.forName resolves the class and throws ClassNotFoundException
(new runtime class) instead of panicking on any not-yet-loaded name
- StringBuffer.append(char)/append(char[]) keep exact UTF-16 units so
unpaired surrogates no longer panic and pairs built char by char
survive; String.valueOf(char) builds through [C for the same reason
- PrintStream.println(char) replaces an unpaired surrogate with '?'
like the JDK charset encoder
- ZipFile validates the archive in its constructor and throws
java.util.zip.ZipException (new runtime class) for a malformed
archive; getInputStream returns null for a missing entry
Expected outputs for the new fixtures are generated by a real JVM.
Remaining unwraps are invariants (interpreter stack discipline, thread
attach), guarded lookups, or documented gaps (lenient calendar
normalization, ClassFormatError plumbing).
* Inline the IOException conversion at each I/O call site
Every attached thread now owns its java/lang/Thread instance: attach
takes the instance for threads started via Thread.start (so
currentThread() inside run() is the started Thread object) and creates
one otherwise (bootstrap, external attachers). currentThread() returns
the stored instance, and the GC roots it per thread.
Also parse unrecognized classfile attributes as an opaque Unknown
variant instead of failing — JVMS 4.7.1 requires silently ignoring
them, and the anonymous-class fixture carries EnclosingMethod and
Signature attributes the parser rejected.
Expected output for the fixture is generated by a real JVM.
* Add Java primitive wrapper classes
* Use Character digit semantics for numeric parsing
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.52.3 to 1.52.4.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](tokio-rs/tokio@tokio-1.52.3...tokio-1.52.4)
---
updated-dependencies:
- dependency-name: tokio
dependency-version: 1.52.4
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Add CLDC 1.1 core API compatibility
* Fix CI lint and improve CLDC coverage
* Fix array assignability and reader progress
* Harden JVM runtime correctness
* Address classfile review findings
* Move class initialization tests to Java fixture
* Separate classfile validation from JVM verification
* Remove ClassFileError re-export
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.52.4 to 1.53.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](tokio-rs/tokio@tokio-1.52.4...tokio-1.53.0)
---
updated-dependencies:
- dependency-name: tokio
dependency-version: 1.53.0
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Add CDC text formatting APIs
* Add integer number format factories
* Fix text format position handling
* Add CLI classpath options
* Simplify URL classpath lookup
* Fix platform classpath handling
* Use File path separator for class loading
* Separate RustJar class loading
… unchanged)
S1~S4 (PR #11/#13/#16/#17) landed their CONTENT via gate3 --squash, which
collapses the PR branch to a single parent and discards the upstream merge
parent. Result: git still answers 'origin/main is 33 behind upstream/main'
and every next round re-opens conflicts the previous round already closed.
This merge records the lineage only. -s ours keeps our tree byte-identical;
3296139 is a descendant of 1f356ae, af4f6f8 and 822504b, so one merge covers
all four landed cuts.
MUST be landed with 'gh pr merge --merge'. Under --squash this commit is a
no-op and the problem recurs.
…squash root cause, correct approach doc §5 premise
Gate3 --squash collapses each sync PR to a single parent, so origin/main
never records the upstream cuts as ancestors. Proven by parent counts:
6bfe97c/11ef5010/4bb796de/3a597768 all have 1 parent, while the S4 branch
commit 34a4235 has 2 (c80638a + 3296139).
approach doc §5's per-round conflict predictions assumed the base advances.
It did not, so S4 met 20 conflicts where the table predicted 0.
…he baseline on every conflict count; replace the mixed series with regeneration counts
The '2 -> 5 -> 11 -> 20' series mixed baselines: S2's 5 was measured AFTER
-s ours restore, S4's 20 BEFORE it. Unified, neither reading rises
monotonically (restored 2/5/11/2, raw 2/15/11/20), and the series was never
in the ledger.
S3 (11) is a COUNTEREXAMPLE, not an example: its merge-base was af4f6f8,
lineage intact, no restore done, regeneration 0.
The evidence for 'lineage divergence costs conflicts' is the regeneration
count on one baseline: S2 10-of-15 -> S4 18-of-20, S3 zero.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Jun025@dlunch