diff --git a/docs/STATUS.md b/docs/STATUS.md index 2338d90..fb2069e 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -235,8 +235,9 @@ > > **▶ 다음 세션 — 여기서 시작한다.** 순서대로: > -> 1. **다음 슬라이스 — 사용자 결정.** 결정표는 §9-71.6이다(권고: F2 — DP-O7을 뒤집는다, Grok 동의). 고르면 -> 그 안의 SPEC을 먼저 쓴다. 시험 구현은 로컬 브랜치 `exp/wide-local`에 있다(푸시 안 함). +> 1. **헬퍼 체크 전파 SPEC 확인 — 사용자 결정.** 방향(§9-71.6의 F2)은 확인받았다(2026-09-26). 초안은 +> `docs/slices/SPEC-helper-check-propagation.md`이고 §4의 DP-P2~P11이 확인을 기다린다. 확인되면 §6의 두 PR로 +> 구현한다. 시험 구현은 로컬 브랜치 `exp/wide-local`에 있다(푸시 안 함). > 2. **작은 항목**: C# 호스트(Phase 4) · LSP(Phase 3, 큰 일). > 3. **외부**: `X1`·`X2` — Delphi가 있는 CI 러너. 이 저장소 안에서는 닫히지 않는다. > diff --git a/docs/slices/README.md b/docs/slices/README.md index f688b23..08b517f 100644 --- a/docs/slices/README.md +++ b/docs/slices/README.md @@ -63,6 +63,7 @@ TDD 구현 → Grok 검증 → PR** 순서를 따른다(`CLAUDE.md` "개발 방 | [나눗셈 가드가 왼쪽 피연산자를 건너뛴다](SPEC-division-guard-operands.md) | ✅ **구현 완료** (2026-09-23) | 제수가 0이면 `/`·`%`의 왼쪽 피연산자(배열 경계 검사)가 실행되지 않던 결함 — 왼쪽을 먼저 묶어 평가한다 | #287 / #291 | | [상수 선언 `const` · `export const`](SPEC-constants.md) | ✅ **구현 완료** (2026-09-26) | 이름 붙은 리터럴 — `export const`만 헤더(`ML__CONST_`)와 지문에 나가, 번호를 바꾼 모듈을 게이트가 거부한다 | #325 / #326·#327 | | [체크드 정수 산술](SPEC-checked-arithmetic.md) | ✅ **구현 완료** (2026-09-26) | `!` 본문의 i32 오버플로와 `f64 as i32`가 `ML_ST_OVERFLOW`(`-3`)로 실패한다 — 조용한 오답 161행 중 101이 status가 된다 | §9-69 / #334 · §9-70 | +| [헬퍼 체크 전파](SPEC-helper-check-propagation.md) | 🔨 **SPEC 초안 · 확인 대기** (2026-09-26) | `!` 본문이 부른 무한 헬퍼의 산술도 검사하고 `-3`을 전파한다 — 방향(F2)은 확인받았고 하위 결정 DP-P2~P11이 남았다 | §9-71 / — | > **2026-09-25에 행을 한 줄로 접었다.** 접기 전의 서술은 [`../history/slices-index.md`](../history/slices-index.md)에 > 바이트 그대로 있다. **새 행도 한 줄로 쓴다** — 행당 400 B(`every_slice_index_row_is_one_line`)이고, 경위는 그 @@ -125,7 +126,7 @@ TDD 구현 → Grok 검증 → PR** 순서를 따른다(`CLAUDE.md` "개발 방 두 번째 호스트(C#, ROADMAP Phase 4), 그리고 ROADMAP Phase 2가 이름만 두고 설계가 없던 둘 — **인터페이스 정의 파일**(설계부터)과 **개발/배포 빌드 분리**(D13, `SECURITY.md` P1). *(2026-09-25 로드맵 검토에서 더했다 — Phase 2의 다섯 항목 중 이 둘이 이 목록에 없었다.)* -§7(§9-69, 12개 도메인 72규칙과 귀속 대조)이 더한 후보: **헬퍼 체크 전파**와 **넓은 중간값**(둘 다 626행으로 시험 구현했다 — 결정표는 §9-71.6), **i64**(§9-71: 옵트인이라 귀속 대조에서 51행이 빠졌다), **입력 문자열의 인코딩 계약**(닫힌 DP-S2의 재개 — `OPEN_QUESTIONS.md` Q17이 (A)로 열어 두었고 재검토 조건은 거기 있다), 비트 연산자, +§7(§9-69, 12개 도메인 72규칙과 귀속 대조)이 더한 후보: **헬퍼 체크 전파**(방향을 확인받아 SPEC 초안이 있다, 위 색인)와 **넓은 중간값**(둘 다 626행으로 시험 구현했다 — 결정표는 §9-71.6), **i64**(§9-71: 옵트인이라 귀속 대조에서 51행이 빠졌다), **입력 문자열의 인코딩 계약**(닫힌 DP-S2의 재개 — `OPEN_QUESTIONS.md` Q17이 (A)로 열어 두었고 재검토 조건은 거기 있다), 비트 연산자, 지역 작업 배열, 수학 내장 함수, 문자 단위 길이. **struct는 §9-1이 강제되지 않는다고 결론냈다** — 고르려면 그 절을 먼저 읽는다(§9-69도 귀속 0으로 다시 확인했다). 배열도 같은 결론이었고(§9-9가 다섯 번째로), **입력은 그 사실을 SPEC 첫 절에 적은 채로 열렸다**. diff --git a/docs/slices/SPEC-helper-check-propagation.md b/docs/slices/SPEC-helper-check-propagation.md new file mode 100644 index 0000000..56b71e5 --- /dev/null +++ b/docs/slices/SPEC-helper-check-propagation.md @@ -0,0 +1,212 @@ +# SPEC — 헬퍼 체크 전파 (`!` 본문이 부른 헬퍼도 검사한다) + +- **상태: 초안. 사용자 확인 전이며 제품 코드는 한 줄도 쓰지 않았다.** + - **방향은 확인받았다(2026-09-26)**: §9-71.6의 권고안 F2 — `!` 함수가 부른 무한 헬퍼 안의 산술도 검사한다. + 이 문서가 묻는 것은 **§4의 하위 결정**이다. +- 선행: `SPEC-checked-arithmetic.md`(DP-O1 — `!` 본문만 · **DP-O7 — 무한 헬퍼가 탈출구**, 이 슬라이스가 뒤집는다 · + DP-O4 — 지문·ABI 불변 · DP-O6 — `result` 뒤) · `SPEC-calls.md`(재귀 금지 — 호출 그래프는 DAG) +- 관련 결정: **D17**(음수 status 예약) · #238(바인딩은 모듈이 낼 수 있는 status를 빠짐없이, 그리고 그것만 선언한다) +- 발단: §9-71(체크드 산술 다음 — 626행 시험 구현) + +--- + +## 0. 왜 — 측정부터 + +### 0.1 체크드 산술이 닿지 못한 조용한 오답 (E2, §9-71.3) + +체크드 산술은 **본문**에 규칙을 걸었다: `!` 본문의 산술은 검사하고, `!` 없는 헬퍼는 누가 불러도 wrap한다(DP-O7). +그래서 같은 식을 헬퍼로 빼면 `-3`이 그럴듯한 숫자로 돌아간다. 로컬 브랜치 `exp/wide-local`의 스위치로 이 슬라이스를 +구현해 626행을 다시 쟀다: + +| 625행(메모 1 제외) | 맞음 | 조용한 오답 | 참값이 드는데 `-3` | +|---|---|---|---| +| 오늘 | 496 | 60 | 52 | +| 헬퍼 체크 전파 | 505 | **44** | 59 | + +바뀐 16행은 **전부 오늘 조용한 오답**이었다: 9행은 참값이 i32 밖이라 실패가 맞고(billing R4 · R6, hostdata R2), +7행은 참값이 드는데 `-3`이 된다(records R2, stateful R1). **맞던 status 0 답은 하나도 바뀌지 않았다.** 전체 스위트에서 +동작이 바뀐 테스트는 DP-O7을 고정한 한 줄뿐이다. + +### 0.2 코퍼스 (E2, 컴파일러 IR로 센 것) + +| 코퍼스 | 무한 내부 헬퍼 | `!` 본문에서 닿음 | 그중 검사할 연산이 있음 | `!`에서 부르는 export 무한 함수 | 가장 긴 헬퍼 사슬 | +|---|---|---|---|---|---| +| `examples/` 26파일 | 2 | 1 | **0** | 0 | 1 | +| 테스트에 박힌 소스 39 | 36 | 5 | 1(DP-O7 고정의 `twice`) | 0 | 1 | +| §7 업무 규칙 83파일 | 50 | 50 | 17 | 0 | 3 | + +- **의도한 wrap에 기대는 헬퍼는 어느 코퍼스에도 없다.** 있는 모듈러·체크섬·날짜 헬퍼는 현실적 입력 22개에서 전부 같은 + 답이고, 극단 입력에서만 바뀌는데 거기서 오늘의 wrap은 **조용한 오답**이다(연도 214748의 쓰레기 날짜, Y2038 직전 + 일일 한도 초기화). 의도한 wrap은 합성 해시·LCG로만 보였고, 그것들은 보통 입력에서 `-3`이 된다(§0.3). +- `examples/`에는 이 슬라이스가 닿는 모양이 **없다** — 수용 D(실제 C 호스트)는 예제에 헬퍼를 넣어야 잴 수 있다(§6). + +### 0.3 시험 구현이 드러낸 결함 — SPEC이 고칠 것 (E2, 재현함) + +| 결함 | 잰 것 | +|---|---| +| **바인딩이 `-3`을 선언하지 않는다** | `!` export가 넘치는 헬퍼를 부르면 모듈은 `-3`을 내는데 `.h`·`.pas`의 `ML_ST_OVERFLOW` 선언은 0번. 술어가 함수 **자신의** 본문만 본다(#238과 같은 부류). §7 코퍼스 83파일에는 없고, 그 변형 파일(예: 사후 가드를 단 요금 계산)에서 나타난다 | +| 쌍둥이 이름이 합법한 사용자 함수와 충돌 | `fn mul` + `fn __twin_mul` → `error[E0428]`. 함수 이름에는 접두 제약이 없다(#101) | +| 주변 `RUSTFLAGS=-D warnings`에서 빌드 실패 | `examples/discount4.mls`가 오늘은 빌드되고 시험 구현에서는 `never used`로 실패 | +| 필요 없는 쌍둥이 | 코퍼스 헬퍼 291개 중 175개가 쓸모없는 쌍둥이를 받았다(검사할 연산이 없거나 `!`에서 안 닿음) | +| **`export`가 검사를 멈춘다** | `!` 본문이 export 무한 함수 `wmul(65536, 65536)`을 부르면 status 0에 `0` — 그 아래 헬퍼까지 wrap | + +### 0.4 크기와 멈춤 (E2) + +- **크기**: 예제 26개는 쌍둥이를 켜도 링크 타임스탬프를 가리면 **바이트까지 같다**(26/26). 헬퍼 20개를 `!` export 10개가 + 부르는 합성 모듈은 `.text` 4280 → 4696바이트(+9.7%), DLL +512(파일 정렬 한 칸). +- **멈춤이 줄어든다**: `fn grow(x, n) { let mut v = x while v < n { v = v * 2 } return v }`를 + `export fn f(n) -> i32! { return grow(1, n) }`가 부를 때 `f(2147483647)`은 오늘 `v`가 `i32::MIN`을 거쳐 0으로 wrap해 + **끝나지 않고**(30초 타임아웃에 죽였다), 시험 구현은 즉시 `-3`이다. `f(1000)`은 둘 다 `1024`. 호스트가 직접 부르는 + 무한 함수의 멈춤은 그대로다. + +--- + +## 1. 범위 + +**포함** + +1. `!` 본문이 **직접 또는 무한 함수들을 거쳐** 부르는 무한 함수(`!` 없는 함수 — 내부든 export든)의 산술과 변환이 + `SPEC-checked-arithmetic` §2.1의 `!` 열 그대로 검사되고, `-3`이 호출자에게 전파된다. +2. 바인딩 술어가 그 경로를 본다 — `.h`·`.pas`가 **한 술어**로 `ML_ST_OVERFLOW`를 선언한다. +3. 생성 Rust의 방출: 검사용 사본의 이름·범위, 참조되는 본문만 방출, 경고. +4. `LANGUAGE.md`·`HOST_ABI.md`·생성 `.h`/`.pas`의 문구, DP-O7을 고정한 테스트. +5. §9-71의 626행을 구현본으로 다시 재어 시험 구현의 표와 대조한다(기록이지 가드가 아니다). + +**미포함 (명시)** + +- 무한 함수를 **호스트가 직접** 부를 때 — wrap·포화 그대로(채널이 없다, D17). export 어댑터는 바뀌지 않는다. +- 넓은 중간값(WIDE) — §9-71.4의 위험을 따로 정해야 한다. i64 · 탈출구 내장 함수(§2.8). +- `-2`(경계 밖) — **무한** 헬퍼에서는 생기지 않는다: 무한 본문은 인덱스·스팬 비교가 거부되고(DP-A3) `fixed`는 + `-> string!`에서만 쓰인다. `!` 헬퍼의 `-2`는 오늘도 선언된다 — 술어가 모든 `!` 본문을 본다. +- `DECISIONS.md` — D17이 음수를 이미 예약했고 DP-O7은 슬라이스 결정이다. + +--- + +## 2. 계약 + +### 2.1 규칙 — 본문이 아니라 호출 경로가 정한다 (DP-P1) + +**`!` 함수를 위해 실행되는 산술은 어디에 쓰여 있든 검사된다.** 무한 함수 `h`를 + +| 부르는 쪽 | `h` 안의 i32 `+ - *`, 단항 `-`, `MIN / -1`, `f64 as i32` | +|---|---| +| `!` 본문(직접, 또는 무한 함수들을 거쳐) | 넘치면 **`-3`**, 호출자가 그 자리에서 `-3`으로 반환 | +| 무한 본문 · 호스트(export 어댑터) | wrap · 포화(오늘과 같다) | + +그래서 **식을 헬퍼로 빼도 답이 바뀌지 않는다** — 오늘은 뺀 순간 `-3`이 wrap한 숫자가 된다. 대가도 적는다: **같은 헬퍼가 +부르는 쪽에 따라 다르게 동작한다**(오늘도 `!`와 무한 본문 사이에서 이미 그렇다). + +### 2.2 어디까지 (DP-P2, DP-P3) + +- **export된 무한 함수도 포함한다**(DP-P2). `export`는 호스트에게 보이는지를 정할 뿐 내부 의미를 바꾸지 않는다 — + 빼면 *"호스트가 시험하려고 헬퍼를 export로 올리는"* 편집이 `-3`을 wrap으로 조용히 바꾼다(시험 구현에서 잰 결함). + 호스트가 부르는 어댑터는 그대로 wrap한다. `out` 파라미터가 있는 함수는 식에서 부를 수 없으므로 대상이 아니다. +- **반환 타입을 가리지 않는다**(DP-P3): `bool`·`f64`를 돌려주는 헬퍼 안의 i32 산술과 `f64 as i32`도 검사한다 + (시험 구현: `a*b > 100`을 돌려주는 `bool` 헬퍼 → `-3`, `x as i32`의 NaN → `-3`). +- **사슬 전체**: 헬퍼가 부르는 헬퍼도 같은 규칙이다. 재귀가 금지돼 있어 호출 그래프는 DAG이고 사본은 함수당 하나다. + +### 2.3 실패 시점과 순서 — 체크드 산술과 같다 (DP-P4) + +- **연산자에서 즉시** 실패한다(`SPEC-checked-arithmetic` §2.1과 같은 검사 자리). 헬퍼를 끝까지 wrap으로 돌린 뒤 표시하지 + 않는다 — 그래서 wrap이 부르던 헬퍼 안의 무한 루프가 `-3`이 된다(§0.4). +- 헬퍼 호출은 **다른 피연산자와 같다**: 한 번, 왼쪽부터 평가되고 `&&`·`||`는 단락하며 먼저 난 실패가 이긴다. + 시험 구현이 잰 것: `false && big(x)` → 호출하지 않음 · 문자열 연결 조각의 순서쌍 · `try` 인자 안의 헬퍼가 피호출자보다 먼저. + +### 2.4 `result` 뒤 — 자기 산술과 같다 (DP-P5) + +`-> [T]!`에서 `result n` 뒤의 헬퍼 호출이 넘치면 `DP-O6` 그대로다 — `*ml_needed`가 쓰였을 수 있고 버퍼는 정의되지 않는다. +**새 거부 규칙은 없다**(`try`와 달리 식 안의 호출이다). 시험 구현: `result[1] = sq(x)`와 `result[1] = x*x`가 같은 상태. + +### 2.5 바인딩 술어 — 한 집합 (DP-P6) + +`ir.rs`에 한 집합을 둔다 — **검사 집합**: `!` 본문에서 무한 함수들을 거쳐 닿고, 자기 본문이나 그 아래에 검사할 연산이 +있는 무한 함수. 이것을 **셋이 함께 읽는다**: + +- codegen — 이 집합의 함수에만 검사용 사본을 방출하고, `!` 본문과 사본은 집합 안의 함수를 사본으로 부른다. +- `.h`와 `.pas` — `ML_ST_OVERFLOW`를 선언하는 조건이 *"어떤 `!` 본문이 자기 검사 연산을 갖거나, 집합 안의 함수를 부른다"* 가 된다. + +한 술어를 셋이 읽는 것은 #238의 규칙이다. Grok 확인: 모듈이 `-3`을 내는 길은 `!` 본문의 연산이나 사본뿐이라 이 술어로 +충분하다(`try`로 부른 `!` 함수는 그 자신이 술어에 든다). + +### 2.6 방출 (DP-P7, DP-P8) + +- **이름은 `ml_ck_`**(DP-P7) — 사용자 함수는 언제나 `ml_fn_<이름>`이고 파라미터·지역 변수는 `ml_`로 시작할 수 없어, + 어떤 합법한 소스와도 겹치지 않는다. 시그니처는 원래 함수의 파라미터에 `Result` 반환. +- **참조되는 본문만 방출한다**(DP-P8): `ml_fn_`는 무한 본문·export 어댑터가 부를 때, `ml_ck_`는 `!` 본문이나 다른 + 사본이 부를 때만. `#![allow(dead_code)]`로 덮지 않는다 — 덮으면 호출자 없는 사본(과다 방출)도 숨는다(Grok). + 크레이트 머리의 `allow` 줄은 바꾸지 않는다. +- 결과: 이 슬라이스가 닿지 않는 모듈의 생성 Rust는 **글자 그대로 같다**(예제 골든 불변 — §3 H). + +### 2.7 지문과 ABI 버전 — 바뀌지 않는다 (DP-P9) + +`DP-O4`와 같다: 지문은 본문이 어느 예약 음수에 닿는지 보지 않는다. 시험 구현에서 모듈 9개의 `ml_iface_hash`· +`ml_module_abi_version`·export 이름 집합이 전부 같았다. 바인딩 텍스트에는 `ML_ST_OVERFLOW` 선언이 새로 붙을 수 있다 +(지문 밖이다). 같은 소스를 다시 컴파일하면 답이 바뀐다(wrap → `-3`) — `DP-O8`처럼 표시 없이, 문서에 적는다. + +### 2.8 탈출구 — 두지 않는다 (DP-P10) + +`DP-O7`의 *"무한 헬퍼가 의도한 wrap의 탈출구"* 는 사라진다. **대신할 것을 지금 두지 않는다**: 코퍼스 어디에도 의도한 wrap에 +기대는 헬퍼가 없다(§0.2). 필요해지면 `wrapping_add`/`_sub`/`_mul` 같은 내장 함수를 가산적으로 더한다 — 후보 목록에 적는다. +export를 탈출구로 남기는 안(§2.2의 반대)은 받지 않는다. + +### 2.9 알려진 결과 (기록) + +- 저자가 손으로 쓴 사후 가드의 **에러 코드가 바뀔 수 있다**: 헬퍼 호출 뒤 `if won < 0 { fail E_BAD_RESULT }`를 둔 모듈이 + 입력에 따라 `2`에서 `-3`으로(측정) — 그리고 그 가드가 놓치던 양수 wrap(`31397270`)도 `-3`이 된다. +- 체크드 산술의 대가(참값이 드는데 중간값만 넘쳐도 실패)가 헬퍼까지 넓어진다 — 표본에서 7행(§0.1). + +--- + +## 3. 수용 기준 (측정 가능) + +| # | 무엇 | 어떻게 잰다 | +|---|---|---| +| **A** | 세 반환 모양(`T!`·`string!`·`[T]!`)이 넘치는 헬퍼를 부르면 `-3`, 경계 바로 안은 정답. 사슬 깊이 3. `bool`·`f64` 헬퍼 | 오라클 값 | +| **B** | 같은 헬퍼를 무한 본문·호스트가 부르면 오늘과 같이 wrap | 오라클 값 | +| **C** | export 무한 함수를 `!` 본문이 부르면 `-3`, 호스트가 직접 부르면 wrap | 오라클 값 | +| **D** | 평가 순서: `&&`·`||` 단락, 순서쌍 둘(왼쪽 실패가 이긴다), `result` 뒤 | 오라클 값 | +| **E** | 바인딩: 헬퍼로만 `-3`에 닿는 모듈이 `.h`·`.pas` 둘 다 선언하고, 검사할 연산 없는 헬퍼만 부르는 모듈은 선언하지 않는다 — 한 술어 | 방출 텍스트 표(`bindings.rs` 행렬에 행 추가) | +| **F** | **실제 C 호스트가 헬퍼 경로의 `-3`을 받는다** | 수용 D(`host.c`) — 예제에 헬퍼를 넣는다(§6) | +| **G** | 빌드 견고성: (1) `fn mul` + `fn ck_mul` + `fn __twin_mul`을 한 모듈에 둔 소스가 빌드되고 값이 맞다(이름 충돌 없음). (2) 주변 `RUSTFLAGS=-D warnings`에서 snake_case 이름의 헬퍼를 `!`와 무한 본문이 함께 부르는 모듈이 빌드된다(쓰지 않는 본문이 없다) | 오라클 값 · `emit_robustness.rs` 행 | +| **H** | 닿지 않는 모듈은 생성 Rust가 글자 그대로 같다 — 예제 골든 불변(헬퍼를 넣는 예제 하나 제외), 지문·ABI 불변 | 골든 | +| **I** | §9-71의 626행을 구현본으로 다시 재어 시험 구현(twin)과 같은 표 | 측정 기록(가드 아님) | +| **J** | 문서 — `LANGUAGE.md`의 DP-O7 문장, `HOST_ABI.md` 현재 경계, 생성 `.h`/`.pas` 문구 | `doc_claims` | + +--- + +## 4. 설계 결정 (확인 요청) + +| DP | 결정 | 대안 | 근거 | +|---|---|---|---| +| **DP-P1** 규칙 | **호출 경로** — `!`를 위해 실행되는 산술은 어디서든 검사 | 본문(오늘) · 산술 있는 헬퍼에 `!` 강제 | **사용자 확인**(2026-09-26, F2). 강제안은 C 시그니처를 바꾸고 `try`가 문장 전용이라 식 호출을 다 다시 써야 한다 | +| **DP-P2** export 무한 함수 | **포함** — 내부에서 부를 때만, 어댑터는 그대로 | 제외(`export`가 탈출구) · 호출 거부 | 제외하면 export로 올리는 편집이 결과를 조용히 바꾼다(측정). Grok plan: YES | +| **DP-P3** 반환 타입 | **가리지 않는다**(`bool`·`f64` 헬퍼 포함) | i32 반환만 | 연산이 넘치는 것이지 반환 타입이 아니다(측정) | +| **DP-P4** 실패 시점 | **연산자에서 즉시** | 끝까지 wrap하고 반환 때 표시 | 체크드 산술과 같은 검사 자리. 즉시 실패가 wrap이 부르던 멈춤을 `-3`으로 바꾼다(측정) | +| **DP-P5** `result` 뒤 | **DP-O6 그대로**, 새 거부 없음 | `try`처럼 거부 | 채우기 루프 안의 모든 헬퍼 호출이 거부된다 | +| **DP-P6** 바인딩 술어 | **`ir.rs`의 한 집합**을 codegen과 `.h`·`.pas`가 함께 읽는다 | `header.rs`에 따로 걷기 · `!`가 있으면 무조건 선언 | #238의 규칙. Grok plan: 충분 | +| **DP-P7** 사본 이름 | **`ml_ck_`** | `__twin_` 같은 이름 예약(#101이 없앤 제약을 되살림) | 합법한 사용자 이름과 겹칠 수 없다. 시험 구현의 이름은 E0428로 충돌했다(측정) | +| **DP-P8** 방출 범위 | **참조되는 본문만** | `allow(dead_code)`로 덮기 | 덮으면 과다 방출이 숨는다(Grok plan). 참조만 방출하면 닿지 않는 모듈이 글자 그대로 같다 | +| **DP-P9** 지문·ABI | **둘 다 불변**, 이주는 표시 없이 문서에 | 매니페스트 표시 · ABI 올림 | DP-O4·O8과 같은 근거. 시험 구현 9모듈 동일(측정) | +| **DP-P10** 탈출구 | **두지 않는다** — `wrapping_*` 내장은 후보로 | 지금 내장 함수 · export를 탈출구로 · 헬퍼 표시 문법 | 의도한 wrap에 기대는 코드가 코퍼스에 0(측정). Grok plan: 뒤집기 수용 가능 | +| **DP-P11** 수용 D | **기존 예제에 내부 헬퍼를 넣는다**(지문 불변) | 새 예제 파일 | 예제에 이 모양이 0개다(측정). 내부 헬퍼는 지문에 들지 않는다 | + +--- + +## 5. 범위 밖 / 미검증 (명시) + +- **호스트가 직접 부르는 무한 함수의 오버플로와 멈춤** — 채널이 없다(D17). `!`를 붙이는 것이 저자의 길이다. +- **넓은 중간값**(§9-71.4) · **i64** · **탈출구 내장 함수**(§2.8) — 별도 후보. +- **성능** — 체크 분기와 `Result` 반환이 는다. 크기는 §0.4에서 쟀고, 실행 속도는 재지 않았다. +- 생성 Rust 전체의 `-D warnings` 청결 — 이 슬라이스는 **자기가 만드는 경고**(쓰지 않는 사본·본문)만 막는다. 이미 있는 + 것은 그대로 두고 기록한다: 사용자 함수 이름이 snake_case가 아니면(`fn a__b`) 오늘도 주변 `RUSTFLAGS=-D warnings`에서 + `non_snake_case`로 빌드가 깨진다(측정). 크레이트에 `allow`를 더하면 모든 모듈의 생성 Rust가 바뀌어 §3 H와 부딪히므로 + 따로 정한다. 다른 기존 경고(예: 쓰지 않는 문자열 헬퍼)도 같다. + +--- + +## 6. 작업 분해 (확인 후) + +| 작업 | 수용 | 크기 | +|---|---|---| +| 1. `ir.rs` 검사 집합 · codegen 사본(`ml_ck_`, 참조만 방출) · `.h`/`.pas` 술어 · 경고 · 골든 · 컴파일러 테스트 · 오라클 값 · 문서 | A · B · C · D · E · G · H · J | 한 PR | +| 2. 예제에 헬퍼를 넣고 실제 C 호스트가 `-3`을 받는다 · §9-71의 626행 재측정 · 슬라이스 닫기 | F · I | 한 PR |