Skip to content
Merged
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
8 changes: 8 additions & 0 deletions .github/workflows/rust.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,3 +61,11 @@ jobs:
steps:
- uses: actions/checkout@v7
- run: python3 scripts/check-worklog-json.py

# parity lock: the CLAUDE.md DoD block must reproduce this file's checks (see the script's
# docstring — hand comparison failed five rounds in a row). One runner, not the matrix.
dod_parity:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: python3 scripts/check-dod-ci-parity.py
8 changes: 7 additions & 1 deletion CLAUDE.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,15 +22,21 @@
**검증기로 막을 수 없다.** ⇒ 이 조항은 **1차 방어**이며 **최종 방어는 diff 검토**다.

## Definition of Done
- ★**`.github/workflows/rust.yml` 이 «치는 그대로» 전부 green** — 축약하지 말고 이 여섯 줄을 그대로 쳐라:
- ★**`.github/workflows/rust.yml` 이 «치는 그대로» 전부 green** — 축약하지 말고 이 블록을 그대로 쳐라:
```
cargo fmt --all -- --check
cargo clippy --all -- -D warnings
cargo +beta clippy --all -- -D warnings
cargo clippy --workspace --exclude test-utils --target wasm32-unknown-unknown -- -D warnings
cargo test --all
python3 scripts/check-worklog-json.py
python3 scripts/check-dod-ci-parity.py
```
★★**이 블록은 이제 «기계가 지킨다» — `scripts/check-dod-ci-parity.py`(CI job `dod_parity`)가
이 코드블록과 `rust.yml` 을 «각각 파싱해» 대칭차를 낸다.** 어긋나면 그 자리에서 red 다.
⇒ ★**줄 수를 세어 문장에 적지 마라**(이 리니지가 그 수로 다섯 번 낡았다) — 세는 것은 검사기 몫이다:
`python3 scripts/check-dod-ci-parity.py` 가 「명령 N개 · toolchain N개로 «둘 다 일치»」를 찍는다.
★**그 검사기가 «못 보는 것»도 그 자리에서 함께 찍는다**(조건부 step = OS 축) — 침묵하지 않는다.
★★**`+beta` 줄을 빼지 마라 — CI 는 이 검사들을 «6셀»(toolchain 2 × OS 3)로 친다.**
`rust.yml` 의 `strategy.matrix.rust = [stable, beta]` 가 그 차원이고, 이 repo 엔 `rust-toolchain.toml` 이
**없어** 맨 `cargo` 는 **stable 1개**로만 돈다. ⇒ ★**toolchain 축을 안 적으면 「rust.yml 이 치는 그대로」가 «거짓»이 된다.**
Expand Down
23 changes: 23 additions & 0 deletions REPORT.md
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
# REPORT

