Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions REPORT.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
# REPORT
## [2026-09-19] 검사기가 «실행마다 자기와 불일치»했다 — `sorted()` 한 줄(2026-09-19-partial-clone-blob-vs-absence-p0)
- 무엇을: 채택 제안 `2026-09-19-partial-clone-blob-vs-absence#p0`(worklog json 기록). `check-merge-dropped-symbols.py` 의 **경로 루프**를 정렬한다. ★**1파일 +7/−1**(코드 1줄 + 측정 기록 주석 6줄).
- ★**전제 재측**(오늘 `origin/main` · 같은 범위 · `PYTHONHASHSEED=random` **8회**): ★**순서 2종**(6 + 2) — 같은 **6건**을 다른 차례로 찍는다. ⇒ 제안은 옳고, ★**그 이유도 옳다**: 이 리니지가 실제로 그 대가를 치렀다(전/후 diff 가 «회귀»처럼 보였고, **원판본이 자기와 불일치**함을 보여서야 갈렸다).
- ★★**다만 «자리»는 제안이 지목한 곳이 아니다**: 제안은 「set 에 모아 iteration order 로 «찍는다»」고 했는데 ★**찍는 자리는 이미 정렬돼 있었다**(`sorted(theirs_symbols - …)` ⇒ 경로 «안»의 이름은 늘 정렬). 흔들린 것은 ★**바깥 경로 루프** — `for path in filter(None, changed)` 이고 `changed` 는 `git diff --name-only` 둘을 합친 **set** 이다. ⇒ 고친 자리는 **print 가 아니라 루프**다.
- ★**양방향 축(제품 스크립트)**: 그 줄만 되돌리면 8회에 **순서 2종** ↔ 넣으면 **8/8 동일**. ★**내용은 양방향 불변** — findings **6** · **rc=1** · 요약 줄 동일.
★**Acceptance 문면 고지**: 「되돌리면 red」를 요구하는데 ★**이 변경에는 뒤집을 판정이 없다**(순서만 바꾸고 rc 는 설계상 전후 1) ⇒ 축을 **«순서 종수»**로 세웠고 그 사실을 적는다.
- ★**대가**: ⒜보고가 **순회 순서를 더는 반영하지 않는다**(아무도 안 읽어서 안전했고, 그래서 여태 안 들켰다) ⒝★**«보고를 비교 가능»하게 할 뿐 «검사를 결정적»으로 만들지는 않는다** — `examined` 수·등장 머지 등 저장소 상태 의존은 그대로다(과장 금지) ⒞★**이 검사기만** 고쳤다 — 형제 검사기는 **보기엔** 안전했으나(정렬된 missing 목록·정렬된 파일 순회) **재지는 않았다**.
- ★**비용 유의차 없음**: 전 **2.09/2.51/2.41s** ↔ 후 **2.52/1.90/1.65s**(구간 겹침).
- ★**노력도**: 제안 추정 **S** 가 맞았다 — 실제 일은 **측정**(8회 × 2방향)이었고, 그것이 「정렬해야 한다」를 「정렬 안 돼 있었고 그 크기는 이만큼」으로 바꾼다.
- 검증: DoD 9명령 · 아래 절.

## [2026-09-19] 적재 가능 집합을 «로더에서 읽을까» — ★**아니다, 재유도를 유지한다**(rustjava-loadable-set-from-loader-vs-rederive-decision)
- 무엇을: 채택 제안 `2026-09-18-named-exception-classes-are-loadable#p2`(worklog json 기록). ★**순수 결정 회차 — `.rs` 0줄 · `scripts/` 0줄.** 산출 = `docs/loadable-set-source-of-truth.md`(선례 = `docs/test-data-target-policy.md`).
- ★★**전제부터 확인했다 — 「4결함 중 3이 재유도」는 «참»이다.** 산문이 아니라 **고침 커밋 `89c2e83c` 에서** 갈랐다: ⑴`as_proto` 전용 → `list_proto` 3건 누락 ⑵한 `impl` 의 첫 `name:` 오귀속 ⑶짧은 이름 키 충돌 = **재유도(loadable) 3건** · ⑷줄 단위 스캔이 rustfmt 가 쪼갠 34건 누락 = ★**호출부 스캔(named) 1건**.
Expand Down
5 changes: 5 additions & 0 deletions STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
(둘 다 이것보다 오래됐고 MERGEABLE/CONFLICTING 처분이 이미 걸려 있다). 겹침은 전부 **append 형 합집합**이라 해소는 기계적이다)

