Skip to content

Commit 2a393c9

Browse files
author
jun0
committed
[rustjava-adopt-test-data-version-freeze-uniform-target-p0-fix] docs: 후속을 «기계 채널»에 싣고 대표 수치를 자기 산술에 맞춘다
게이트② 반려 5건. 결정(「모으지 않는다」)과 되돌릴 조건 4개는 무접촉 — 바뀐 것은 수와 문장이다. ⒟(급소) worklog .json 에 proposals 키가 «아예 없었다» ⇒ REPORT 는 후속 2건을 쓰는데 cockpit 에 도달하는 카드는 0장이었다. 7키를 채운 카드 2장을 넣었다. ★단 초판이 ⑴로 적은 「NativeMethod 제3 축 여부」는 검수자가 규명해 닫혔으므로 카드로 내지 않고, 그 자리에 검수자가 지목한 「되돌릴 조건에 관측자가 없다」를 넣었다(닫힌 질문을 채택하게 만들지 않으려고). ⒜ 「5 of the 20」이 자기 산술과 어긋났다(5+16=21≠20). 선별 기준(StringBuilder 없음)에서 정의상 배제된 2건을 얹은 수이고, 방향이 「버전이 답」 쪽 과대라 결론을 더 세게 보이게 했다 ⇒ 3 으로 내리고 «세는 집합»을 문장 안에 명시했다. 네 곳(정본·REPORT·worklog .md·.json)을 맞췄다. ⒝ 「lose StringBuilder outright」가 셋 중 하나에서 거짓. FormatterIntegration$FailingAppendable 은 FormatterIntegration.java:36 의 private final StringBuilder 필드 = 명시적 API 라 target 과 무관하다. ⒞ 「소스 없음」은 공집합이다 — major-52 40건 전건이 소스를 갖는다(INNER 18 · TOP 22 · NOSRC 0). 실제 배제는 내부 클래스 18 + StringBuilder 보유 TOP 2. 수 20 은 맞고 이유가 틀렸다. 선별 기준도 「단독 재빌드 가능」이 아니라 「최상위 + StringBuilder 없음」이다(재빌드 가능은 결과). ⒠ 「target policy」 파일에 신규 fixture 문장이 0건이었다 ⇒ "What this does not decide" 한 절. NativeMethod 는 재조사하지 않고 검수자 결과를 인용했다 — 제3 축이 아니라 축 2(JEP 181)의 다른 얼굴이고(자기 클래스가 자기 nest host 라 access$ 없이 opcode 만 이동), 되돌릴 조건 ⑷의 전제가 사라져 「새 후보를 기다린다」로 바꿨다. 상이 3건이 두 축으로 전부 설명된다(잔여 0). 재컴파일 0 · 픽스처 0바이트 · .rs 무접촉 · check-worklog-json.py 무접촉. cargo test --all 583/0/1(base 8c7b473, 불변).
1 parent 481f86b commit 2a393c9

4 files changed

Lines changed: 87 additions & 20 deletions

File tree