## [2026-09-04] 로컬 DoD ↔ CI 매트릭스 «기계 대조» 신설 (rustjava-local-dod-vs-ci-matrix-mechanical-check)
- 무엇을: `scripts/check-dod-ci-parity.py` 신설 + `rust.yml` job **`dod_parity`** 배선 + DoD 블록에 그 줄 추가.
★**`CLAUDE.md` DoD 코드블록**과 **`.github/workflows/rust.yml`** 을 «각각 파싱해» **대칭차**를 낸다 —
축 A(명령 집합) · 축 B(toolchain 집합). 오늘 **둘 다 0** 이라 계약대로 **rc=1(막는다)** 로 켰다.
- 왜: `…-going-stale` 리니지가 **다섯 회차** 내내 「전건 동기」를 주장했고 **매번 «또 한 자리»**가 나왔다
(게이트②에서 6건째). ★**전부 같은 종류** — 「로컬 DoD 가 CI 검사 몇 개를 재현하는가」가 `rust.yml` 과
어긋난 채 문서에 굳었다. ⇒ ★**사람 손 대조로는 다섯 번 실패했다.**
★★**그런데 «낡은 문자열 스캐너»는 만들지 않았다** — 게이트② 검수자가 「F1 은 «수»가 아니라 «말»이라
문자열 검사기로도 안 잡힌다」를 실측으로 세웠기 때문이다. ⇒ 문서의 문장이 아니라 ★**문서가 틀리는 «원인»**을 잡는다.
- 사용자 영향: 런타임 동작 **무변경**(`.rs` 변경 0). 회차가 DoD 를 축약하거나 CI 가 검사·매트릭스 차원을
늘렸는데 DoD 를 안 고치면 ★**그 PR 이 그 자리에서 red** 다 — 종전엔 «사람이 축을 돌려야» 드러났다.
- 검증: ★**개악 5건 전건 red · 무개악 green** — ⒜DoD wasm32 줄 제거 ⒝CI `- run: cargo doc --no-deps` 추가
⒞매트릭스 `nightly` 추가 ⒟DoD `+beta` 줄 제거 ⒠`rust-toolchain.toml` 신설(축 B 매핑 붕괴 가드).
DoD 7줄 전건 rc=0 · `cargo test --all` **554 / 0 / 1**(새 red 0).
- ★**한계를 숨기지 않는다 — 검사기가 «그 자리에서 함께» 찍는다**: ⒜**OS 축**(조건부 step)은 로컬 재현 불가라
여전히 CI 가 유일한 그물 ⒝두 축을 **«교차곱»으로 보지 않는다** — CI 는 cargo 검사 4종을 stable·beta 둘 다
치는데 DoD 는 `clippy` 만 이중이다. ★**이것은 2026-09-04 결정이 «고른 값»**이고(로컬 `cargo +beta test` =
두 번째 toolchain 전면 재빌드 · lint 를 지는 축은 clippy 뿐), 넓히는 것은 «새 결정»이다.
- ★**후속 추천**: ⑴교차곱(모든 검사 × 모든 toolchain)까지 넓힐지 — ★**비용을 먼저 재고** 결정하라.
⑵같은 형태의 파리티 락이 형제 repo(wie·qts)에도 필요한지 판정.

## [2026-09-04] 「우리 자산이 낡는다」 상시 조항 판정 — 넣지 않고 «구멍 하나»를 막았다 (rustjava-sync-contract-standing-clause-for-our-assets-going-stale)
- 무엇을: 운영자 채택 제안 ★**셋**(`2026-09-04-upstream-sync-s6#p1` · `…-s7#p1` · ★`…-s8#p0`)에 대한 **결정**이다.
(★**[fix3 정정] 초판은 「둘」** — 같은 제안의 세 번째 판이 도착해 `adoptedProposals` 는 **세 ref** 다.)
Expand All@@ -9,6 +30,8 @@
(`REPORT.md` · `STATE.md` · 워크로그 `.md`/`.json`).
★**[게이트② 정정] 초판은 「CI 검사 5종 중 wasm32 clippy 한 줄」이라 적었다** — 계수 «1» 시절 문면이고,
계수 **2** 정정 후에는 **두 축**(target · toolchain)이라 DoD 도 **6줄**이다.
★★**[후속 정정] 그 «6줄»도 낡았다 — 파리티 검사기가 더해져 «7줄»이다.**
⇒ ★**줄 수는 이제 문장이 아니라 `scripts/check-dod-ci-parity.py` 가 센다**(CI job `dod_parity`).
- 왜: ★**목록 문서화로 시작하지 않고 «먼저 셌다»**(티켓이 그렇게 요구했다). 우리 자산 **8건**을
★**돌연변이로 깨뜨려** 무엇이 잡는지 실측했다 — 경로 문자열·`setProperty` 서술자·charset 라우팅·
`ClassFormatError` 종류 단정은 **`cargo test` RED**, 수동 span 은 **clippy RED**,
Expand Down
24 changes: 24 additions & 0 deletions STATE.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,6 +23,28 @@
(25번째 run, 앞선 24건 전부 red). **PR 대기 — 게이트③ 미착지.**

