Skip to content

Commit 82d8423

Browse files
authored
Merge pull request #100 from Jun025/chore/checker-offspring-orphan-cleanup
[rustjava-checker-offspring-and-orphan-artefacts-cleanup] chore: 09-18 채택분의 호출자 없는 산출물 정리
2 parents fc04897 + 947fe90 commit 82d8423

8 files changed

Lines changed: 133 additions & 314 deletions

File tree

‎AGENTS.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ done | /usr/bin/grep -c .
173173
- Test JVM and interpreter semantics, including class initialization, bytecode execution, and monitor behavior, with compiled Java fixtures under `test-data/src` and expected output under `test-data`, executed by `tests/test_class.rs`.
174174
- Do not place JVM core behavior tests in the `rustjava-runtime` standard library test tree.
175175
- **Adding or recompiling a fixture means editing `test-data/class-file-versions.txt` in the same commit.** Every committed `.class` has its version frozen there, and a fixture that is not listed fails the pin — deliberately, since a pin that only covers what it already knows about stops covering anything added later. Run `python3 test-data/src/record-class-file-versions.py` and commit the row next to the fixture; a moved version means look at why before re-recording.
176+
- **Regenerating a hand-assembled fixture** (`test-data/src/{cp,indy,ldc}/make_*_fixtures.py`) — also run `python3 test-data/src/audit-fixture-single-defect.py` (no JDK, under a second; rc=0 = each fixture is broken in exactly its named way). It is manual like `test-data/src/verify-javac-fixtures.sh`: CI does not run it.
176177

177178
## Compatibility Sources
178179
- Implement Java compatibility from public specifications, Javadocs, and observable behavior tests. Do not consult or reproduce OpenJDK or other Java runtime implementation source code; keep the implementation independent to avoid licensing and provenance concerns.

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

