Skip to content

Commit 42e99a7

Browse files
authored
[rustjava-adopt-cp-tag-passthrough-detectable-p1] docs(classfile): 「원인」을 실을 값은 있다 — 제안의 역사·책임·범위를 바로잡는다 (#56)
[rustjava-adopt-cp-tag-passthrough-detectable-p1] docs(classfile): 「원인」을 실을 값은 있다 — 제안의 역사·책임·범위를 바로잡는다
2 parents 6e016a2 + a48a593 commit 42e99a7

5 files changed

Lines changed: 204 additions & 3 deletions

File tree

‎REPORT.md‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,31 @@
4141
★그래도 적는 이유: ★**제안이 걱정한 드리프트가 «실재»한다는 첫 직접 증거**다.
4242
- 검증: `cargo test --all` **572 / 0 failed / 1 ignored**(doc 주석만 바꿔 **불변**) · DoD 7명령 rc=0.
4343
- 후속 추천: 루트 5건이 **왜** 재현되지 않는지 규명(M) — 상세 = `docs/worklog/2026-09-17-javac-fixture-provenance-verified.md`.
44+
## [2026-09-17] `ClassFileError` 가 «원인»을 실어야 하는가 — ★**판정: 할 값 있다. 단 제안의 이름·이유·범위가 셋 다 틀렸다** (rustjava-adopt-cp-tag-passthrough-detectable-p1)
45+
- 무엇을: 낱말이 **`Decide`** 인 제안을 **판정**했다. ★**코드 변경은 «틀린 주석 한 곳» 정정뿐** — 구현은 후속으로 넘겼다.
46+
- 왜: 채택 제안 `2026-09-16-cp-tag-passthrough-detectable#p1`.
47+
- 사용자 영향: 없다(판정). ★바뀐 것은 ★**착지한 트리가 «거짓 전제»를 나르지 않게 된 것**이다.
48+
- ★★**제안의 «역사»가 거짓이다 — 두 겹으로**: ⑴`822504b` 는 `classfile/src/error.rs` 를 **«자르지» 않고 «만들었다»**
49+
(`new file` · 내용이 지금과 **동일한 2변형**) ⑵그 이전에는 `ClassInfo::parse` 가 **`Option<Self>`** 를 돌려줬다
50+
(실패에 정보 **0**) ⇒ ★**그 커밋은 «후퇴»가 아니라 «개선»이었고, 「again」·「restore」는 성립하지 않는다.**
51+
- ★★**「upstream 이 해야 한다」도 거짓**: `upstream/main` 기준 **5커밋 뒤**이고 그중 이 파일들을 만지는 것 **0건** ·
52+
upstream 이 `error.rs` 를 만진 커밋은 **1건(생성)** 뿐 · ★**우리는 이미 이 crate 에서 크게 갈렸다**
53+
(`constant_pool.rs` **+211/−6** · `validation.rs` **+137/−0** · `attribute.rs` **+129/−3** · `opcode.rs` **+83/−7**).
54+
※`AGENTS.md` 의 read-only 규율은 **upstream 으로 «보내는 것»**을 금할 뿐 로컬 변경을 금하지 않는다.
55+
- ★★**ⓑ 설계는 «한 enum 건너» 이미 증명돼 있다**: `ClassDefinitionError::UnsupportedFeature(&'static str)` 가
56+
**5곳**에서 쓰이며 `"ldc of a method handle"` 같은 문장을 낸다 ⇒ ★**새 발명이 아니라 «일관성 회복»**이고, 모양도 자명하다.
57+
- ★**이득(과장하지 않는다)**: kind-only 단언 **8곳**이 원인을 이름 부를 수 있게 되고, 참조 JVM 격차가 줄어든다
58+
(OpenJDK 는 `Multiple BootstrapMethods attributes…`·`argument_index 65535 has bad constant type` 를 내는데 우리는 전부 `Invalid class file`).
59+
★**그러나 「픽스처보다 강한 자물쇠」는 «절반만» 참이다** — 원인은 「어느 검사가 울렸나」를, 픽스처는 「그 검사가 관측 가능한가」를 잠근다.
60+
★**증거**: 직전 `-fix` 가 찾은 구멍(신원 4축 중 3축 미관측)은 **링크 축**이라 원인을 실었어도 **안 잡혔다**.
61+
- ★★**비용 — 제안의 `target: classfile/src/error.rs` 는 틀렸다(1파일이 아니라 3층)**: 평탄화가 아래로 두 번 더 일어난다
62+
(`InvalidFormat` → `ClassDefinitionError::InvalidClassFile`(From 이 원인을 버린다) → ★**하드코딩 문자열 2곳**).
63+
⇒ ★**`error.rs` 만 고치면 관측 변화가 «0»** 이다. ★**진짜 비용은 `validate_class` 의 8항 `||` 사슬을 쪼개는 것**이고,
64+
그것은 이 티켓이 **금지한 리팩터**다 ⇒ ★**여기서 구현하지 않고 «범위를 바로잡아» 넘겼다.**
65+
- 검증: `cargo test --all` **572 / 0 failed / 1 ignored**(주석만 바꿔 불변) · DoD 7명령 rc=0.
66+
- 후속 추천: 원인을 **3층에 관통**시키고 `validate_class` 를 **검사마다 반환**으로 쪼갠다(M) —
67+
★「⑴만 하고 멈추면 관측 변화 0 · ⑷ 없이 하면 평탄함이 «이사»할 뿐」까지 제안에 적었다.
68+
상세 = `docs/worklog/2026-09-17-classfile-error-cause-decision.md`.
4469
## [2026-09-17] 신원 4축을 «각각» 관측 가능하게 했다 — 감사의 「고칠 것이 없다」를 정정한다 (rustjava-adopt-cp-tag-passthrough-detectable-p0-fix)
4570
- 무엇을: `string_concat.rs` 의 부트스트랩 신원 **4축**(kind·class·name·descriptor) 중 ★**3축이 «관측되지 않고» 있었다** —
4671
근접 실패 픽스처가 **class 축 하나**뿐이었기 때문이다. 나머지 3축의 픽스처를 만들었다. ★**제품 코드 무접촉.**

‎STATE.md‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,43 @@
7979
★★**게이트③ 2회차 — 형제 #59 가 그 사이 착지(`66bc49e8`)해 base 를 다시 당겼다.** 충돌은 또 **원장 2파일뿐**(코드 충돌 0).
8080
★**이번엔 시간순이 «뒤집혔다»** — main 쪽 항목(`3b04712e` 06:52)이 이 회차(`38c02a2d` 05:22)보다 **뒤**라 **위**에 얹었다.
8181
★두 번의 base 당김을 거쳐도 이 PR 의 기여 numstat 은 **불변**(`94/0` 검증 스크립트 · `14/2` 핀 테스트 · worklog 2건).
82+
- [rustjava-adopt-cp-tag-passthrough-detectable-p1] ★★**판정 — `ClassFileError` 에 «원인»을 실을 값은 있다. 단 제안의 이름·이유·범위가 «셋 다» 틀렸다.**
83+
채택 제안 `2026-09-16-cp-tag-passthrough-detectable#p1`(worklog json `adoptedProposals` 기록). 낱말이 **`Decide`** 다
84+
⇒ ★**코드 변경은 «틀린 주석 한 곳» 정정뿐** · 구현은 **범위를 바로잡아 후속으로** 넘겼다.
85+
★★**⑴역사가 거짓이다**: `822504b` 는 `error.rs` 를 **«자르지» 않고 «만들었다»**(`new file` · 지금과 동일한 2변형)이고,
86+
그 이전 `ClassInfo::parse` 는 **`Option<Self>`**(실패에 정보 **0** · `.unwrap()` 투성이)였다 ⇒ ★**그 커밋은 «개선»이었다.**
87+
⇒ ★**「carry a cause **again**」·「restoring」은 성립하지 않는다 — 이 리니지에 원인이 실렸던 시기는 «없다».**
88+
★★**⑵「upstream 이 해야 한다」도 거짓**: `upstream/main` 기준 **5커밋 뒤** · 그중 이 파일들을 만지는 것 **0건** ·
89+
upstream 의 `error.rs` 접촉은 **1건(생성)** 뿐(이 crate 에서 가장 안정된 파일) · ★**우리는 이미 이 crate 에서 크게 갈렸다**
90+
(`constant_pool.rs` +211/−6 · `validation.rs` +137/−0 · `attribute.rs` +129/−3 · `opcode.rs` +83/−7).
91+
※`AGENTS.md` read-only 는 **upstream 으로 «보내는 것»** 금지이지 로컬 변경 금지가 아니다.
92+
★★**⑶범위도 틀렸다 — `target: classfile/src/error.rs` 는 1파일인데 평탄화는 «3층»이다**:
93+
`InvalidFormat`(생산 9곳) → `ClassDefinitionError::InvalidClassFile`(**From 이 원인을 버린다**) →
94+
★**`"Invalid class file"` 하드코딩 2곳**(`src/runtime.rs:189` · `test-utils/src/lib.rs:334`).
95+
⇒ ★**`error.rs` 만 고치면 «관측 변화 0»** — 아무도 원인을 넣지 않고 아무도 읽지 않는, 이 저장소가 규탄하는 그 형태다.
96+
★★**진짜 비용은 `validate_class` 의 «8항 `||` 사슬»을 쪼개는 것**이다(원인이 갈리는 유일한 자리) —
97+
★그것은 이 티켓이 **명시적으로 금지한 리팩터**(계약 3)라 ★**여기서 구현하지 않았다.**
98+
★★**ⓑ 그런데 설계는 «한 enum 건너» 이미 증명돼 있다** — `ClassDefinitionError::UnsupportedFeature(&'static str)` 가
99+
**5곳**에서 쓰이며 `"ldc of a method handle"` 같은 문장을 낸다 ⇒ ★**새 발명이 아니라 «일관성 회복»**이고 이것이 「할 값 있다」의 근거다.
100+
★**이득을 과장하지 않는다**: kind-only 단언 **8곳**이 원인을 이름 부를 수 있고 참조 JVM 격차가 준다.
101+
★**그러나 제안의 「픽스처보다 강한 자물쇠」는 «절반만» 참** — 원인은 «어느 검사가 울렸나», 픽스처는 «그 검사가 관측 가능한가»를 잠근다.
102+
★**증거**: 직전 `-fix` 가 찾은 구멍(신원 4축 중 3축 미관측)은 **링크 축**이라 ★**원인을 실었어도 안 잡혔다** ⇒ **대체가 아니라 «더하기»다.**
103+
★**지금 고친 것**: `tests/test_class_format.rs` 머리 주석 — ★**제안이 근거로 인용한 바로 그 문장**이 거짓이었다
104+
(「cut 822504b」·「Restoring it needs upstream variants」) ⇒ 그 자리에서 정정했다.
105+
★**착지한 트리가 거짓을 나르면 다음 사람이 같은 전제로 같은 제안을 다시 만든다.**
106+
★두 번째 언급(「`ClassFileError` 가 평탄화한다」)은 **참**이라 **건드리지 않았다**(과잉 편집 0).
107+
★`cargo test --all` **572 / 0 failed / 1 ignored**(주석만 바꿔 **불변**) · DoD **7줄 전건 rc=0**.
108+
★★**게이트③ 착지 — PR #56 · `--merge`**(등재 repo · `merge_strategy: merge` 선언분). 게이트② **approve** ·
109+
핀 `53ca3409` **불이동**(착수 실측 2026-09-17T00:42:56Z · 핀에서 `ci-presence` **rc=0 CI_GREEN**).
110+
★**충돌은 원장 2파일뿐**(`REPORT.md`·`STATE.md`) — 형제 **#55** 착지분과 겹쳤고 **코드 파일 충돌 0**.
111+
★★**`tests/test_class_format.rs` 는 «자동 병합»됐고 그것을 믿지 않고 쟀다** — 양측 델타가 둘 다 살아 있다
112+
(이쪽 **10/3** · main 측 **32/0** · 추가·삭제줄 다중집합 **전건 일치** · 스위트 14/14 green).
113+
원장 해소는 전건 보존·합집합·**시간순**: 이 회차(`53ca3409` 04:31)가 main 쪽 최신 항목(`30a31bda` 04:04)보다 **뒤**라 위에 얹었다.
114+
★줄 소실 **0**(양방향) · 합집합 밖 신규줄 **0** · 계약 12 착지 diff numstat **해소 전후 동일**.
115+
★배포 **0**(이 저장소에 배포 워크플로 없음) · 자식 PR **0건** · 주기 자동 커밋 **0건**.
116+
★★**게이트③ 2회차 — 형제 #59(`66bc49e8`)·#58(`6e016a27`)이 그 사이 착지해 base 를 다시 당겼다.** 충돌은 또 **원장 2파일뿐**(코드 충돌 0).
117+
★**시간순이 이 회차를 «맨 아래»로 보낸다**(06:52 · 05:22 > 04:31) — 「내 것이 위」가 아니라 «잰 시각»이 규칙이다.
118+
★`tests/test_class_format.rs` 는 두 번 다 **자동 병합**됐고 두 번 다 양방향으로 쟀다(이쪽 **10/3 불변** · main 델타 **누락 0**).
82119
- [rustjava-adopt-cp-tag-passthrough-detectable-p0-fix] ★★**신원 4축을 «각각» 관측 가능하게 했다 — 감사의 「고칠 것이 없다」를 정정한다.**
83120
게이트② **request-changes** 승계(PR #55 · 핀 `ab13a3c7`). ★**제품 코드 무접촉** — 없던 것은 **픽스처**다.
84121
★★**무엇이 틀렸나**: 직전 감사의 **M7**(「신원 4축 검사 제거」)은 네 비교를 ★**한꺼번에** 지운다 ⇒ 그 red 가 증명하는 것은
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"schema": "worklog/v1",
3+
"date": "2026-09-17",
4+
"taskId": "rustjava-adopt-cp-tag-passthrough-detectable-p1",
5+
"summary": "Decided whether ClassFileError should carry a cause. Verdict: worth doing, but the proposal's history, blame and scope are all wrong, and doing it properly needs a refactor this ticket forbids. Recorded the corrected scope and fixed the false comment the proposal cited.",
6+
"changes": [
7+
"tests/test_class_format.rs: the header comment claimed the variants were cut upstream at 822504b and that restoring them needs upstream changes. Both are false; replaced with what is actually true and why.",
8+
"docs/worklog/2026-09-17-classfile-error-cause-decision.{md,json}: the decision, its evidence, and the scope handed to a follow-up"
9+
],
10+
"verification": [
11+
"current state: classfile/src/error.rs still has two variants, and 8 assertions in tests/test_class_format.rs check only the ClassFormatError kind",
12+
"822504b created classfile/src/error.rs as a new file with these same two variants; before it, ClassInfo::parse returned Option, so failure carried nothing at all — the commit was an improvement, not a cut",
13+
"upstream is not the blocker: we are 5 commits behind upstream/main and none of them touch these files; upstream has touched classfile/src/error.rs exactly once (its creation); our fork already diverges by +211/-6 in constant_pool.rs, +137/-0 in validation.rs, +129/-3 in attribute.rs, +83/-7 in opcode.rs",
14+
"the pattern already exists one enum over: ClassDefinitionError::UnsupportedFeature(&'static str) is used at 5 sites and produces messages like 'ldc of a method handle'",
15+
"the flattening happens at three layers, not one: ClassFileError::InvalidFormat (9 production sites) -> ClassDefinitionError::InvalidClassFile (the From impl drops any cause) -> a hardcoded \"Invalid class file\" string at src/runtime.rs:189 and test-utils/src/lib.rs:334",
16+
"validate_class evaluates an eight-term || chain and returns one InvalidFormat, so a per-check cause requires splitting that chain — a refactor this ticket forbids",
17+
"cargo test --all: 572 passed / 0 failed / 1 ignored, unchanged (the only code change is a comment)",
18+
"DoD 7 commands all rc=0"
19+
],
20+
"issues": [
21+
"The proposal's claim that a cause would be 'a stronger lock than a carefully shaped fixture' is half true: a cause locks which check fired, a fixture locks whether the check is observable at all. The hole the sibling -fix round found was in linking, not parse errors, so a cause would not have caught it.",
22+
"Implementing only the proposal's stated target (classfile/src/error.rs) would produce no observable change, since nothing would set the cause and nothing would read it."
23+
],
24+
"adoptedProposals": [
25+
"2026-09-16-cp-tag-passthrough-detectable#p1"
26+
],
27+
"proposals": [
28+
{
29+
"title": "Thread a cause through ClassFileError, and split validate_class so it can differ",
30+
"plainSummary": "Give class file rejections a reason, all the way out to the exception message a user sees.",
31+
"userBenefit": "A rejected class file says what is wrong with it — 'unknown constant pool tag', 'bootstrap argument names nothing' — instead of the same 'Invalid class file' for every cause, which is what a real JVM does.",
32+
"why": "Decided in this round after measuring: the design already exists one enum over (ClassDefinitionError::UnsupportedFeature carries &'static str at 5 sites), upstream is not the blocker, and 8 assertions currently can only check the exception kind. The work is ClassFileError::InvalidFormat(&'static str), the same on ClassDefinitionError::InvalidClassFile so the From impl stops dropping it, the two hardcoded message sites (src/runtime.rs, test-utils/src/lib.rs), and splitting validate_class's eight-term || chain so each check can name itself.",
33+
"tradeoff": "Doing only the error type changes nothing observable, and doing it without splitting the || chain just moves the flatness rather than removing it — so this is an all-or-nothing scope, and it includes a refactor of validate_class. It also does not replace the shaped-fixture discipline: a cause says which check fired, not whether each axis of a multi-axis check is observable.",
34+
"effort": "M",
35+
"target": "classfile/src/error.rs, classfile/src/validation.rs, jvm-bytecode/src/error.rs, src/runtime.rs, test-utils/src/lib.rs"
36+
}
37+
]
38+
}

0 commit comments

Comments
 (0)