## 완료
- [rustjava-local-dod-vs-ci-matrix-mechanical-check] ★★**로컬 DoD ↔ `rust.yml` «기계 대조» 신설 —
`scripts/check-dod-ci-parity.py` + CI job `dod_parity`.** ★**5회차 리니지의 상수를 «사람 손»에서 뺐다.**
★★**설계 제약을 먼저 지켰다 — «낡은 문자열 스캐너»를 만들지 «않았다».** 게이트② 검수자가 실측으로
「F1 은 «수»가 아니라 «말»이라 문자열 검사기로도 안 잡힌다」를 세웠기 때문이다. ⇒ 문서의 «문장»이 아니라
★**문서가 틀리는 «원인»(두 집합이 갈린 것)**을 잡는다 — `CLAUDE.md` DoD 코드블록과 `rust.yml` 을
**각각 파싱해 대칭차**를 낸다(★정본 위치는 문서가 아니라 **스크립트 안**에 박혀 있다 · 계약 3).
★**축은 둘**: A=명령 집합 · B=toolchain 집합(`strategy.matrix.rust` ↔ `cargo +<tc>` 접두).
★**오늘 대칭차 0** ⇒ 계약 2 대로 **경고가 아니라 rc=1(막는다)** 로 배선했다.
★**검사기가 자기 줄을 «양쪽에» 넣는다** — CI job 과 DoD 블록 둘 다 `python3 scripts/check-dod-ci-parity.py`
라 ★**자기 존재를 자기가 강제**한다. ⇒ DoD 는 6줄 → **7줄**.
★★**개악 5건 전건 red · 무개악 green**(DoD 줄 제거 · CI `- run:` 추가 · 매트릭스 nightly 추가 ·
DoD `+beta` 제거 · `rust-toolchain.toml` 신설) — ★**공허하지 않다.**
★**침묵하지 않는다**: 성공에도 「명령 N개 · toolchain N개로 «둘 다 일치»」를 찍고,
★**못 보는 것**(조건부 step = OS 축 · 두 축을 «교차곱»으로 보지 않는 것)도 **그 자리에서 함께** 찍는다.
★**교차곱 미적용은 결함이 아니라 2026-09-04 결정이 «고른 값»이다**(`cargo +beta test` = 두 번째
toolchain 전면 재빌드 · lint 를 지는 축은 clippy 뿐) — 넓히는 것은 «새 결정»이다.
★**§4 의 셸 두 토막을 «지웠다»** — 같은 술어가 두 벌이면 다음 사람이 한쪽만 고친다(정본 = 스크립트).
★**C7⒜(「그 축을 돌리는 것이 사람이다」)가 닫혔다** · ⒝(OS 축)는 그대로 열려 있다.
★`.rs` 변경 0 · `allow` 9곳 무접촉 · upstream 무접촉.
★게이트③ 완료: PR #26 — ★★**`--merge` 착지**(★`--squash` 아님 · 등재 repo). 머지커밋 sha 는 회신 `merged:` 참조.
★**착지 후 반사실 확인**: `origin/main..upstream/main` = **0 유지**(스쿼시였으면 계보가 접혀 다시 벌어진다) ·
★**`origin/main` 에서 신설 job `dod_parity` success** 확인.
- [rustjava-sync-contract-standing-clause-for-our-assets-going-stale] ★**「우리 자산이 낡는다」 상시 조항
«판정» — 결론: ★★넣지 «않는다». 대신 «구멍 하나»(로컬 DoD 가 CI 매트릭스를 재현하지 않던 것)를 막았다.**
★코드(`.rs`) 변경 0 · 규범 문서 2 + 기록 문서 4.
Expand All@@ -38,6 +60,8 @@
★★**근인은 「자산 목록이 없다」가 아니었다** — ★**로컬 DoD 가 CI 검사 5종 중 «wasm32 clippy» 한 줄을 빠뜨렸고**
그 줄이 그 자산이 사는 **유일한 자리**다. ⇒ `CLAUDE.md` DoD 가 이제 ★**CI 명령 5줄 + toolchain 축 1줄 = «6줄»**을
축약 없이 싣는다(★**[게이트② 정정] 「5줄」은 계수 «1» 시절 수다 — 빠진 것은 «줄 하나»가 아니라 «두 축»이었다**).
★★**[후속 정정] 그 «6줄»도 낡았다 — 파리티 검사기가 더해져 «7줄»이다.** ⇒ ★**이제 줄 수를 문장에 적지 않는다**:
`scripts/check-dod-ci-parity.py`(CI job `dod_parity`)가 DoD 코드블록과 `rust.yml` 을 각각 파싱해 대칭차를 낸다.
★그리고 ②는 «조용히» 실패하지도 않는다(`excluded package(s) not found` + 빌드 실패) ⇒ 문제는 침묵이 아니라 **늦음**이다.
★**재개 조건은 «축 둘»이다**(정정): **축① `- run:` 줄** · ★**축② toolchain 매트릭스** — 세는 명령 둘 다 §4 에 박았다.
★**오늘의 값 = 축① 0 · 축② 0**(착수 시 축① **5** · 축② **1**). ★세 돌연변이(beta 제거·nightly 추가·`- run:` 추가)로
Expand Down
41 changes: 25 additions & 16 deletions docs/upstream-sync-approach.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -200,6 +200,8 @@ wasm32 clippy 한 줄」이었다.** 그것은 ★**계수 «1» 시절의 문
빠진 것은 «줄 하나»가 아니라 ★**«두 축»**(② target 축 = wasm32 `- run:` 줄 · ⑦ toolchain 축 = beta)이고,
둘은 ★**한 근인의 두 얼굴**이다. ⇒ 그래서 DoD 는 **5줄이 아니라 6줄**이다.