Lines changed: 0 additions & 125 deletions
This file was deleted.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
## [2026-09-25] 09-18 채택분이 남긴 호출자 없는 산출물 정리 (rustjava-checker-offspring-and-orphan-artefacts-cleanup)
2+
- 무엇을: `scripts/ldc-tag-survey-targets/`(Kotlin·Scala 85줄)와 그 조사 블록을 지웠다. `docs/test-data-target-policy.md` 의 결정 논거는 `test-data/class-file-versions.txt` 머리로 접고 문서를 지웠다. `audit-fixture-single-defect.py` 를 `AGENTS.md` 의 픽스처 재생성 절차에 1줄로 올렸다. `check-merge-dropped-symbols.py` docstring 을 검사 내용·trailer 규칙·종료 코드만 남겨 84줄에서 38줄로 줄였고, 측정 이력은 아래로 옮겼다.
3+
- 왜: 셋 다 CI·테스트·DoD 어디에서도 부르지 않았다. 정책 문서는 들어오는 참조가 0이었고 같은 논거가 두 곳에 있었다. 검사기 docstring 은 측정 서술이라 09-18 반려 4회 중 3회가 그 수치 정정이었다.
4+
- 사용자 영향: 없음. 검사 로직·CI 잡은 건드리지 않았다. 감사 스크립트는 JDK 없이 0.8초에 rc=0(검사 18 · 결함 없음 5)이라 지우지 않고 수동 경로에 올렸다.
5+
6+
열린 카드 2장(`2026-09-18-root-fixture-target-decision#p0`·`#p1`)의 `target` 이 지운 `docs/test-data-target-policy.md` 를 가리킨다. 그 결정·재개 조건은 이제 `test-data/class-file-versions.txt` 머리에 있다. 카드 처분은 이 회차 범위가 아니라 그대로 둔다.
7+
8+
### `check-merge-dropped-symbols.py` 에서 옮긴 측정 이력 (원문 그대로)
9+
10+
```text
11+
Report definitions that were in the branch a merge pulled from, and are not in its result.
12+
13+
What this answers: *did a conflict resolution silently drop one side's work*. That failure is
14+
invisible to everything else we have, which is why it exists. Measured 2026-09-18 by reconstructing
15+
the loss on `origin/main` and running every axis against it: the generator ran (rc=0), the
16+
single-defect auditor passed (23 checks, rc=0), `test_class_format` passed (21), `test_fixture_pins`
17+
passed (3), `check-dod-ci-parity` passed, `git status` was empty and there was no conflict marker.
18+
Nothing went red. The only signal was counting names by hand, which is what this does instead.
19+
20+
The real incident: two merges on one PR branch (e53b2142, 514d5b08) each dropped four definitions
21+
that came from the branch being merged in -- `Pool.fieldref`, `MAKECONCAT_DESCRIPTOR`,
22+
`make_concat_call_site` and the `LINKED` table. The suite stayed green because the fixtures those
23+
build are committed bytes, so when the generator lost the code the expected output did not move.
24+
25+
Why it is silent, precisely: the loss is invisible exactly when the dropped names are *consistent
26+
with each other*. Dropping a slice that something else still calls raises AttributeError and gets
27+
noticed; dropping a whole feature -- which is what taking one side of a conflict does -- leaves a
28+
file that parses, runs and agrees with every committed artefact. Both were measured.
29+
30+
Scope: a definition is flagged when it exists in the merge's second parent and not in the merge
31+
result, looked for in every file that either the merged-in branch or the merge itself changed.
32+
That second half costs something. Measured by running both filters over one window of 83 merges
33+
(38b0df38..8c7b473f, the last 200 commits of origin/main at the time): the narrow filter reports
34+
8 merges / 19 definitions, this one reports 10 / 26. The seven extra definitions come from two
35+
merges -- 514d5b08 (six) and 37ea5a13 (one) -- and they are not all one kind. Four are the second
36+
of the two real incidents, restored later and present in the tree today. The other three are the
37+
class described next. On time: the measurement noise is larger than the difference between the two
38+
versions -- three independent runs of the narrow filter over this window span 229s to 585s, a factor
39+
of 2.6, while the gap between the versions in one back-to-back run was 70s over 83 merges, about
40+
0.8s per merge. So there is no significant increase to report, which is a weaker claim than "no
41+
slower" and the one the numbers actually support. A pull request carries 0-2 internal merges. The
42+
price of widening is reading, not waiting.
43+
44+
A branch that deletes or renames a definition main still has goes red on its next base pull, and an
45+
ordinary refactor then has to carry a trailer to say so. 37ea5a13 is exactly that: it pulled
46+
origin/main into a branch that had already generalised `at_most_one_bootstrap_methods_attribute`
47+
into `at_most_one_of_each_single_class_attribute`, and the pull reported the old name as dropped.
48+
Three of the seven extra definitions are this class, so it is a class and not a corner. "CI only
49+
looks at origin/main..HEAD" is not a reason to discount it -- that range is precisely where this
50+
lands, on the next base pull of an open branch.
51+
52+
That deliberately also flags *our* intentional deletions, because from the outside the two
53+
look identical -- which is the whole difficulty. Saying which is which is a judgement, so it is
54+
recorded as one, on the merge commit:
55+
56+
Dropped-from-theirs: method fieldref -- superseded by the new pool builder, see <round>
57+
58+
One trailer per name, a reason after `--`, and both are required. THE NAME MUST BE COPIED FROM THIS
59+
CHECK'S OWN OUTPUT, character for character -- it is matched literally, so `method fieldref` works
60+
and `Pool.fieldref` does not, even though the second reads better. Run the check, copy the name it
61+
prints after the colon, paste it. (An earlier version of this docstring used the prettier form as its
62+
only worked example, which meant anyone who followed it got no exemption and lost a round.)
63+
64+
The list lives in the merge commit message rather than in a file on purpose: a file accumulates
65+
entries that outlive the merge they excused and quietly turns the check off, while a trailer can
66+
only ever excuse the one commit it is written on.
67+
68+
Usage:
69+
check-merge-dropped-symbols.py [<range>] # default: origin/main..HEAD
70+
71+
Exit: 0 nothing dropped, or everything dropped is accounted for by a trailer
72+
1 something was dropped and not accounted for
73+
2 could not measure -- a git call failed, or the clone is shallow
74+
75+
★ 2 is not a softer 0. Every git call here raises rather than returning nothing, because the one
76+
failure this check must never produce is a green one: in a shallow clone the second parent's objects
77+
are absent, every read of it comes back empty, and the old code printed `✓ (0 file(s) examined)` and
78+
exited 0. Measured on this repository at depth 10: merges that examine 20 files in a full clone
79+
examined 0 and the whole run was green. A check for a silent loss had a silent pass in it.
80+
81+
`-s ours` merges -- "record these upstream cuts as ancestors" -- drop the whole other side on
82+
purpose, and one trailer per name would mean hundreds. They use the wildcard form instead:
83+
84+
Dropped-from-theirs: * -- recorded as a merged ancestor only, our tree is authoritative
85+
86+
There is deliberately no structural exemption for them. The obvious one, "skip a merge whose tree
87+
equals its first parent's", was written and then removed: it is true of `-s ours` *and* of a
88+
resolution that took our side wholesale, and the second of those is the exact failure this exists
89+
to catch. Measured -- with that exemption in place, a synthetic merge that discarded the other
90+
side's new function passed. So the wholesale case has to be declared rather than inferred.
91+
92+
A squash landing has one parent, so there is nothing for this to compare and it reports nothing.
93+
That is not a gap: the merges this catches are the base-pulls *inside* a branch, and those are
94+
checked while the pull request is open, whichever way the branch is eventually landed.
95+
```

0 commit comments

Comments
 (0)