## 완료
- [2026-09-19-partial-clone-blob-vs-absence-p0] ★★**검사기가 실행마다 자기와 불일치했다 — 경로 루프 `sorted()` 한 줄.** 채택 제안 `2026-09-19-partial-clone-blob-vs-absence#p0`. ★**1파일 +7/−1.**
★**전제 재측**: 오늘 main 에서 8회에 **순서 2종**(6+2) · 같은 6건.
★★**자리가 제안과 다르다**: 「print 가 set 순서」가 아니라 ★**바깥 «경로» 루프**가 set 이었다(이름은 이미 `sorted`).
★**양방향**: 되돌리면 **2종** ↔ 넣으면 **8/8 동일** · 내용 불변(6건 · rc=1 · 요약 동일). ★rc 로는 red 를 못 만든다(순서만 바뀐다) — 축을 «순서 종수»로 세웠다.
★**대가**: 순회 순서 미반영 · ★**«비교 가능»일 뿐 «결정적»이 아니다**(저장소 상태 의존 그대로) · **이 검사기만** 고쳤다(형제는 미측정).
- [rustjava-loadable-set-from-loader-vs-rederive-decision] ★★**적재 가능 집합은 «재유도»를 유지한다 — 로더에서 읽지 않는다.** 채택 제안 `2026-09-18-named-exception-classes-are-loadable#p2`. ★**순수 결정 · 코드 0줄** · 산출 = `docs/loadable-set-source-of-truth.md`.
★**전제 확인**: 「4중 3이 재유도」는 **참**(고침 커밋 `89c2e83c` 에서 갈랐다 — loadable 3 · named 1).
★★**그 1건이 결정한다**: `named`(코드가 무엇을 넘기는가)는 **로더가 답할 수 없다** ⇒ 로더 읽기는 **파서 하나를 없앨 뿐 파싱을 못 없앤다**(그 절반에서 형제 회차가 ★**4시간 31분** 뒤에 또 잡았다 — ★**「다른 함수 8종 41자리」**를 쓸어담는 앵커 함정이고, 세면 **33** · 맞는 답은 **0** 이다).
Expand Down
37 changes: 37 additions & 0 deletions docs/worklog/2026-09-19-sorted-findings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"date": "2026-09-19",
"taskId": "2026-09-19-partial-clone-blob-vs-absence-p0",
"summary": "The merge-dropped-symbols check emitted its findings in hash-seed order, so two runs of the same version disagreed. Re-measured on today's origin/main: eight runs produced two distinct orderings of the same six findings. Sorting the path loop makes the report comparable; content, rc and summary are unchanged.",
"measurements": {
"runs_per_direction": 8,
"orderings_before": 2,
"orderings_after": 1,
"findings": 6,
"rc_before": 1,
"rc_after": 1,
"files_changed": 1,
"lines_added": 7,
"lines_removed": 1,
"runtime_before_seconds": [2.09, 2.51, 2.41],
"runtime_after_seconds": [2.52, 1.90, 1.65]
},
"verification": [
"premise re-measured on origin/main @ ad9eb1a6: 8 runs under PYTHONHASHSEED=random over e53b2142^..e53b2142 gave 2 orderings (6 + 2) of the same 6 findings",
"axis, both directions on the product script: with the sort reverted 8 runs give 2 orderings; with it, 8/8 identical",
"content unchanged in both directions: 6 findings, rc=1, identical summary line",
"cost: before 2.09/2.51/2.41s vs after 2.52/1.90/1.65s, overlapping"
],
"changes": [
"scripts/check-merge-dropped-symbols.py - the path loop iterates sorted(changed) instead of the set, with the measurement recorded in a comment",
"docs/worklog/2026-09-19-sorted-findings.{md,json}, REPORT.md, STATE.md"
],
"issues": [
"The proposal located the problem at the print site ('accumulated in a set and printed in iteration order'); names were already sorted there. The unordered part was the outer path loop over a set built from two git diff --name-only results.",
"This makes the report comparable, not the check deterministic: examined counts and which merges appear still depend on repository state.",
"Only this checker was changed. The sibling check appeared safe on inspection (sorted missing list, sorted file walk) but was not measured."
],
"adoptedProposals": [
"2026-09-19-partial-clone-blob-vs-absence#p0"
],
"proposals": []
}
68 changes: 68 additions & 0 deletions docs/worklog/2026-09-19-sorted-findings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# 2026-09-19 — The check disagreed with itself between runs. One `sorted()` fixed it.