★★**[2026-09-04 후속 — `rustjava-local-dod-vs-ci-matrix-mechanical-check`] 위 «6줄»은 «수»이고, 그 수가 이 리니지를 다섯 번 낡게 했다.** DoD 는 그 뒤 `python3 scripts/check-dod-ci-parity.py` 가 더해져 **7줄**이 됐다. ⇒ ★**이제 줄 수를 문장에 적지 않는다** — `scripts/check-dod-ci-parity.py`(CI job `dod_parity`)가 DoD 코드블록과 `rust.yml` 을 **각각 파싱해** 대칭차를 내고, 어긋나면 **red** 다.

★**왜 조항이 아닌가 — «세고» 정했다**(먼저 목록을 만들지 않았다). 자산 8건을 **돌연변이로 깨뜨려** 무엇이 잡는지 쟀다:

| # | 우리 자산 | 돌연변이 | 무엇이 잡나 |
Expand DownExpand Up@@ -276,26 +278,27 @@ sed -n '/^| # | 우리 자산/,/^$/p' docs/upstream-sync-approach.md \
> ★**CI 가 치는 것 중 로컬 DoD 에 없는 것이 «1건이라도» 생기면 이 결정을 다시 연다.**
> ★★**«치는 것»은 «줄»만이 아니라 «매트릭스 차원»도 포함한다** — 그래서 축이 둘이다.

★★★**[2026-09-04 후속 — 이 두 축은 이제 «기계»가 센다. 손으로 세지 마라.]**
종전에는 여기 셸 두 토막이 있었고 ★**회차가 그것을 «돌려야» 했다**(C7⒜ 가 「그 축을 돌리는 것이 사람이다」로 고지한 그 구멍).
그 손 대조는 이 리니지에서 **다섯 번 실패**했다. ⇒ ★**같은 술어를 코드로 옮겼다**:

```sh
cd "$(git rev-parse --show-toplevel)"
DOD=$(sed -n '/## Definition of Done/,/^- 착수·완료마다/p' CLAUDE.md)

# ★축① — CI 의 `- run:` 줄 ∖ 로컬 DoD (0 이어야 한다)
LC_ALL=C /usr/bin/grep -E '^[[:space:]]+- run: ' .github/workflows/rust.yml | sed 's/^[[:space:]]*- run: //' \
| while IFS= read -r c; do printf '%s' "$DOD" | LC_ALL=C /usr/bin/grep -qF -- "$c" || echo "MISSING-RUN: $c"; done \
| /usr/bin/grep -c .

# ★축② — CI 의 toolchain 매트릭스 ∖ 로컬 DoD (0 이어야 한다)
LC_ALL=C /usr/bin/grep -E '^[[:space:]]+rust: \[' .github/workflows/rust.yml \
| sed 's/.*\[//; s/\].*//; s/, */\n/g' \
| while IFS= read -r tc; do
[ "$tc" = stable ] && { printf '%s' "$DOD" | LC_ALL=C /usr/bin/grep -qE 'cargo (fmt|clippy|test)' || echo "MISSING-TC: $tc"; continue; }
printf '%s' "$DOD" | LC_ALL=C /usr/bin/grep -qF -- "cargo +$tc " || echo "MISSING-TC: $tc"
done | /usr/bin/grep -c .
python3 scripts/check-dod-ci-parity.py # rc=0 일치 · rc=1 대칭차 있음(어느 원소인지 찍는다)
```