‎REPORT.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
- 무엇을: 채택 제안 `2026-09-17-test-data-version-freeze#p0` 의 **결정**(worklog json `adoptedProposals` 기록). ★**코드 0행 · 재컴파일 0 · `.class` 바이트 0 변경** — 산출물은 `docs/test-data-target-policy.md` 와 그 근거다.
44
- ⑴**분포**(동결 파일이 아니라 fixture 자신에서 읽었다): 루트 **114**건 · major **52×40 · 65×62 · 66×8 · 68×1 · 70×3** — 동결 파일 머리주석과 일치.
55
- ⑵★★**양방향으로 갈랐다 — 이것이 이 회차의 실질이다**:
6-
⒜★**버전이 곧 시험 대상**: **문자열 연결**(52 의 `StringBuilder` 3건을 21 로 재컴파일하면 ★`BootstrapMethods` 생기고 `StringBuilder` 사라짐 · ★`StringConcat.class` 는 루트에서 indy 를 가진 **유일한** fixture ⇒ **낮춤 전략마다 하나씩**) · **nestmate**(`ThreadInterruption` `access$`**×10** → 21 에서 **0 + `NestMembers`** · `MonitorSemantics` ×4 동일 · JEP 181).
6+
⒜★**버전이 곧 시험 대상**: **문자열 연결**(52 의 `StringBuilder` 3건을 21 로 재컴파일하면 ★`BootstrapMethods` 가 생기고, 그중 **둘**은 `StringBuilder` 가 사라진다 — ★**셋째 `$FailingAppendable` 은 남는다**(`FormatterIntegration.java:36` 의 명시적 필드 선언 = 낮춤 산물이 아니다) · ★`StringConcat.class` 는 루트에서 indy 를 가진 **유일한** fixture ⇒ **낮춤 전략마다 하나씩**) · **nestmate**(`ThreadInterruption` `access$`**×10** → 21 에서 **0 + `NestMembers`** · `MonitorSemantics` ×4 동일 · JEP 181).
77
⒝★**아무 버전이나 되는 것**: 「`StringBuilder`·indy 둘 다 없고 단독 재빌드 가능」한 20건을 21 로 재컴파일해 **명령 시퀀스 전체 대조** → ★**16건 완전 동일**.
8-
⇒ ★**본 20건 중 5건은 버전이 답이고 16건은 아무래도 좋다.**
8+
⇒ ★**본 20건 중 «3건»이 버전이 답이고(nestmate 2 + `NativeMethod`) 1건은 단독 재빌드 불가, 16건은 아무래도 좋다.** ★초판이 적은 「5건」은 **자기 산술과 어긋났다**(5+16=21≠20) — 선별에서 «이미 배제한» `StringBuilder` 2건을 얹어야 나오는 수이고, ★**결론을 더 세게 보이게 하는 방향의 오차**였다(결론은 이 비가 아니라 「0·0」에 선다).
99
- ★★**그 커버리지는 다른 데 없다**: `test-data/{cp,indy,ldc,attr}` 생성기 산출 **64건 전수**에서 `StringBuilder` **0** · `access$` **0** ⇒ 루트 52 무리가 **유일한 시험면**이다.
1010
- ★**결론의 근거**: 제안의 이득(「숫자 하나로 예측」)이 실측에 **뒤집힌다** — 지금 major 52 는 「전-indy·전-nestmate」라는 **뜻을 실제로 갖고**, 전부 펴면 그 구분이 사라지며 **런타임이 아직 구현해야 하는 두 경로의 유일한 커버리지**가 지워진다. 대가도 실재한다(핀 `test_fixture_pins` · 루트 **66건**의 `.txt` 출력 대조).
1111
- ★**잃는 것**: 비균일은 그대로 남고(신규 fixture 의 target 규칙은 **세우지 않았다** — 별 축) · 16건은 「아무래도 좋은 채」로 남으며 · ★**본 것은 40 중 20 이다**(16/20 을 40 의 비로 읽지 마라) · ★`NativeMethod` 의 명령 차이는 **원인을 못 밝혔다**.
1212
- 검증: `cargo test --all` **583 passed / 0 failed / 1 ignored**(불변 — 코드 무접촉 · ★이 브랜치 base `8c7b473f` 기준이다. 같은 날 앞 회차들의 **579** 는 PR #61 착지 «전» base 의 수라 다르다) · `check-dod-ci-parity` → **「OK 두 축 모두 대칭차 0 — 명령 6개 · toolchain 2개로 «둘 다 일치»」**.
13-
- ★후속 추천: ⑴`NativeMethod` 의 제3 축 여부 규명(S) ⑵**신규 fixture 의 target 규칙**을 세울 것인가(M) — 상세 = `docs/worklog/2026-09-18-root-fixture-target-decision.md`.
13+
- ★후속 추천(★**worklog `.json` `proposals[]` 에 카드 2장으로 «기계 채널»에 실었다** — 초판은 `REPORT` 에만 적어 cockpit 에 **0장**이었다): ⑴**신규 fixture 의 target 규칙**을 세울 것인가(M) ⑵**되돌릴 조건에 «관측자»를 붙인다**(S · 넷 중 셋은 문서를 열어야만 발화한다 — 게이트② 실측). ★초판이 ⑴로 적은 「`NativeMethod` 제3 축 여부」는 ★**검수자가 규명해 닫혔다**(축 2 의 다른 얼굴) ⇒ 카드로 내지 않는다. 상세 = `docs/worklog/2026-09-18-root-fixture-target-decision.md`.
1414

1515
## [2026-09-17] 코드 2파일 합집합 — ★**그런데 ours 의 «삭제»는 의도가 아니라 선행 머지의 «조용한 롤백»이었다** (rustjava-adopt-link-stringconcatfactory-p2-fix3)
1616
- 무엇을: 게이트③이 `code-conflict-out-of-scope` 로 세운 PR #61 의 충돌 4파일(원장 2 + 코드 2)을 합집합으로 해소. ★제품 Rust **0줄**(테스트·픽스처 생성기만).

‎docs/test-data-target-policy.md‎

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ comparing, not by reading the spec.
3131

3232
- Three major-52 fixtures carry `StringBuilder`: `FormatterIntegration`,
3333
`FormatterIntegration$FailingAppendable`, `NullSpecGuards`.
34-
- Recompiled at 21 they gain `BootstrapMethods` and lose `StringBuilder` outright.
34+
- Recompiled at 21 all three gain `BootstrapMethods`. Two of them — `FormatterIntegration` and
35+
`NullSpecGuards` — lose `StringBuilder` entirely. The third does not: `FailingAppendable`
36+
declares `private final StringBuilder output` at `test-data/src/FormatterIntegration.java:36`,
37+
so that use is the program asking for the class by name rather than the compiler reaching for it,
38+
and no target changes it. What moves is the concatenation, not every mention.
3539
- `StringConcat.class` (major 65) is the **only** root fixture that has `invokedynamic` at all.
3640

3741
So the root tree holds exactly one fixture per lowering strategy. Retargeting the 52 cohort would
@@ -48,9 +52,14 @@ through a synthetic `access$NNN` bridge; from 11 on, `NestHost`/`NestMembers` pe
4852
This repo added `NestHost`/`NestMembers` handling only recently, which makes both sides live test
4953
surface rather than legacy.
5054

51-
**Not explained.** `NativeMethod` also changes opcode counts at 21 (`invokespecial` 3→2,
52-
`invokevirtual` 1→2) with no nest attributes and no `StringBuilder` on either side. The cause was
53-
not isolated. It is recorded here as a real difference rather than folded into the two axes above.
55+
**`NativeMethod` is the same second axis wearing a different face.** It changes opcode counts at
56+
21 (`invokespecial` 3→2, `invokevirtual` 1→2) with no nest attributes on either side, which this
57+
document first recorded as unexplained. The gate-2 review isolated it: the whole `javap -c -p` diff
58+
is one line, `invokespecial` becoming `invokevirtual` on a call to `private native void missing()`
59+
made from `static main` in the same class. After JEP 181 a member of a nest reaches its own private
60+
methods directly, so there is no `access$` bridge to delete here — the class is its own nest host —
61+
and only the opcode moves. So all three of the differing fixtures are accounted for by the two axes,
62+
with nothing left over.
5463

5564
**This coverage exists nowhere else.** Across the 64 generator-built fixtures in `test-data/cp`,
5665
`indy`, `ldc` and `attr`, the counts of `StringBuilder` and of `access$` bridges are both **zero**.
@@ -66,8 +75,17 @@ Of the 40 major-52 fixtures, 20 have a rebuildable source and carry neither `Str
6675
- 3 differ, and they are the two nestmate cases plus `NativeMethod` above.
6776
- 1 could not be rebuilt alone (it references a sibling; see `verify-javac-fixtures.sh`).
6877

69-
So the honest split is: **the target matters for 5 of the 20 examined, and for the other 16 it
70-
buys nothing** — which is also why uniformity is not worth its cost.
78+
So the honest split is: **of the 20 examined the target matters for 3, one cannot be rebuilt
79+
alone, and for the remaining 16 it buys nothing** — which is also why uniformity is not worth its
80+
cost. The three are the two nestmate cases and `NativeMethod`.
81+
82+
A first draft of this document said "5 of the 20". That was wrong by its own arithmetic — 5 + 16 is
83+
21 — and wrong in the direction that flatters the conclusion, because it reached the 5 by adding
84+
the two string-concatenation fixtures, which the selection had *already excluded* for carrying
85+
`StringBuilder`. The conclusion does not rest on this ratio (it rests on the zero-coverage
86+
measurement below), but a policy document's headline number should be countable from its own
87+
bullets, so it is stated here with the set it counts: the 20 are the major-52 fixtures that are
88+
top-level and free of `StringBuilder`.
7189

7290
## Why not unify anyway
7391

@@ -82,6 +100,13 @@ in `test-data/class-file-versions.txt` and asserted by `tests/test_fixture_pins.
82100
fixtures have their stdout compared against a committed `.txt` by `tests/test_class.rs`. A bulk
83101
retarget is therefore a per-fixture judgement, and for 16 of 20 the judgement returns "no change".
84102

103+
## What this does not decide
104+
105+
Nothing here says which target a *new* fixture should be built for. This round looked only at the
106+
fixtures that already exist and decided not to move them; the rule for new ones is a separate
107+
question and was deliberately left open. Until it is answered, a new fixture's target is whatever
108+
its author chose, and the freeze records that rather than judging it.
109+
85110
## Reopen this decision if
86111

87112
- **The runtime drops support for the old shapes.** If RustJava stops accepting major ≤ 52, or
@@ -92,8 +117,9 @@ retarget is therefore a per-fixture judgement, and for 16 of 20 the judgement re
92117
- **The freeze goes away.** This decision assumes `class-file-versions.txt` plus
93118
`test_fixture_pins.rs` keep the versions from moving on their own. Without that guarantee the
94119
question is no longer "should they be uniform" but "why did they change".
95-
- **`NativeMethod`'s difference is explained** and turns out to be a third version axis — that
96-
would widen the "version is the subject" set and strengthen, not weaken, this decision.
120+
- **A third version axis turns up.** `NativeMethod` was the open candidate and is now closed as
121+
the nestmate axis again, so the current set is two. A genuinely new one would widen the "version
122+
is the subject" set and strengthen, rather than weaken, this decision.
97123

98124
Re-measure rather than re-argue. The commands are in the round's worklog:
99125
`docs/worklog/2026-09-18-root-fixture-target-decision.md`.

‎docs/worklog/2026-09-18-root-fixture-target-decision.json‎

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,39 @@
1010
"version distribution read from the fixtures themselves (od on bytes 6-7), not from the freeze file: 114 root fixtures, major 52 x40, 65 x62, 66 x8, 68 x1, 70 x3 — matches what test-data/class-file-versions.txt's header claims",
1111
"VERSION IS THE SUBJECT, axis 1: the three major-52 fixtures carrying StringBuilder (FormatterIntegration, its inner class, NullSpecGuards) gain BootstrapMethods and lose StringBuilder when recompiled at --release 21. StringConcat.class (major 65) is the only root fixture with invokedynamic at all, so the tree holds exactly one fixture per lowering strategy",
1212
"VERSION IS THE SUBJECT, axis 2: ThreadInterruption has 10 access$ bridges and no nest attributes at 52; at 21 the bridges are gone and NestMembers appears. MonitorSemantics the same with 4. That is JEP 181 nestmates, and this repo added NestHost/NestMembers handling recently",
13-
"VERSION IS IRRELEVANT: of the 20 major-52 fixtures with a rebuildable source and neither StringBuilder nor BootstrapMethods, 16 recompile at --release 21 to an identical full opcode sequence; 3 differ (the two nestmate cases plus NativeMethod) and 1 cannot be rebuilt alone",
13+
"VERSION IS IRRELEVANT: of the 20 major-52 fixtures that are top-level and carry neither StringBuilder nor BootstrapMethods, 16 recompile at --release 21 to an identical full opcode sequence; 3 differ (the two nestmate cases plus NativeMethod) and 1 cannot be rebuilt alone",
1414
"NO REDUNDANT COVERAGE: across the 64 generator-built fixtures in test-data/{cp,indy,ldc,attr}, the count of StringBuilder is 0 and of access$ bridges is 0 — so the root 52 cohort is the only place those paths are exercised",
15-
"cargo test --all: 583 passed / 0 failed / 1 ignored, unchanged — this round adds no code. Measured on this branch's base 8c7b473f; earlier rounds the same day reported 579 against a base that predates PR #61's landing, so the two numbers are both correct for their own base and should not be compared directly."
15+
"cargo test --all: 583 passed / 0 failed / 1 ignored, unchanged — this round adds no code. Measured on this branch's base 8c7b473f; earlier rounds the same day reported 579 against a base that predates PR #61's landing, so the two numbers are both correct for their own base and should not be compared directly.",
16+
"SELECTION, restated after gate 2: the 20 are 22 top-level major-52 fixtures minus the 2 that carry StringBuilder. Counted at fix time: INNER 18, TOP 22, NOSRC 0 — every one of the 40 has a source under test-data/src, so 'no source' was an empty set and the first draft's stated reason for excluding the other 20 was wrong even though the count was right.",
17+
"NativeMethod, resolved by the gate-2 review and cited rather than re-investigated: the whole javap -c -p diff is one line, invokespecial becoming invokevirtual on a call to a private native method from static main in the same class. That is JEP 181 again — the class is its own nest host, so there is no access$ bridge to remove and only the opcode moves. All three differing fixtures are therefore explained by the two axes, with no residue."
1618
],
1719
"issues": [
1820
"NativeMethod's opcode counts also change at 21 (invokespecial 3->2, invokevirtual 1->2) with no nest attributes and no StringBuilder on either side. The cause was not isolated; it is recorded as a real difference rather than attributed to one of the two axes. If it turns out to be a third version axis it widens the 'version is the subject' set.",
1921
"The 'no redundant coverage' claim is a measurement with a date, not a standing property. A later round that adds StringBuilder or access$ fixtures under test-data/ subdirectories would make the root cohort redundant and this decision should be re-run.",
20-
"The 20 examined are the major-52 fixtures that can be rebuilt alone. The other 20 at major 52 either have no source under test-data/src or carry an inner-class marker, so the 16/20 ratio is not a claim about all 40."
22+
"The 20 examined are the top-level major-52 fixtures without StringBuilder. The other 20 are 18 inner classes plus the 2 top-level fixtures that carry StringBuilder — 'no source' is an empty set, since all 40 have one. The 16/20 ratio is not a claim about all 40. Selection is by source shape, not by rebuildability: one of the 20 (VirtualDispatchSemantics) could not be rebuilt alone, which is a result rather than a criterion.",
23+
"One of the three string-concatenation fixtures does not lose StringBuilder when retargeted. FormatterIntegration$FailingAppendable declares `private final StringBuilder output` at test-data/src/FormatterIntegration.java:36, so that use is explicit API rather than a lowering artefact and survives any target. What the target moves is the concatenation, not every mention."
2124
],
2225
"adoptedProposals": [
2326
"2026-09-17-test-data-version-freeze#p0"
27+
],
28+
"proposals": [
29+
{
30+
"title": "Decide which target a newly added root fixture should be built for",
31+
"plainSummary": "We decided not to move the fixtures we already have, but nobody has said what target a new one should use, so the next person picks whatever their JDK defaults to.",
32+
"userBenefit": "A fixture's target stops being an accident of who added it and when, which is the drift the freeze can record but not prevent.",
33+
"why": "The decision round measured the existing spread and left this open on purpose — it is about new files, not existing ones, so folding it in would have widened a decision ticket into a policy one. The freeze plus test_fixture_pins stops a fixture moving on its own but says nothing about what it should have been. Measured in that round: the target changes the shape for 3 of 20 examined and is arbitrary for 16, so the answer is probably 'pick one and say why', not 'it does not matter'.",
34+
"tradeoff": "Picking a single target contradicts the decision this round just made for existing fixtures, so the rule has to be written as 'new fixtures default to X unless the test is about a version behaviour', and that exception is where the judgement lives — which means the rule cannot be fully mechanical. Writing it also invites a follow-up urge to retrofit existing fixtures, which this round measured as not worth its cost.",
35+
"effort": "M",
36+
"target": "docs/test-data-target-policy.md, AGENTS.md"
37+
},
38+
{
39+
"title": "Give the revert conditions in the target policy an observer",
40+
"plainSummary": "The policy lists four conditions that should make us revisit it, but only one of them is something a person or a check would actually notice.",
41+
"userBenefit": "A decision that records when it stops being true is only useful if someone finds out when that happens; otherwise it quietly becomes folklore.",
42+
"why": "Measured by the gate-2 review of that round: of the four conditions, 'the freeze goes away' is effectively self-enforcing because deleting class-file-versions.txt or test_fixture_pins.rs shows up as a diff and a red test; 'that coverage turns up elsewhere' has a command to measure it but nobody scheduled to run it; 'the runtime drops the old shapes' has no observer at all; and the fourth was retired when NativeMethod turned out to be the nestmate axis. So three of four rely on someone happening to open the document.",
43+
"tradeoff": "The cheap version — re-run the zero-coverage count in CI — adds a check whose failure mode is a judgement call rather than a defect, and this repo has been bitten before by checks that fire on something nobody is obliged to act on. The alternative, leaving it to review discipline, is what produced the current state.",
44+
"effort": "S",
45+
"target": "docs/test-data-target-policy.md, scripts/"
46+
}
2447
]
2548
}

0 commit comments

Comments
 (0)