From 24aa0f3d78dd8d955081120796ee4369df74d2fa Mon Sep 17 00:00:00 2001 From: xzawed <47019855+xzawed@users.noreply.github.com> Date: Sat, 26 Sep 2026 15:02:27 +0900 Subject: [PATCH 1/2] =?UTF-8?q?docs:=20Q17=20stays=20open=20with=20(A)=20?= =?UTF-8?q?=E2=80=94=20the=20encoding=20risk=20goes=20where=20a=20host=20a?= =?UTF-8?q?uthor=20reads=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User confirmed Q17 (A) on 2026-09-26: DP-S2 is not reopened and DECISIONS.md does not change. What (A) asks for is the risk in writing, so HOST_ABI.md's string-parameter contract item 4 now carries the §9-69.3 measurements: a byte_len limit that passes on a CP949 host and refuses on a UTF-8 one, a returned literal concatenated to CP949 input giving mixed bytes (so the generated "RETURNS UTF-8 bytes" notice holds only for UTF-8 input), the EUC-KR counter-example, and that the .pas "CORRECT" row was measured with ASCII only. It also stops saying source literals are ASCII-only: that holds for compared literals since non-ASCII return literals exist. Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/HOST_ABI.md | 19 +++++++++++++++++-- docs/OPEN_QUESTIONS.md | 3 ++- docs/STATUS.md | 1 - docs/slices/README.md | 2 +- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/HOST_ABI.md b/docs/HOST_ABI.md index 2b6ef43..6c99dad 100644 --- a/docs/HOST_ABI.md +++ b/docs/HOST_ABI.md @@ -164,8 +164,23 @@ int ml_module_set_host_fn(MlModule*, const char* name, void* fn); > 지키고 있었다. 4. **인코딩은 호스트 계약이다.** 모듈은 **바이트만** 본다 — `==`는 NUL까지의 바이트 동등성이고, 대소문자를 구분하며 정규화하지 않는다(DP-S2). 호스트가 넘기는 바이트와 `.mls` 소스에 쓴 - 리터럴의 바이트가 같은 인코딩이어야 한다. 소스 리터럴은 **ASCII만** 허용하므로, ASCII 범위에서는 - UTF-8·Latin-1·대부분의 코드 페이지가 일치한다. + 리터럴의 바이트가 같은 인코딩이어야 한다. **비교하는** 소스 리터럴은 **ASCII만** 허용하므로(비ASCII + 리터럴은 반환에만 — 위 "현재 구현된 경계"), ASCII 범위에서는 UTF-8·Latin-1·대부분의 코드 페이지가 일치한다. + - **⚠ ASCII 밖에서는 같은 모듈이 호스트의 코드 페이지에 따라 다른 답을 status `0`으로 낸다** + (2026-09-26, `HISTORY.md` §9-69.3). 한국어 ANSI 기계(`GetACP() = 949`)에서 로드한 모듈에 CP949 + 바이트를 넣어 잰 값: + - `byte_len`으로 쓴 길이 제한 — `가`×34는 UTF-8로 102바이트, CP949로 68바이트다. 100바이트 한도가 + UTF-8 호스트에서는 거부하고 CP949 호스트에서는 **통과**한다. + - 입력에 비ASCII **반환 리터럴**을 이으면 결과는 **호스트의 CP949 바이트 + 리터럴의 UTF-8 바이트**다. + 생성 `.h`·`.pas`의 *"This module RETURNS UTF-8 bytes"* 는 **입력이 UTF-8일 때만** 참이고, 그 + 결과는 어느 코드 페이지로 읽어도 한쪽이 깨진다(측정한 바이트: UTF-8로 읽으면 입력 이름이, CP949로 + 읽으면 리터럴이 깨진다). + 모듈의 답은 E2이고, Delphi의 `AnsiString(S)`가 시스템 ANSI 코드 페이지로 바꾸는 단계는 E1이다 — + 아래 5번 표의 "맞다"는 **ASCII 값(`"UPSN"`)으로만** 잰 것이다. + - **반대 방향의 규칙도 같은 표본에서 나왔다**: SMS·LMS 경계처럼 **EUC-KR 바이트로 정의된 업무 규칙**은 + CP949로 보낼 때만 맞는다(측정). 그래서 이 계약은 인코딩을 하나로 정하지 않는다(`OPEN_QUESTIONS.md` Q17 (A)). + - **호스트 규칙: 모듈의 바이트 규칙이 어느 인코딩을 전제하는지 모듈 저자와 맞추고, 모든 호출에서 그 + 인코딩 하나로 보낸다.** 헤더는 그것을 말해 주지 않는다. 5. **⚠ Delphi 함정 (E2 — 2026-09-10 실측, Delphi CE 37.0 Win64).** Delphi의 기본 `string`은 UTF-16 `UnicodeString`이다. **어떤 캐스트를 쓰느냐가 결과를 가른다.** `"UPSN"`을 이 ABI로 실제로 보내며 잰 것이다(`hosts/delphi-host/host.dpr`, `MATHLESS_GATE_DELPHI`): diff --git a/docs/OPEN_QUESTIONS.md b/docs/OPEN_QUESTIONS.md index 7a9f2fe..b1e7ea8 100644 --- a/docs/OPEN_QUESTIONS.md +++ b/docs/OPEN_QUESTIONS.md @@ -71,7 +71,8 @@ ABI 정수 상태코드+out-param, 표면 Result는 sugar. 남은 하위 → Q13 | (C) 파라미터별 코드 페이지 선언 | 두 부류의 규칙을 다 쓸 수 있다 | 표면이 는다. 혼합 바이트(CP949 이름에 UTF-8 리터럴을 잇기)는 모듈 쪽 변환 없이 여전히 틀린다 — 할당자가 없다 | **권고 (A) — 재검토 조건**: 비ASCII **비교**나 **문자 단위 길이**가 필요한 슬라이스를 고를 때 이 표로 돌아온다. - ⏳ **사용자 확인 대기(2026-09-26).** + ✅ **2026-09-26 사용자 확인: (A).** 결정이 아니라 **열어 두는 것**이므로 `DECISIONS.md`도 DP-S2도 + 바뀌지 않는다. 위험은 `HOST_ABI.md` "문자열 파라미터 계약" 4번에 적었다. - Q12. 반환 값 소유권 규약 — **닫힘(2026-08-31)**: 사용자 확정으로 **(a) caller-allocates out-buffer**. 가변 길이 데이터는 **호스트가 버퍼와 용량을 주고, 모듈이 채우고, 필요한 길이를 돌려준다**. 절단은 **D17의 음수 예약 status**로 보고한다 — "성공했는데 짧다"가 아니라 명시적 실패다. diff --git a/docs/STATUS.md b/docs/STATUS.md index cabe78e..17e87fb 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -236,7 +236,6 @@ > 1. **체크드 정수 산술 — 구현 중.** DP-O1~O9 전부 사용자 확인(2026-09-26). `docs/slices/SPEC-checked-arithmetic.md` > §6의 작업 1(codegen·바인딩·오라클 값·문서)이 들어갔고, **작업 2가 남았다** — 실제 C 호스트가 `-3`을 받는 수용 D, > §9-69의 161행 재측정, 크기 변화, 그리고 슬라이스 닫기. -> 같은 날 인코딩 질문은 `OPEN_QUESTIONS.md` **Q17**로 올렸다(권고 (A) — 사용자 확인 대기). > 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 03b0d05..8b8f2fb 100644 --- a/docs/slices/README.md +++ b/docs/slices/README.md @@ -126,7 +126,7 @@ TDD 구현 → Grok 검증 → PR** 순서를 따른다(`CLAUDE.md` "개발 방 **인터페이스 정의 파일**(설계부터)과 **개발/배포 빌드 분리**(D13, `SECURITY.md` P1). *(2026-09-25 로드맵 검토에서 더했다 — Phase 2의 다섯 항목 중 이 둘이 이 목록에 없었다.)* §7(§9-69, 12개 도메인 72규칙과 귀속 대조)이 더한 후보: **체크드 정수 산술**(가장 강한 근거 — 확정되어 -구현 중이다, 위 색인), **i64**, **입력 문자열의 인코딩 계약**(닫힌 DP-S2의 재개 — 설계 질문, §9-69.3), 비트 연산자, +구현 중이다, 위 색인), **i64**, **입력 문자열의 인코딩 계약**(닫힌 DP-S2의 재개 — `OPEN_QUESTIONS.md` Q17이 (A)로 열어 두었고 재검토 조건은 거기 있다), 비트 연산자, 지역 작업 배열, 수학 내장 함수, 문자 단위 길이. **struct는 §9-1이 강제되지 않는다고 결론냈다** — 고르려면 그 절을 먼저 읽는다(§9-69도 귀속 0으로 다시 확인했다). 배열도 같은 결론이었고(§9-9가 다섯 번째로), **입력은 그 사실을 SPEC 첫 절에 적은 채로 열렸다**. From 724f33fecbb7af2df5736d3b3d039ba1e6a9c31d Mon Sep 17 00:00:00 2001 From: xzawed <47019855+xzawed@users.noreply.github.com> Date: Sat, 26 Sep 2026 15:11:31 +0900 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20=C2=A79-69.3=20carries=20the=20rule?= =?UTF-8?q?=20texts=20and=20values=20HOST=5FABI=20now=20cites?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Grok verify found the 100-byte limit and the CP949-only SMS result stated in HOST_ABI.md with no in-repo source; both were in the measurement data only. Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/history/9-69.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/history/9-69.md b/docs/history/9-69.md index f901229..24aba04 100644 --- a/docs/history/9-69.md +++ b/docs/history/9-69.md @@ -59,6 +59,14 @@ A+as에도 남는 60행: 무한(`-> i32`) 헬퍼 16 · 무한 export 본문 4( 조건은 *대소문자 무시·정규화*다 — 이번 근거는 그 조건과 다르므로, 재개하려면 그 사실부터 적어야 한다. 또 *UTF-8 전용* 으로 정하면 EUC-KR 바이트 단위 규칙(SMS 길이)이 모든 준수 호스트에서 틀린다는 반례가 같은 도메인에서 나왔다. +규칙과 잰 값(Q17 (A)가 `HOST_ABI.md` 문자열 파라미터 계약 4번에 옮긴 것의 근거 — 같은 날 덧붙였다): + +| 규칙 | UTF-8 입력(mlprobe) | CP949 입력(ctypes, `GetACP() = 949`) | +|---|---|---| +| NA-R1 상세주소 — **UTF-8 100바이트** 이하면 바이트 수, 넘으면 `E_TOO_LONG` | 가×33(99B) → 99 · 가×34(102B) → status 1 | 가×34(68B) → **status 0** | +| NA-R3 SMS/LMS — **EUC-KR 90바이트**(한글 45자) 이하 SMS, 2000바이트 이하 LMS | 가×45 → LMS(**틀림**) | 가×45 → SMS · 가×46 → LMS · 가×1001 → `E_TOO_LONG`(전부 맞음) | +| NA-R5 인사말 = 이름 + 반환 리터럴 `" 고객님"` | 홍길동 → 맞음 | 출력 = CP949 이름 바이트 + UTF-8 리터럴 바이트 — UTF-8로 읽으면 이름이, CP949로 읽으면 리터럴이 깨진다 | + #### 9-69.4. 고친 것 — PR 셋 | PR | 결함(전부 E2로 재현) |