★**오늘의 값**(2026-09-04 정정 후): **축① `0`** · **축② `0`**.
★**CI 도 이것을 친다** — `rust.yml` job **`dod_parity`** · 로컬 DoD 블록에도 그 줄이 있다.
⇒ ★**셸 토막을 여기 다시 적지 마라 — 두 벌이 되면 다음 사람이 한쪽만 고친다.** 정본은 그 스크립트다.
★**정본 위치도 문서가 아니라 «스크립트 안»에 박혀 있다**(`CI_FILE`·`DOD_FILE`·`DOD_SECTION`).

★**오늘의 값**(2026-09-04 · 검사기 착지 후): ★**축 A(명령) 대칭차 `0`** · ★**축 B(toolchain) 대칭차 `0`**
— 출력은 「OK 두 축 모두 대칭차 0 — 명령 6개 · toolchain 2개로 «둘 다 일치»」.
※착수 시엔 **축① 5 · 축② 1**(beta 가 DoD 에 없었다) — 축①은 원 회차가, 축②는 정정 회차가 0 으로 만들었다.
★★**검사기가 «못 보는 것»을 침묵시키지 않는다 — 그 자리에서 함께 찍는다**:
⒜**OS 축**(조건부 step) — 로컬 재현 불가라 CI 가 유일한 그물이다.
⒝★**두 축은 «독립»으로 비교한다 — 교차곱이 아니다.** CI 는 cargo 검사 4종을 stable·beta **둘 다** 치는데
DoD 는 `clippy` 만 이중으로 친다. ★**이것은 결함이 아니라 2026-09-04 결정이 «고른 값»이다**(로컬에서
`cargo +beta test` 는 두 번째 toolchain 전면 재빌드다 · lint 를 지는 축은 clippy 뿐이고 실측 gap 도 거기였다).
⇒ ★**교차곱까지 넓히는 것은 «버그 수정»이 아니라 «새 결정»이다.**

★★**축②를 왜 따로 두는가 — 축① 만으로는 «구조적으로» 못 본다.** 실측(정정 회차):

Expand All@@ -316,6 +319,12 @@ LC_ALL=C /usr/bin/grep -E '^[[:space:]]+rust: \[' .github/workflows/rust.yml \
⒜**DoD 블록 자체의 개악은 자동으로 안 잡힌다** — 누가 그 블록에서 한 줄을 지우면 축①이 **1** 이 되지만,
★**그 축을 «돌리는 것»이 사람이다.** 기계 강제(DoD ↔ `rust.yml` 대조 CI job)는 이 회차 범위 밖이고,
★**고칠 수 없으면 «고지»가 처방이다.** ⇒ ★**이 절을 읽는 회차는 「축①·축②를 «실제로 돌렸는가»」를 회신에 적어라.**
★★★**[2026-09-04 후속 — ⒜ 는 «닫혔다». 위 문장은 사료다.]** 그 「범위 밖」을 총괄이 판정해
**`scripts/check-dod-ci-parity.py` + CI job `dod_parity`** 로 배선했다 ⇒ ★**DoD 블록에서 한 줄을 지우면
그 자리에서 CI 가 red 다**(개악 대조 실측: DoD wasm32 줄 제거 → rc=1 · CI 에 `- run:` 1줄 추가 → rc=1 ·
매트릭스에 nightly 추가 → rc=1 · DoD 의 `+beta` 줄 제거 → rc=1 · `rust-toolchain.toml` 신설 → rc=1).
⇒ ★**「돌렸는가」를 회신에 적는 관례는 이제 «불요»다** — 안 돌리면 CI 가 대신 말한다.
★**⒝(OS 축)는 그대로 열려 있다** — 검사기도 그것을 «제외»로 찍을 뿐 잡지 못한다.
⒝★**OS 축(macos·ubuntu·windows 3종)은 로컬에서 재현할 수 없다** — 그 차원은 ★**CI 가 «유일한» 그물**이고
대조 대상이 아니다. **결함이 아니라 «알고 두는» 값이다.**

Expand Down
Loading