Round: `2026-09-19-partial-clone-blob-vs-absence-p0`
Adopted proposal: `2026-09-19-partial-clone-blob-vs-absence#p0` —
*"Sort the checker's findings so two runs can be compared."*

## The premise, re-measured on today's `origin/main`

Eight runs of the **unchanged** checker over the same range (`e53b2142^..e53b2142`), under
`PYTHONHASHSEED=random`, hashing the output:

```
6 16efef4228f50b1147cb57f8e1aced09
2 9b1105a77918f30b31c42c890815d10c
```

Two orderings of the same six findings. The proposal is right, and it is right for the reason it
gives: this cost a real round — a before/after diff of this checker looked like a regression until
the *unchanged* version was shown to disagree with itself.

## Where it came from, which is not quite where the proposal looked

The proposal says *"Findings are accumulated in a set and printed in iteration order."* Close, but
the print site was already fine: names are emitted through `sorted(theirs_symbols - …)`, so findings
**within a path** were always ordered. What was unordered is the **path loop** —
`for path in filter(None, changed)`, where `changed` is a `set` built from two `git diff --name-only`
results. So the fix is on the outer loop, not at the print:

```python
for path in sorted(filter(None, changed)):
```

**Changed: 1 file, +7/−1 lines** (one of them code, six a comment recording the measurement).

## Axis — bidirectional, on the product script

| form | 8 runs, `PYTHONHASHSEED=random` |
|---|---|
| that line reverted | **2 orderings** (6 + 2) |
| with it | **1 ordering** (8 / 8) |

Content is untouched in both directions: 6 findings, `rc=1`, and the same summary line
`8 merge(s) in e53b2142^..e53b2142: 6 definition(s) dropped without a trailer`.

**On the acceptance wording**: it asks for "revert it and get red". This change has no verdict to
flip — it changes output *order*, not outcome, so `rc` is 1 before and after by design. The axis is
therefore the ordering count above, measured in both directions on the real script.

## What this costs

- **The report no longer reflects traversal order.** Nothing reads it, which is exactly why this was
safe — and also why it was never noticed.
- **It makes the report comparable, not the check deterministic.** `examined` counts, which merges
appear, and everything else that depends on repository state still vary with the repository. A
future round that diffs two runs across *different* trees will still see real differences; this
only removes the false ones.
- **It fixes this checker only.** The sibling checks were not audited for the same shape in this
round; `check-named-exception-classes-are-loadable.py` emits its missing list through `sorted(…)`
and walks files through a sorted `rust_files()`, so it appeared safe, but that is an observation
in passing rather than a measurement.
- Runtime: **no significant change** — before 2.09 / 2.51 / 2.41 s, after 2.52 / 1.90 / 1.65 s
(overlapping). Sorting a set of a few dozen paths is not where this check spends its time.

## Effort

The proposal estimated **S** and that was right: the change is one line. The round's actual work was
the measurement — 8 runs × 2 directions — which is what turns "should be sorted" into "was unordered,
here by how much".
8 changes: 7 additions & 1 deletion scripts/check-merge-dropped-symbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,13 @@ def check(merge):
accounted = excused(merge)
if excuses_everything(accounted):
return [], 0
for path in filter(None, changed):
# Sorted because `changed` is a set: without this the findings come out in whatever order the
# hash seed produced, and two runs of the *same* version disagree. Measured on `origin/main`
# before this line: eight runs under PYTHONHASHSEED=random gave two distinct orderings of the
# same six findings (6 + 2). That cost a real round -- a before/after diff of this check looked
# like a regression until the unchanged version was shown to disagree with itself. Names are
# already sorted within a path below; this makes the whole report comparable.
for path in sorted(filter(None, changed)):
theirs_symbols = symbols(theirs, path)
if theirs_symbols is None:
continue
Expand Down
Loading