From 3031e2335a0928cfc6b6597826632e9eac91342c Mon Sep 17 00:00:00 2001 From: jun0 Date: Fri, 18 Sep 2026 07:31:00 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[rustjava-adopt-loadable-bootstrap-argument?= =?UTF-8?q?s-diagnostic]=20docs:=20=EC=9D=B4=20=ED=9A=8C=EC=B0=A8=EB=8A=94?= =?UTF-8?q?=20=EB=8C=80=EC=A0=84=EC=A0=9C=20=E2=93=92=20=EC=97=90=EC=84=9C?= =?UTF-8?q?=20=EB=81=9D=EB=82=9C=EB=8B=A4=20=E2=80=94=20=EA=B7=B8=20?= =?UTF-8?q?=EC=9D=BC=EC=9D=84=20=ED=95=98=EB=8A=94=20=EC=B6=95=EC=9D=B4=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=20=EB=96=A0=20=EC=9E=88=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 채택 제안 2026-09-17-loadable-bootstrap-arguments#p0 의 처분. ★코드 0행 (classfile/src/{error,validation}.rs 무접촉). 제안의 전제는 참이다 — CLI 로 돌려 확인했다: 서로 다른 세 규칙(나쁜 argument · 중복 속성 · 버전 게이트)이 글자 하나 다르지 않은 `ClassFormatError: Invalid class file` 을 낸다. 그런데 겹침이 부분이 아니라 전부다. PR #67 이 제안의 target 바로 그 두 파일을 고치고, 이 술어에 이미 사유를 주며, 밋밋한 문면이 박힌 두 경계 자리를 둘 다 고쳤다. main 에서 시작하면 같은 enum 을 세 번째로 고치고 같은 커버리지 구멍을 다시 발견한다. ★제안 자신이 tradeoff 에 「두 번 하지 말고 함께 하라」고 적어 두었다. 남는 잔여는 있으나 좁다 — #67 의 payload 는 &'static str 이라 런타임 인덱스를 구조적으로 못 담는다 ⇒ 「기대」는 달성 · 「인덱스」·「실제」는 미달. 그래서 새 카드를 좁혀 냈다(S). 원 제안은 adoptedProposals 로 처분하되 잔여를 정확한 범위로 다시 세운다 — 안 그러면 카드와 함께 잔여도 사라진다. 설계 제약 하나를 기록했다: ClassFileError 는 Copy 이고 네 크레이트가 기댄다. String 을 넣으면 깨지지만 정적사유+u16 인덱스+u8 태그면 셋 다 Copy 라 깨지 않고 된다. 잃는 것: main 은 #67 착지까지 밋밋한 채로 남는다(오늘 사용자는 규칙 이름조차 못 받는다) · 이 회차가 전달한 것은 값이 아니라 순서다 · #67 이 폐기되면 이 판단은 한 회차를 버린 것이 된다. cargo test --all 583/0/1(불변 · base 8c7b473f) · check-dod-ci-parity OK. --- REPORT.md | 12 ++++ STATE.md | 6 ++ ...tstrap-argument-diagnostic-sequencing.json | 33 +++++++++ ...ootstrap-argument-diagnostic-sequencing.md | 67 +++++++++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.json create mode 100644 docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md diff --git a/REPORT.md b/REPORT.md index 5b62ced8..4b026213 100644 --- a/REPORT.md +++ b/REPORT.md @@ -1,4 +1,16 @@ # REPORT +## [2026-09-18] 「어느 bootstrap argument 가 왜 나빴나」 — ★**대전제 ⓒ 에서 끝난다: 그 일을 하는 축이 이미 떠 있다**(rustjava-adopt-loadable-bootstrap-arguments-diagnostic) +- 무엇을: 채택 제안 `2026-09-17-loadable-bootstrap-arguments#p0` 의 처분(worklog json `adoptedProposals` 기록). ★**코드 0행** — `classfile/src/{error,validation}.rs` **무접촉**. +- ★**제안의 전제는 참이다 — CLI 로 돌려서 봤다**(`main` @ `8c7b473f`): 서로 다른 세 규칙(`LdcDynamicBSMArgPastEnd` 나쁜 argument · `LdcDynamicDuplicateBSM` 중복 속성 · `LdcDynamicOldMajor` 버전 게이트)이 ★**글자 하나 다르지 않은 `java.lang.ClassFormatError: Invalid class file`** 를 낸다. +- ★★**그런데 겹침이 «부분»이 아니라 «전부»다** — **PR #67** 이 제안의 `target` **바로 그 두 파일**을 고치고(merge-base 대비 `error.rs` **10/1** · `validation.rs` **61/27**), ★**이 술어에 이미 사유를 준다**(`"a bootstrap method argument names nothing or is not a loadable constant"`), ★밋밋한 문면이 박힌 **두 경계 자리**(`src/runtime.rs:189`·`test-utils/src/lib.rs:334`)도 **둘 다** 고쳤다. ⇒ main 에서 시작하면 **같은 enum 을 세 번째로 고치고** 같은 커버리지 구멍을 다시 발견한다. + ★**제안 자신이 그렇게 적어 두었다** — `tradeoff`: 「the two should be done together rather than twice」. +- ★**남는 것은 있다 · 다만 좁다**: `#67` 의 payload 는 **`&'static str`** 이라 ★**런타임 인덱스를 구조적으로 못 담는다** ⇒ 「기대」는 **달성**, 「인덱스」·「실제」는 **미달**. ⇒ ★**새 카드를 좁혀 냈다**(effort **S**) — 원 제안은 처분하고 잔여만 정확한 범위로 다시 세운다(안 그러면 카드와 함께 잔여도 사라진다). +- ★**제안이 적지 않은 설계 제약**: `ClassFileError` 는 **`Copy`** 이고 네 크레이트가 그것에 기댄다(`tests/test.rs` 13 · `validation.rs` 8 · `class.rs` 7 · `jvm-bytecode/src/error.rs` 5). ★**깨지 않고도 된다** — 정적 사유 + `u16` 인덱스 + `u8` 태그면 셋 다 `Copy`. 후속이 다시 발견하지 않도록 새 카드에 적었다. +- ★**#67 위에 쌓지 않은 이유**(선택이지 누락 아님): ⑴아직 approve 아님(게이트② 재검 중) ⑵head 가 회차마다 움직임 ⑶**자식 PR** 이 되어 base 소멸 시 자동으로 닫힌다(게이트③ 계약 5). +- ★**잃는 것**: ★**main 은 #67 착지까지 밋밋한 채로 남는다**(오늘 사용자는 **규칙 이름조차** 못 받는다) · 이 회차는 제안의 값을 **전혀 전달하지 않았고** 전달한 것은 **순서**다 · #67 이 폐기되면 이 판단은 **한 회차를 버린 것**이 된다. +- 검증: `cargo test --all` **583 passed / 0 failed / 1 ignored**(불변 — 코드 무접촉 · base `8c7b473f`) · `check-dod-ci-parity` → **「OK 두 축 모두 대칭차 0 — 명령 6개 · toolchain 2개로 «둘 다 일치»」**. +- ★후속 추천: 새 카드 「bootstrap argument 의 인덱스와 태그를 사유 위에 얹는다」(S) — ★**#67 «뒤»에** · 상세 = `docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md`. + ## [2026-09-17] 코드 2파일 합집합 — ★**그런데 ours 의 «삭제»는 의도가 아니라 선행 머지의 «조용한 롤백»이었다** (rustjava-adopt-link-stringconcatfactory-p2-fix3) - 무엇을: 게이트③이 `code-conflict-out-of-scope` 로 세운 PR #61 의 충돌 4파일(원장 2 + 코드 2)을 합집합으로 해소. ★제품 Rust **0줄**(테스트·픽스처 생성기만). - ★★**브리프의 전제 하나가 반증됐다** — 「ours 가 «의도적으로» 지운 54·16줄을 되살리지 마라」였는데, 두 파일의 성격이 **정반대**였다: diff --git a/STATE.md b/STATE.md index ab8991d0..125055ef 100644 --- a/STATE.md +++ b/STATE.md @@ -7,6 +7,12 @@ (둘 다 이것보다 오래됐고 MERGEABLE/CONFLICTING 처분이 이미 걸려 있다). 겹침은 전부 **append 형 합집합**이라 해소는 기계적이다) ## 완료 +- [rustjava-adopt-loadable-bootstrap-arguments-diagnostic] ★★**대전제 ⓒ 에서 끝났다 — 그 일을 하는 축(PR #67)이 이미 떠 있다.** 채택 제안 `2026-09-17-loadable-bootstrap-arguments#p0`(worklog json 기록). ★**코드 0행.** + ★**전제는 참**(CLI 실행: 세 규칙이 전부 `ClassFormatError: Invalid class file` 동일 문면) — 그러나 ★**겹침이 전부다**: #67 이 제안 `target` 두 파일을 고치고, 이 술어에 **이미 사유를 주며**, 밋밋한 문면 **두 자리**를 둘 다 고쳤다. ★제안 `tradeoff` 자신이 「두 번 하지 말고 함께 하라」고 적었다. + ★**남는 잔여는 좁다** — `&'static str` 이라 **인덱스를 못 담는다** ⇒ 「기대」 달성 · 「인덱스·실제」 미달 ⇒ ★**새 카드를 좁혀 냈다**(S). + ★**설계 제약 기록** — `ClassFileError` 는 `Copy`(4크레이트 의존) · 정적사유+`u16`+`u8` 로 **깨지 않고 된다**. + ★**잃는 것**: main 은 #67 착지까지 **밋밋한 채**(규칙 이름조차 없다) · 이 회차가 전달한 것은 **값이 아니라 순서**다. + ★`--all` **583/0/1**(불변 · base `8c7b473f`). - [rustjava-adopt-link-stringconcatfactory-p2-fix2] ★★**#57 의 버전 표에 25행 등재 — 「착지 순서」가 만든 부채를 갚는다(PR #61).** ★**막힌 것은 CI 도 충돌도 아니었다**: 핀 `85cf0fba` 에서 rc=0 CI_GREEN · `git merge origin/main` **코드 충돌 0** 인데 ★**합친 결과**가 #57 이 세운 「미등재 픽스처는 핀을 실패시킨다」를 어겼다(미등재 **25건** 재현). diff --git a/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.json b/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.json new file mode 100644 index 00000000..aa422b09 --- /dev/null +++ b/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.json @@ -0,0 +1,33 @@ +{ + "date": "2026-09-18", + "taskId": "rustjava-adopt-loadable-bootstrap-arguments-diagnostic", + "summary": "Stopped at the ticket's own precondition: an axis already doing most of this is in flight. PR #67 rewrites exactly the two files this proposal names, already gives this very predicate a cause string, and already replaces the flat 'Invalid class file' at both boundary sites. Doing it now on main would be a third competing edit to the same enum and would rediscover the same duplicated boundary. The proposal's residue after #67 is real but narrower than the proposal describes, and it is recorded as a new, correctly scoped card.", + "changes": [ + "no code: classfile/src/error.rs and classfile/src/validation.rs untouched", + "docs/worklog only — the finding, the measurements, and a narrowed successor proposal" + ], + "verification": [ + "PREMISE CONFIRMED on main @ 8c7b473f, measured by running the CLI rather than by reading: three different rules all print the identical message. `rust_java -cp ./test-data/ldc LdcDynamicBSMArgPastEnd` (bad bootstrap argument), `LdcDynamicDuplicateBSM` (duplicate attribute) and `LdcDynamicOldMajor` (version gate) each answer `java.lang.ClassFormatError: Invalid class file`", + "OVERLAP IS TOTAL: the proposal's target is classfile/src/error.rs and classfile/src/validation.rs; PR #67 changes error.rs 10/1 and validation.rs 61/27 against their merge base. #67 already gives this exact predicate the cause 'a bootstrap method argument names nothing or is not a loadable constant'", + "CONTRACT 2 SWEEP: the literal 'Invalid class file' is hardcoded at two boundary sites, src/runtime.rs:189 and test-utils/src/lib.rs:334. #67 rewrites both; a round starting from main would have to change both again and would hit the same test-coverage gap #67's round already reported", + "RESIDUE IS REAL BUT NARROWER: #67's payload is &'static str, which structurally cannot carry a runtime index. So after #67 lands the proposal's 'expected' is delivered by the rule wording and its 'index' and 'actual' are not", + "DESIGN CONSTRAINT the proposal does not name: ClassFileError derives Copy. Carrying an owned String would drop Copy for every consumer (classfile/tests/test.rs 13 uses, validation.rs 8, class.rs 7, jvm-bytecode/src/error.rs 5). A Copy-preserving shape exists — the static cause plus a u16 index plus the u8 tag found — so the successor does not need to break it", + "cargo test --all: 583 passed / 0 failed / 1 ignored on base 8c7b473f, unchanged — this round adds no code" + ], + "issues": [ + "Not stacking on #67's branch was a choice, not an oversight: #67 is not approved (its gate2 re-review is in flight), its head moves each round, and a PR based on it would be a child PR whose base can vanish on merge — the hazard gate3 contract 5 exists for.", + "This leaves the flat message in place on main until #67 lands. That is the cost of not duplicating: a user bisecting a rejected class file today still gets no cause at all, not even the rule." + ], + "adoptedProposals": ["2026-09-17-loadable-bootstrap-arguments#p0"], + "proposals": [ + { + "title": "Name the failing bootstrap argument's index and tag, on top of the cause threading", + "plainSummary": "Once the rejection says which rule failed, make the bootstrap-argument rule also say which argument number was wrong and what it actually pointed at.", + "userBenefit": "OpenJDK says 'argument_index 4 has bad constant type'. Naming the rule gets a reader to the right sentence; naming the index and the tag gets them to the right byte without bisecting the file.", + "why": "This is the measured residue of 2026-09-17-loadable-bootstrap-arguments#p0 after PR #67. That PR carries the cause as a &'static str, which cannot hold a runtime index, so the 'which one and what was it' half is still missing while the 'why' half is done. The predicate already knows the index at the moment it returns false and throws it away.", + "tradeoff": "ClassFileError derives Copy and four crates rely on it, so the payload has to stay Copy — static cause plus u16 index plus u8 tag, not a formatted String. And it must be sequenced after #67 rather than beside it: both touch the same enum and the same function, so doing them in parallel guarantees a conflict and duplicates the boundary rewrite.", + "effort": "S", + "target": "classfile/src/error.rs, classfile/src/validation.rs" + } + ] +} diff --git a/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md b/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md new file mode 100644 index 00000000..e521abbe --- /dev/null +++ b/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md @@ -0,0 +1,67 @@ +# 2026-09-18 — 「어느 bootstrap argument 가 왜 나빴나」 — ★**이 회차는 대전제 ⓒ 에서 끝난다** (rustjava-adopt-loadable-bootstrap-arguments-diagnostic) + +채택 제안 `2026-09-17-loadable-bootstrap-arguments#p0` 의 처분. ★**코드 0행**(`classfile/src/error.rs`·`validation.rs` **무접촉**). + +## 제안의 전제는 «참»이다 — 내가 실행으로 확인했다 + +읽어서가 아니라 **CLI 로 돌려서** 봤다(`main` @ `8c7b473f`): + +``` +rust_java -cp ./test-data/ldc LdcDynamicBSMArgPastEnd → java.lang.ClassFormatError: Invalid class file +rust_java -cp ./test-data/ldc LdcDynamicDuplicateBSM → java.lang.ClassFormatError: Invalid class file +rust_java -cp ./test-data/ldc LdcDynamicOldMajor → java.lang.ClassFormatError: Invalid class file +``` + +★**서로 다른 세 규칙**(나쁜 argument · 중복 속성 · 버전 게이트)이 **글자 하나 다르지 않은 같은 문장**을 낸다. +제안이 말한 「밋밋한 `Invalid class file`」은 정확한 서술이다. + +## ★그런데 대전제 ⓒ 가 «발화한다» — 이미 그 일을 하는 축이 «떠 있다» + +**PR #67**(`rustjava-adopt-classfile-error-cause-decision-p0` 리니지)이 **바로 그것**을 한다. +겹침이 «부분»이 아니라 «전부»다: + +| 축 | 제안 | PR #67 | +|---|---|---| +| `target` | `classfile/src/error.rs` · `classfile/src/validation.rs` | ★**정확히 그 둘**(merge-base 대비 `error.rs` **10/1** · `validation.rs` **61/27**) | +| 이 술어 | 「어느 argument 가 왜」를 말하게 하라 | ★**이미 사유를 준다** — `"a bootstrap method argument names nothing or is not a loadable constant"` | +| 밋밋한 문면 | 없애라 | ★**두 경계 자리**(`src/runtime.rs:189` · `test-utils/src/lib.rs:334`)를 **둘 다** 고쳤다 | + +★**제안 자신이 이것을 적어 두었다**: `tradeoff` 에 「The same follow-up is already proposed from the p2-fix round, +so the two should be done together rather than twice.」 ⇒ ★**제안이 «따로 하지 마라»고 말한 그 상황이 지금이다.** + +★**계약 2(문면을 match 하는 곳 전수 조회)도 같은 결론을 가리킨다**: `"Invalid class file"` 리터럴은 **두 곳**에 박혀 있고, +#67 이 그 둘을 이미 고쳤다. main 에서 시작하면 **같은 두 곳을 다시 고치고**, #67 회차가 이미 보고한 +「마지막 홉이 두 번 쓰여 있고 한 쪽만 테스트가 본다」는 **커버리지 구멍을 다시 발견**하게 된다. + +## ★남는 것은 «있다» — 다만 제안이 말한 것보다 좁다 + +★**`#67` 의 payload 는 `&'static str` 이라 «런타임 인덱스»를 «구조적으로» 담을 수 없다.** + +| 제안이 요구한 것 | #67 착지 후 | +|---|---| +| 「기대」(무엇이어야 했나) | ★**달성** — 규칙 문면이 그것을 말한다 | +| 「인덱스」(몇 번째 argument) | ★**미달** | +| 「실제」(실제로 무엇이 있었나) | ★**미달** | + +⇒ 그래서 **새 카드**를 좁혀서 냈다(`proposals[0]` · effort **S**) — 원 제안은 `adoptedProposals` 로 처분하고, +**남은 절반만** 정확한 범위로 다시 세운다. ★**그렇게 하지 않으면 카드가 사라지면서 잔여도 함께 사라진다.** + +## ★제안이 «적지 않은» 설계 제약 하나 — 후속이 다시 발견하지 않도록 + +`ClassFileError` 는 ★**`Copy` 를 derive 한다**. 인덱스를 담겠다고 `String` 을 넣으면 **`Copy` 가 깨지고** +그것은 네 크레이트의 소비자에게 전파된다(`classfile/tests/test.rs` **13** · `validation.rs` **8** · `class.rs` **7** · +`jvm-bytecode/src/error.rs` **5**). +★**깨지 않고도 된다**: 정적 사유 + `u16` 인덱스 + 발견된 `u8` 태그면 **셋 다 `Copy`** 다. 그 모양을 새 카드에 적었다. + +## 왜 #67 브랜치 «위에» 쌓지 않았나 — 선택이지 누락이 아니다 + +⑴#67 은 **아직 approve 가 아니다**(게이트② 재검이 진행 중) ⑵그 head 는 회차마다 **움직인다** +⑶그 위에 PR 을 내면 **자식 PR** 이 되고, ★**base 가 사라지면 자식이 자동으로 닫힌다**(게이트③ 계약 5 가 있는 이유). + +## 잃는 것 — 「없다」로 적지 않는다 + +- ★**main 은 #67 이 착지할 때까지 밋밋한 채로 남는다.** 오늘 거부된 클래스 파일을 든 사람은 + **규칙 이름조차** 못 받는다. 그것이 «중복하지 않기»의 대가이고, 숨기지 않는다. +- ★**이 회차는 제안의 값을 «전혀» 전달하지 않았다** — 전달한 것은 **순서**다. + 그 판단이 틀렸다면(예: #67 이 폐기되면) 이 회차는 **한 회차를 버린 것**이 된다. +- ★**「#67 이 착지하면 잔여가 정확히 둘」은 «오늘의 #67»** 기준이다. 그 PR 은 아직 움직이고 있다. From 151e8fb42fefe1570b967ce503f3dd82aef50f83 Mon Sep 17 00:00:00 2001 From: jun0 Date: Fri, 18 Sep 2026 09:59:47 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[rustjava-adopt-loadable-bootstrap-argument?= =?UTF-8?q?s-diagnostic-fix]=20docs:=20=EC=9E=94=EC=97=AC=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=EB=A5=BC=20=EC=8B=A4=EC=B8=A1=EC=97=90=20=EB=A7=9E?= =?UTF-8?q?=EC=B6=94=EA=B3=A0=20=E3=80=8C=EC=A0=84=EB=B6=80=20=EA=B2=B9?= =?UTF-8?q?=EC=B9=9C=EB=8B=A4=E3=80=8D=EB=A5=BC=20=EB=91=90=20=EC=B6=95?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EA=B0=80=EB=A5=B8=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 게이트② 반려 3건. 세 지적이 «한 뿌리»에서 나왔다 — 「겹침이 전부다」로 읽고 그 위에 S 를 얹었다. 코드 0행(이 회차는 대전제 ⓒ 로 «멈춘» 회차다 — 구현은 그 카드가 진다). ⑶ verification[1] 을 두 축으로 갈랐다: 편집 영역은 «전부» 겹치지만(target 두 파일을 #67 이 정확히 고친다) 전달된 값은 «3 중 1» 이다(기대만 · 인덱스·실제는 &'static str 이라 구조적으로 불가). 대전제 ⓒ 가 묻는 것은 후자이므로 「전부」는 축을 갈아탄 말이었다. ⑴ 카드를 실측에 맞췄다. 두 선택지를 각각 재서 골랐다: ⒝ 페이로드를 넓힌다 → 생성 17곳(validation 14 + class 3) + 값 매치 11곳 전건 ⒜ 새 variant → 생성 1곳 · 값 매치 0곳 강제 ⒜ 를 고르되 effort 는 S → M 으로 올렸다. 크기를 정하는 것은 편집 수가 아니라 «건너는 층»이고, 잔여도 #67 과 같은 3층을 건넌다(중간층 jvm-bytecode 도 &'static str · 경계 exception(&str) 이라 runtime.rs·test-utils 에서 포맷해야 한다) ⇒ target 5파일 / 3크레이트를 전부 적었다. ★원 제안이 «전체»를 M 으로 값했는데 «미전달된 절반»을 S 로 값하면 순서가 뒤집힌다. ⒜ 의 대가도 카드에 적었다 — 거부 오류가 두 갈래가 되고 이후 규칙마다 어느 쪽인지 답해야 한다. ⑵ 「네 크레이트」의 «명사»를 고쳤다(수 13·8·7·5 는 맞으니 무접촉). Cargo.toml 로 확인하니 classfile 3 + jvm-bytecode 1 = 파일 4 / 크레이트 2 이고, 루트 2건은 주석이다. 5곳 전부 고쳤다. cargo test --all 583/0/1(base 8c7b473f, 불변) · adoptedProposals 원 ref 유지 · #67 무접촉. --- REPORT.md | 6 ++-- STATE.md | 4 +-- ...tstrap-argument-diagnostic-sequencing.json | 20 +++++++------ ...ootstrap-argument-diagnostic-sequencing.md | 30 ++++++++++++++++--- 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/REPORT.md b/REPORT.md index 4b026213..7e2e6b4a 100644 --- a/REPORT.md +++ b/REPORT.md @@ -2,14 +2,14 @@ ## [2026-09-18] 「어느 bootstrap argument 가 왜 나빴나」 — ★**대전제 ⓒ 에서 끝난다: 그 일을 하는 축이 이미 떠 있다**(rustjava-adopt-loadable-bootstrap-arguments-diagnostic) - 무엇을: 채택 제안 `2026-09-17-loadable-bootstrap-arguments#p0` 의 처분(worklog json `adoptedProposals` 기록). ★**코드 0행** — `classfile/src/{error,validation}.rs` **무접촉**. - ★**제안의 전제는 참이다 — CLI 로 돌려서 봤다**(`main` @ `8c7b473f`): 서로 다른 세 규칙(`LdcDynamicBSMArgPastEnd` 나쁜 argument · `LdcDynamicDuplicateBSM` 중복 속성 · `LdcDynamicOldMajor` 버전 게이트)이 ★**글자 하나 다르지 않은 `java.lang.ClassFormatError: Invalid class file`** 를 낸다. -- ★★**그런데 겹침이 «부분»이 아니라 «전부»다** — **PR #67** 이 제안의 `target` **바로 그 두 파일**을 고치고(merge-base 대비 `error.rs` **10/1** · `validation.rs` **61/27**), ★**이 술어에 이미 사유를 준다**(`"a bootstrap method argument names nothing or is not a loadable constant"`), ★밋밋한 문면이 박힌 **두 경계 자리**(`src/runtime.rs:189`·`test-utils/src/lib.rs:334`)도 **둘 다** 고쳤다. ⇒ main 에서 시작하면 **같은 enum 을 세 번째로 고치고** 같은 커버리지 구멍을 다시 발견한다. +- ★★**겹침을 «두 축»으로 갈라야 한다**(초판은 「전부」로 뭉쳤고 ★그 낱말이 카드의 과소 산정을 낳았다): ★**편집 영역은 전부 겹친다** — **PR #67** 이 제안의 `target` **바로 그 두 파일**을 고치고(merge-base 대비 `error.rs` **10/1** · `validation.rs` **61/27**), ★**이 술어에 이미 사유를 준다**(`"a bootstrap method argument names nothing or is not a loadable constant"`), ★밋밋한 문면이 박힌 **두 경계 자리**(`src/runtime.rs:189`·`test-utils/src/lib.rs:334`)도 **둘 다** 고쳤다. ⇒ main 에서 시작하면 **같은 enum 을 세 번째로 고치고** 같은 커버리지 구멍을 다시 발견한다. ★**제안 자신이 그렇게 적어 두었다** — `tradeoff`: 「the two should be done together rather than twice」. - ★**남는 것은 있다 · 다만 좁다**: `#67` 의 payload 는 **`&'static str`** 이라 ★**런타임 인덱스를 구조적으로 못 담는다** ⇒ 「기대」는 **달성**, 「인덱스」·「실제」는 **미달**. ⇒ ★**새 카드를 좁혀 냈다**(effort **S**) — 원 제안은 처분하고 잔여만 정확한 범위로 다시 세운다(안 그러면 카드와 함께 잔여도 사라진다). -- ★**제안이 적지 않은 설계 제약**: `ClassFileError` 는 **`Copy`** 이고 네 크레이트가 그것에 기댄다(`tests/test.rs` 13 · `validation.rs` 8 · `class.rs` 7 · `jvm-bytecode/src/error.rs` 5). ★**깨지 않고도 된다** — 정적 사유 + `u16` 인덱스 + `u8` 태그면 셋 다 `Copy`. 후속이 다시 발견하지 않도록 새 카드에 적었다. +- ★**제안이 적지 않은 설계 제약**: `ClassFileError` 는 **`Copy`** 이고 ★**파일 4 · 크레이트 «2»**(`classfile` 3 + `jvm-bytecode` 1)가 그것을 쓴다 — ★초판의 「네 크레이트」는 **명사가 틀렸다**(수는 맞다 · 루트 2건은 **주석**이다)(`tests/test.rs` 13 · `validation.rs` 8 · `class.rs` 7 · `jvm-bytecode/src/error.rs` 5). ★**깨지 않고도 된다** — 정적 사유 + `u16` 인덱스 + `u8` 태그면 셋 다 `Copy`. 후속이 다시 발견하지 않도록 새 카드에 적었다. - ★**#67 위에 쌓지 않은 이유**(선택이지 누락 아님): ⑴아직 approve 아님(게이트② 재검 중) ⑵head 가 회차마다 움직임 ⑶**자식 PR** 이 되어 base 소멸 시 자동으로 닫힌다(게이트③ 계약 5). - ★**잃는 것**: ★**main 은 #67 착지까지 밋밋한 채로 남는다**(오늘 사용자는 **규칙 이름조차** 못 받는다) · 이 회차는 제안의 값을 **전혀 전달하지 않았고** 전달한 것은 **순서**다 · #67 이 폐기되면 이 판단은 **한 회차를 버린 것**이 된다. - 검증: `cargo test --all` **583 passed / 0 failed / 1 ignored**(불변 — 코드 무접촉 · base `8c7b473f`) · `check-dod-ci-parity` → **「OK 두 축 모두 대칭차 0 — 명령 6개 · toolchain 2개로 «둘 다 일치»」**. -- ★후속 추천: 새 카드 「bootstrap argument 의 인덱스와 태그를 사유 위에 얹는다」(S) — ★**#67 «뒤»에** · 상세 = `docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md`. +- ★후속 추천: 새 카드 「**구조화된 variant 로** bootstrap argument 의 인덱스와 태그를 말한다」(★**M** · ★초판은 `S` 였다 — **실측 후 올렸다**: 잔여도 #67 과 **같은 3층**을 건넌다(중간층 `jvm-bytecode` 도 `&'static str` · 경계는 `&str`) ⇒ `target` **5파일 / 3크레이트**. ★`InvalidFormat` 을 넓히면 생성 **17**곳 + 값 매치 **11**곳이라 **새 variant** 를 고르되 ★**두 갈래가 생기는 대가**를 카드에 적었다) — ★**#67 «뒤»에** · 상세 = `docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md`. ## [2026-09-17] 코드 2파일 합집합 — ★**그런데 ours 의 «삭제»는 의도가 아니라 선행 머지의 «조용한 롤백»이었다** (rustjava-adopt-link-stringconcatfactory-p2-fix3) - 무엇을: 게이트③이 `code-conflict-out-of-scope` 로 세운 PR #61 의 충돌 4파일(원장 2 + 코드 2)을 합집합으로 해소. ★제품 Rust **0줄**(테스트·픽스처 생성기만). diff --git a/STATE.md b/STATE.md index 125055ef..23b12039 100644 --- a/STATE.md +++ b/STATE.md @@ -8,8 +8,8 @@ ## 완료 - [rustjava-adopt-loadable-bootstrap-arguments-diagnostic] ★★**대전제 ⓒ 에서 끝났다 — 그 일을 하는 축(PR #67)이 이미 떠 있다.** 채택 제안 `2026-09-17-loadable-bootstrap-arguments#p0`(worklog json 기록). ★**코드 0행.** - ★**전제는 참**(CLI 실행: 세 규칙이 전부 `ClassFormatError: Invalid class file` 동일 문면) — 그러나 ★**겹침이 전부다**: #67 이 제안 `target` 두 파일을 고치고, 이 술어에 **이미 사유를 주며**, 밋밋한 문면 **두 자리**를 둘 다 고쳤다. ★제안 `tradeoff` 자신이 「두 번 하지 말고 함께 하라」고 적었다. - ★**남는 잔여는 좁다** — `&'static str` 이라 **인덱스를 못 담는다** ⇒ 「기대」 달성 · 「인덱스·실제」 미달 ⇒ ★**새 카드를 좁혀 냈다**(S). + ★**전제는 참**(CLI 실행: 세 규칙이 전부 `ClassFormatError: Invalid class file` 동일 문면) — 그러나 ★**편집 영역은 전부 겹친다**(전달된 값은 **3 중 1** — 아래): #67 이 제안 `target` 두 파일을 고치고, 이 술어에 **이미 사유를 주며**, 밋밋한 문면 **두 자리**를 둘 다 고쳤다. ★제안 `tradeoff` 자신이 「두 번 하지 말고 함께 하라」고 적었다. + ★**남는 잔여는 좁다** — `&'static str` 이라 **인덱스를 못 담는다** ⇒ 「기대」 달성 · 「인덱스·실제」 미달 ⇒ ★**새 카드를 냈다**(★**M** — 초판 `S` 에서 **실측 후 올렸다**: 잔여도 **같은 3층**을 건너 `target` **5파일/3크레이트** · `InvalidFormat` 을 넓히면 생성 17 + 매치 11 이라 **새 variant** 를 고르고 **두 갈래의 대가**를 적었다). ★**설계 제약 기록** — `ClassFileError` 는 `Copy`(4크레이트 의존) · 정적사유+`u16`+`u8` 로 **깨지 않고 된다**. ★**잃는 것**: main 은 #67 착지까지 **밋밋한 채**(규칙 이름조차 없다) · 이 회차가 전달한 것은 **값이 아니라 순서**다. ★`--all` **583/0/1**(불변 · base `8c7b473f`). diff --git a/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.json b/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.json index aa422b09..79cbb77f 100644 --- a/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.json +++ b/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.json @@ -8,26 +8,28 @@ ], "verification": [ "PREMISE CONFIRMED on main @ 8c7b473f, measured by running the CLI rather than by reading: three different rules all print the identical message. `rust_java -cp ./test-data/ldc LdcDynamicBSMArgPastEnd` (bad bootstrap argument), `LdcDynamicDuplicateBSM` (duplicate attribute) and `LdcDynamicOldMajor` (version gate) each answer `java.lang.ClassFormatError: Invalid class file`", - "OVERLAP IS TOTAL: the proposal's target is classfile/src/error.rs and classfile/src/validation.rs; PR #67 changes error.rs 10/1 and validation.rs 61/27 against their merge base. #67 already gives this exact predicate the cause 'a bootstrap method argument names nothing or is not a loadable constant'", + "OVERLAP, split into the two axes it was conflating. By EDIT AREA it is total: this proposal's target is classfile/src/error.rs and classfile/src/validation.rs, and PR #67 changes exactly those two (error.rs 10/1, validation.rs 61/27 against their merge base), already gives this predicate the cause 'a bootstrap method argument names nothing or is not a loadable constant', and already rewrites both boundary sites that hardcode 'Invalid class file'. By DELIVERED CAPABILITY — which is what precondition (c) actually asks — it is 1 of 3: the proposal wants expected, index and actual, and #67's &'static str payload supplies the expectation only. An earlier draft wrote 'OVERLAP IS TOTAL' unqualified, which contradicted the residue entry three lines down and is the same word that produced the under-sized effort on the card.", "CONTRACT 2 SWEEP: the literal 'Invalid class file' is hardcoded at two boundary sites, src/runtime.rs:189 and test-utils/src/lib.rs:334. #67 rewrites both; a round starting from main would have to change both again and would hit the same test-coverage gap #67's round already reported", "RESIDUE IS REAL BUT NARROWER: #67's payload is &'static str, which structurally cannot carry a runtime index. So after #67 lands the proposal's 'expected' is delivered by the rule wording and its 'index' and 'actual' are not", - "DESIGN CONSTRAINT the proposal does not name: ClassFileError derives Copy. Carrying an owned String would drop Copy for every consumer (classfile/tests/test.rs 13 uses, validation.rs 8, class.rs 7, jvm-bytecode/src/error.rs 5). A Copy-preserving shape exists — the static cause plus a u16 index plus the u8 tag found — so the successor does not need to break it", + "DESIGN CONSTRAINT the proposal does not name: ClassFileError derives Copy. Carrying an owned String would drop Copy for every consumer. Counted at 8c7b473f with git grep -c: classfile/tests/test.rs 13, classfile/src/validation.rs 8, classfile/src/class.rs 7, jvm-bytecode/src/error.rs 5 — that is 4 FILES across 2 CRATES (classfile three, jvm-bytecode one), not four crates as an earlier draft said; the two further hits under tests/ are comments, not code. A Copy-preserving shape exists — the static cause plus a u16 index plus the u8 tag found — so the successor does not need to break it.", "cargo test --all: 583 passed / 0 failed / 1 ignored on base 8c7b473f, unchanged — this round adds no code" ], "issues": [ "Not stacking on #67's branch was a choice, not an oversight: #67 is not approved (its gate2 re-review is in flight), its head moves each round, and a PR based on it would be a child PR whose base can vanish on merge — the hazard gate3 contract 5 exists for.", "This leaves the flat message in place on main until #67 lands. That is the cost of not duplicating: a user bisecting a rejected class file today still gets no cause at all, not even the rule." ], - "adoptedProposals": ["2026-09-17-loadable-bootstrap-arguments#p0"], + "adoptedProposals": [ + "2026-09-17-loadable-bootstrap-arguments#p0" + ], "proposals": [ { - "title": "Name the failing bootstrap argument's index and tag, on top of the cause threading", - "plainSummary": "Once the rejection says which rule failed, make the bootstrap-argument rule also say which argument number was wrong and what it actually pointed at.", + "title": "Add a structured variant that names the failing bootstrap argument's index and tag", + "plainSummary": "Once the rejection says which rule failed, give that one rule a richer error that also carries which argument number was wrong and what it actually pointed at.", "userBenefit": "OpenJDK says 'argument_index 4 has bad constant type'. Naming the rule gets a reader to the right sentence; naming the index and the tag gets them to the right byte without bisecting the file.", - "why": "This is the measured residue of 2026-09-17-loadable-bootstrap-arguments#p0 after PR #67. That PR carries the cause as a &'static str, which cannot hold a runtime index, so the 'which one and what was it' half is still missing while the 'why' half is done. The predicate already knows the index at the moment it returns false and throws it away.", - "tradeoff": "ClassFileError derives Copy and four crates rely on it, so the payload has to stay Copy — static cause plus u16 index plus u8 tag, not a formatted String. And it must be sequenced after #67 rather than beside it: both touch the same enum and the same function, so doing them in parallel guarantees a conflict and duplicates the boundary rewrite.", - "effort": "S", - "target": "classfile/src/error.rs, classfile/src/validation.rs" + "why": "This is the measured residue of 2026-09-17-loadable-bootstrap-arguments#p0 after PR #67. That PR carries the cause as a &'static str, which cannot hold a runtime index, so of the proposal's three asks — expected, index, actual — it delivers the first and not the other two. The predicate already knows the index at the moment it returns false and throws it away.", + "tradeoff": "Measured rather than estimated, against #67's tree. Widening InvalidFormat's payload would touch 17 construction sites (validation.rs 14, class.rs 3) and force all 11 value matches in classfile/tests/test.rs to change. Adding a separate variant instead touches one construction site and forces none of the 11, so that is the shape proposed — but it leaves TWO KINDS of rejection error side by side, and 'why is this one structured and that one a bare string' becomes a standing question every later rule has to answer. Either way the work crosses the same three layers, because the middle layer (jvm-bytecode ClassDefinitionError::InvalidClassFile) is also &'static str and the boundary (jvm exception(&str)) takes a plain string, so the text has to be formatted at src/runtime.rs and test-utils/src/lib.rs. ClassFileError also derives Copy and 4 files across 2 crates use it, so the payload must stay Copy: static cause plus u16 index plus u8 tag. And it must be sequenced after #67, not beside it — both touch the same enum and function.", + "effort": "M", + "target": "classfile/src/error.rs, classfile/src/validation.rs, jvm-bytecode/src/error.rs, src/runtime.rs, test-utils/src/lib.rs" } ] } diff --git a/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md b/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md index e521abbe..b1b8c278 100644 --- a/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md +++ b/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md @@ -18,7 +18,10 @@ rust_java -cp ./test-data/ldc LdcDynamicOldMajor → java.lang.ClassForma ## ★그런데 대전제 ⓒ 가 «발화한다» — 이미 그 일을 하는 축이 «떠 있다» **PR #67**(`rustjava-adopt-classfile-error-cause-decision-p0` 리니지)이 **바로 그것**을 한다. -겹침이 «부분»이 아니라 «전부»다: +★**두 축으로 갈라 읽어야 한다** — ⒜**편집 영역**은 «전부» 겹치고 ⒝**전달된 값**은 «3 중 1» 이다. +★초판은 이것을 「전부」로 뭉쳤고, ★**그 낱말이 카드를 `S` 로 과소 산정하게 만들었다**(둘은 같은 뿌리다). + +**⒜ 편집 영역 — 전부 겹친다:** | 축 | 제안 | PR #67 | |---|---|---| @@ -33,7 +36,7 @@ so the two should be done together rather than twice.」 ⇒ ★**제안이 « #67 이 그 둘을 이미 고쳤다. main 에서 시작하면 **같은 두 곳을 다시 고치고**, #67 회차가 이미 보고한 「마지막 홉이 두 번 쓰여 있고 한 쪽만 테스트가 본다」는 **커버리지 구멍을 다시 발견**하게 된다. -## ★남는 것은 «있다» — 다만 제안이 말한 것보다 좁다 +## ⒝ 전달된 값 — ★**3 중 1** (= 남는 것은 «있다») ★**`#67` 의 payload 는 `&'static str` 이라 «런타임 인덱스»를 «구조적으로» 담을 수 없다.** @@ -43,13 +46,32 @@ so the two should be done together rather than twice.」 ⇒ ★**제안이 « | 「인덱스」(몇 번째 argument) | ★**미달** | | 「실제」(실제로 무엇이 있었나) | ★**미달** | -⇒ 그래서 **새 카드**를 좁혀서 냈다(`proposals[0]` · effort **S**) — 원 제안은 `adoptedProposals` 로 처분하고, +⇒ 그래서 **새 카드**를 냈다(`proposals[0]` · effort ★**M**) — 원 제안은 `adoptedProposals` 로 처분하고, **남은 절반만** 정확한 범위로 다시 세운다. ★**그렇게 하지 않으면 카드가 사라지면서 잔여도 함께 사라진다.** +## ★카드를 `S` → `M` 으로 올렸다 — 두 선택지를 «재고» 골랐다 + +★**초판의 `S` 는 «편집 영역이 전부 겹친다»를 «남은 일도 작다»로 읽은 결과**였다. 재보니 반대다 — +★**잔여도 #67 과 «같은 3층»을 건넌다**: 중간층 `jvm-bytecode/src/error.rs:5` 가 **`InvalidClassFile(&'static str)`** 이고 +경계 `jvm/src/jvm.rs` 의 `exception(&str)` 이 **평범한 문자열**을 받으므로, 「argument_index 4 …」는 +`src/runtime.rs:189`·`test-utils/src/lib.rs:334` 에서 **포맷**되어야 한다. + +| 선택지 | 생성 자리 | 값 매치(`classfile/tests/test.rs`) | 층 | 판정 | +|---|---|---|---|---| +| ⒝ `InvalidFormat` 페이로드를 **넓힌다** | `validation.rs` **14** + `class.rs` **3** = **17곳** | **11곳 전건** | 3 | 편집 ≈30+ | +| ★⒜ **새 variant** | ★**1곳**(그 규칙만) | ★**0곳 강제** | 3 | 편집 ≈6 | + +⇒ ★**⒜ 를 골랐다**(편집이 1/5 이고 기존 단정 11 을 건드리지 않는다). ★**그래도 `M` 이다** — 크기를 정하는 것은 +**편집 수가 아니라 «건너는 층»** 이고, 잔여는 **5파일 / 3크레이트**를 건넌다. +★★**원 제안이 «전체»를 `M` 으로 값했는데 «미전달된 절반»을 `S` 로 값하면 순서가 뒤집힌다** — 그 역전을 되돌린 것이다. + +★**⒜ 의 대가**(카드 `tradeoff` 에도 적었다): ★**거부 오류가 «두 갈래»가 된다** — `InvalidFormat(&'static str)` 과 +구조화된 variant 가 나란히 서고, 「왜 이건 구조화고 저건 맨 문자열인가」를 **이후 규칙마다** 답해야 한다. + ## ★제안이 «적지 않은» 설계 제약 하나 — 후속이 다시 발견하지 않도록 `ClassFileError` 는 ★**`Copy` 를 derive 한다**. 인덱스를 담겠다고 `String` 을 넣으면 **`Copy` 가 깨지고** -그것은 네 크레이트의 소비자에게 전파된다(`classfile/tests/test.rs` **13** · `validation.rs` **8** · `class.rs` **7** · +그것은 그 소비자에게 전파된다 — ★**파일 4 · 크레이트 «2»**(`classfile` 3 + `jvm-bytecode` 1 · ★초판의 「네 크레이트」는 명사가 틀렸다 · 수는 맞다 · 루트 2건은 **주석**)(`classfile/tests/test.rs` **13** · `validation.rs` **8** · `class.rs` **7** · `jvm-bytecode/src/error.rs` **5**). ★**깨지 않고도 된다**: 정적 사유 + `u16` 인덱스 + 발견된 `u8` 태그면 **셋 다 `Copy`** 다. 그 모양을 새 카드에 적었다. From edadc2d22eb98f389ce473a20917d11feeeddf23 Mon Sep 17 00:00:00 2001 From: jun0 Date: Fri, 18 Sep 2026 12:40:26 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[rustjava-adopt-loadable-bootstrap-argument?= =?UTF-8?q?s-diagnostic-fix2]=20docs:=20=E3=80=8C=EC=B8=B5=203=E3=80=8D?= =?UTF-8?q?=EC=9D=84=20=E3=80=8C=ED=81=AC=EB=A0=88=EC=9D=B4=ED=8A=B8=203?= =?UTF-8?q?=E3=80=8D=EC=9C=BC=EB=A1=9C=20=EC=98=AE=EA=B2=A8=20=EC=A0=81?= =?UTF-8?q?=EC=9D=80=20=EC=B9=B8=EC=9D=84=204=EB=A1=9C=20=EA=B3=A0?= =?UTF-8?q?=EC=B9=98=EA=B3=A0=20STATE=20=EC=9D=98=20=EC=9E=94=EC=A1=B4=20?= =?UTF-8?q?=EC=A3=BC=EC=9E=A5=EC=9D=84=20=EC=A7=80=EC=9A=B4=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- REPORT.md | 2 +- STATE.md | 4 ++-- ...2026-09-18-bootstrap-argument-diagnostic-sequencing.json | 2 +- .../2026-09-18-bootstrap-argument-diagnostic-sequencing.md | 6 +++++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/REPORT.md b/REPORT.md index 7e2e6b4a..0324adfa 100644 --- a/REPORT.md +++ b/REPORT.md @@ -9,7 +9,7 @@ - ★**#67 위에 쌓지 않은 이유**(선택이지 누락 아님): ⑴아직 approve 아님(게이트② 재검 중) ⑵head 가 회차마다 움직임 ⑶**자식 PR** 이 되어 base 소멸 시 자동으로 닫힌다(게이트③ 계약 5). - ★**잃는 것**: ★**main 은 #67 착지까지 밋밋한 채로 남는다**(오늘 사용자는 **규칙 이름조차** 못 받는다) · 이 회차는 제안의 값을 **전혀 전달하지 않았고** 전달한 것은 **순서**다 · #67 이 폐기되면 이 판단은 **한 회차를 버린 것**이 된다. - 검증: `cargo test --all` **583 passed / 0 failed / 1 ignored**(불변 — 코드 무접촉 · base `8c7b473f`) · `check-dod-ci-parity` → **「OK 두 축 모두 대칭차 0 — 명령 6개 · toolchain 2개로 «둘 다 일치»」**. -- ★후속 추천: 새 카드 「**구조화된 variant 로** bootstrap argument 의 인덱스와 태그를 말한다」(★**M** · ★초판은 `S` 였다 — **실측 후 올렸다**: 잔여도 #67 과 **같은 3층**을 건넌다(중간층 `jvm-bytecode` 도 `&'static str` · 경계는 `&str`) ⇒ `target` **5파일 / 3크레이트**. ★`InvalidFormat` 을 넓히면 생성 **17**곳 + 값 매치 **11**곳이라 **새 variant** 를 고르되 ★**두 갈래가 생기는 대가**를 카드에 적었다) — ★**#67 «뒤»에** · 상세 = `docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md`. +- ★후속 추천: 새 카드 「**구조화된 variant 로** bootstrap argument 의 인덱스와 태그를 말한다」(★**M** · ★초판은 `S` 였다 — **실측 후 올렸다**: 잔여도 #67 과 **같은 3층**을 건넌다(중간층 `jvm-bytecode` 도 `&'static str` · 경계는 `&str`) ⇒ `target` **5파일 / 4크레이트**(`classfile`·`jvm-bytecode`·`RustJava`·`test-utils` — ★**층은 3인데 크레이트는 4다**: 경계 층 하나가 두 크레이트에 걸친다). ★`InvalidFormat` 을 넓히면 생성 **17**곳 + 값 매치 **11**곳이라 **새 variant** 를 고르되 ★**두 갈래가 생기는 대가**를 카드에 적었다) — ★**#67 «뒤»에** · 상세 = `docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md`. ## [2026-09-17] 코드 2파일 합집합 — ★**그런데 ours 의 «삭제»는 의도가 아니라 선행 머지의 «조용한 롤백»이었다** (rustjava-adopt-link-stringconcatfactory-p2-fix3) - 무엇을: 게이트③이 `code-conflict-out-of-scope` 로 세운 PR #61 의 충돌 4파일(원장 2 + 코드 2)을 합집합으로 해소. ★제품 Rust **0줄**(테스트·픽스처 생성기만). diff --git a/STATE.md b/STATE.md index 23b12039..90921551 100644 --- a/STATE.md +++ b/STATE.md @@ -9,8 +9,8 @@ ## 완료 - [rustjava-adopt-loadable-bootstrap-arguments-diagnostic] ★★**대전제 ⓒ 에서 끝났다 — 그 일을 하는 축(PR #67)이 이미 떠 있다.** 채택 제안 `2026-09-17-loadable-bootstrap-arguments#p0`(worklog json 기록). ★**코드 0행.** ★**전제는 참**(CLI 실행: 세 규칙이 전부 `ClassFormatError: Invalid class file` 동일 문면) — 그러나 ★**편집 영역은 전부 겹친다**(전달된 값은 **3 중 1** — 아래): #67 이 제안 `target` 두 파일을 고치고, 이 술어에 **이미 사유를 주며**, 밋밋한 문면 **두 자리**를 둘 다 고쳤다. ★제안 `tradeoff` 자신이 「두 번 하지 말고 함께 하라」고 적었다. - ★**남는 잔여는 좁다** — `&'static str` 이라 **인덱스를 못 담는다** ⇒ 「기대」 달성 · 「인덱스·실제」 미달 ⇒ ★**새 카드를 냈다**(★**M** — 초판 `S` 에서 **실측 후 올렸다**: 잔여도 **같은 3층**을 건너 `target` **5파일/3크레이트** · `InvalidFormat` 을 넓히면 생성 17 + 매치 11 이라 **새 variant** 를 고르고 **두 갈래의 대가**를 적었다). - ★**설계 제약 기록** — `ClassFileError` 는 `Copy`(4크레이트 의존) · 정적사유+`u16`+`u8` 로 **깨지 않고 된다**. + ★**남는 잔여는 좁다** — `&'static str` 이라 **인덱스를 못 담는다** ⇒ 「기대」 달성 · 「인덱스·실제」 미달 ⇒ ★**새 카드를 냈다**(★**M** — 초판 `S` 에서 **실측 후 올렸다**: 잔여도 **같은 3층**을 건너 `target` **5파일/4크레이트**(`classfile`·`jvm-bytecode`·`RustJava`·`test-utils` — ★층 3 ↔ 크레이트 4: 경계 층이 두 크레이트에 걸친다) · `InvalidFormat` 을 넓히면 생성 17 + 매치 11 이라 **새 variant** 를 고르고 **두 갈래의 대가**를 적었다). + ★**설계 제약 기록** — `ClassFileError` 는 `Copy`(파일 4 · 크레이트 2 의존) · 정적사유+`u16`+`u8` 로 **깨지 않고 된다**. ★**잃는 것**: main 은 #67 착지까지 **밋밋한 채**(규칙 이름조차 없다) · 이 회차가 전달한 것은 **값이 아니라 순서**다. ★`--all` **583/0/1**(불변 · base `8c7b473f`). - [rustjava-adopt-link-stringconcatfactory-p2-fix2] ★★**#57 의 버전 표에 25행 등재 — 「착지 순서」가 만든 부채를 갚는다(PR #61).** diff --git a/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.json b/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.json index 79cbb77f..cd6fa96e 100644 --- a/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.json +++ b/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.json @@ -27,7 +27,7 @@ "plainSummary": "Once the rejection says which rule failed, give that one rule a richer error that also carries which argument number was wrong and what it actually pointed at.", "userBenefit": "OpenJDK says 'argument_index 4 has bad constant type'. Naming the rule gets a reader to the right sentence; naming the index and the tag gets them to the right byte without bisecting the file.", "why": "This is the measured residue of 2026-09-17-loadable-bootstrap-arguments#p0 after PR #67. That PR carries the cause as a &'static str, which cannot hold a runtime index, so of the proposal's three asks — expected, index, actual — it delivers the first and not the other two. The predicate already knows the index at the moment it returns false and throws it away.", - "tradeoff": "Measured rather than estimated, against #67's tree. Widening InvalidFormat's payload would touch 17 construction sites (validation.rs 14, class.rs 3) and force all 11 value matches in classfile/tests/test.rs to change. Adding a separate variant instead touches one construction site and forces none of the 11, so that is the shape proposed — but it leaves TWO KINDS of rejection error side by side, and 'why is this one structured and that one a bare string' becomes a standing question every later rule has to answer. Either way the work crosses the same three layers, because the middle layer (jvm-bytecode ClassDefinitionError::InvalidClassFile) is also &'static str and the boundary (jvm exception(&str)) takes a plain string, so the text has to be formatted at src/runtime.rs and test-utils/src/lib.rs. ClassFileError also derives Copy and 4 files across 2 crates use it, so the payload must stay Copy: static cause plus u16 index plus u8 tag. And it must be sequenced after #67, not beside it — both touch the same enum and function.", + "tradeoff": "Measured rather than estimated, against #67's tree @56bb54fa. Widening InvalidFormat's payload would touch 17 construction sites (validation.rs 14, class.rs 3) and force all 11 value matches in classfile/tests/test.rs to change. Adding a separate variant instead touches one construction site and forces none of the 11, so that is the shape proposed — but it leaves TWO KINDS of rejection error side by side, and 'why is this one structured and that one a bare string' becomes a standing question every later rule has to answer. Either way the work crosses the same three layers, because the middle layer (jvm-bytecode ClassDefinitionError::InvalidClassFile) is also &'static str and the boundary (jvm exception(&str)) takes a plain string, so the text has to be formatted at src/runtime.rs and test-utils/src/lib.rs. ClassFileError also derives Copy and 4 files across 2 crates use it, so the payload must stay Copy: static cause plus u16 index plus u8 tag. And it must be sequenced after #67, not beside it — both touch the same enum and function.", "effort": "M", "target": "classfile/src/error.rs, classfile/src/validation.rs, jvm-bytecode/src/error.rs, src/runtime.rs, test-utils/src/lib.rs" } diff --git a/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md b/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md index b1b8c278..511683bb 100644 --- a/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md +++ b/docs/worklog/2026-09-18-bootstrap-argument-diagnostic-sequencing.md @@ -62,7 +62,9 @@ so the two should be done together rather than twice.」 ⇒ ★**제안이 « | ★⒜ **새 variant** | ★**1곳**(그 규칙만) | ★**0곳 강제** | 3 | 편집 ≈6 | ⇒ ★**⒜ 를 골랐다**(편집이 1/5 이고 기존 단정 11 을 건드리지 않는다). ★**그래도 `M` 이다** — 크기를 정하는 것은 -**편집 수가 아니라 «건너는 층»** 이고, 잔여는 **5파일 / 3크레이트**를 건넌다. +**편집 수가 아니라 «건너는 층»** 이고, 잔여는 **5파일 / 4크레이트**(`classfile`·`jvm-bytecode`·`RustJava`·`test-utils`)를 건넌다. +★**층은 3인데 크레이트는 4다 — 둘을 같은 수로 적지 마라**: 경계 층 하나가 `RustJava`(`src/runtime.rs`)와 +`test-utils`(`test-utils/src/lib.rs`) **두 크레이트**에 걸친다(`cargo metadata --no-deps` 귀속). 이 사실은 `M` 의 근거를 **강화한다**. ★★**원 제안이 «전체»를 `M` 으로 값했는데 «미전달된 절반»을 `S` 로 값하면 순서가 뒤집힌다** — 그 역전을 되돌린 것이다. ★**⒜ 의 대가**(카드 `tradeoff` 에도 적었다): ★**거부 오류가 «두 갈래»가 된다** — `InvalidFormat(&'static str)` 과 @@ -87,3 +89,5 @@ so the two should be done together rather than twice.」 ⇒ ★**제안이 « - ★**이 회차는 제안의 값을 «전혀» 전달하지 않았다** — 전달한 것은 **순서**다. 그 판단이 틀렸다면(예: #67 이 폐기되면) 이 회차는 **한 회차를 버린 것**이 된다. - ★**「#67 이 착지하면 잔여가 정확히 둘」은 «오늘의 #67»** 기준이다. 그 PR 은 아직 움직이고 있다. +- ★**`S` 에서 `M` 으로 올린 대가 — 카드가 뒤로 밀린다.** 실측이 올린 값이라 되돌리지 않지만, + `S` 였다면 먼저 집혔을 자리에서 내려가고 그만큼 열린 카드가 는다. 그 손실을 여기 적는다.