aboutsummaryrefslogtreecommitdiffstats
path: root/docs/design
diff options
context:
space:
mode:
Diffstat (limited to 'docs/design')
-rw-r--r--docs/design/001-operation-semantics.md126
-rw-r--r--docs/design/002-memory-lifetime.md135
-rw-r--r--docs/design/003-module-contract.md119
-rw-r--r--docs/design/004-prepared-connections.md39
-rw-r--r--docs/design/005-field-connections.md28
-rw-r--r--docs/design/006-native-protocol.md139
-rw-r--r--docs/design/007-execution-domains.md222
-rw-r--r--docs/design/abi-v0.h76
-rw-r--r--docs/design/check-abi-layout.py46
-rw-r--r--docs/design/validation/2026-09-22-record-layout.json80
10 files changed, 1010 insertions, 0 deletions
diff --git a/docs/design/001-operation-semantics.md b/docs/design/001-operation-semantics.md
new file mode 100644
index 0000000..ae2ed5d
--- /dev/null
+++ b/docs/design/001-operation-semantics.md
@@ -0,0 +1,126 @@
+# 연산 의미 초안 0.1
+
+상태: **다음 구현을 위한 명세**. 현재 제작 도구의 문법·실행기를 변경하지 않는다.
+아래에서 `현재`는 구현을 확인한 동작, `제안`은 후속 구현의 요구조건이다.
+현재 동작의 기준은 [Workbench 계약](../../prototypes/workbench/CONTRACT.md)이다.
+
+## 1. 연산의 구분
+
+| 종류 | 읽고 바꾸는 것 | 실패의 의미 |
+|---|---|---|
+| 순수 계산 | 명시적인 값·읽기 전용 데이터 | 결과 없음; 외부 효과 없음 |
+| 상태 전이 | 한 실행 영역의 관리 상태 | 확정 전 실패는 이전 관리 상태 유지 |
+| 버퍼 변환 | 입력 구간, 독점 출력 구간, 변환 문맥 | 이번 호출의 유효 출력과 문맥의 재사용 가능 여부를 명시 |
+| 외부 작업 | 파일·네트워크·장치·시계 등 | 이미 발생한 효과가 남을 수 있음; 실제 완료로 보고 |
+
+이 구분은 제안이다. 현재 코어에는 앞의 두 종류와 순수한 표시 계산만 있다.
+비용이나 실패 의미가 다른 작업을 모두 숫자 함수처럼 처리하지 않는다.
+재계산 가능한 연산은 첫 종류로 제한한다. 파일 쓰기·난수 획득·작업 제출은 재계산으로 반복하지 않는다.
+
+## 2. 현재 숫자 규칙과 확장 경계
+
+현재 상태는 유한한 `f64`다. 대입과 같은 이벤트의 핸들러는 소스 순서로 실행한다.
+`if` 조건은 한 번 계산하며 `&&`·`||`는 양쪽을 모두 평가한다.
+0 나눗셈, 유한하지 않은 계산 결과, 스택·분기 오류는 이벤트 전체의 숫자 상태 변경을 취소한다.
+표시 표현식은 상태·이벤트 진단을 변경하지 않는다.
+
+현재 시간 입력은 프레임당 1/60초, 일반 입력에서 0이다.
+이는 작은 화면 실험의 규칙이다. 서버의 시계나 미디어 타임스탬프에 60Hz를 강제하는 계약이 아니다.
+후속 시간·난수·외부 완료는 명시적인 입력 기록으로 전달한다.
+
+제안하는 데이터 경계 규칙:
+
+- 바이트·버퍼 길이·오프셋·식별자는 정수로 다룬다. `f64`를 경유해 큰 정수의 정확성을 잃지 않는다.
+- 길이·메모리 계산은 검사된 정수 연산을 사용한다. 넘치면 오류다. 축약·순환 연산은 별도 명시가 있어야 한다.
+- 정수 폭, 바이트 단위, 정렬 요구와 변환 가능 범위를 각 연산에 기록한다.
+- 부동소수점 확장은 연산 순서, 반올림·서브노멀·부호 있는 0 처리와 허용 오차를 명시한 뒤 추가한다.
+ 현재 테스트는 모든 네이티브 타깃의 비트 단위 일치를 증명하지 않는다.
+- 기존 논리 연산을 단락 평가로 바꾸는 일은 의미 변경이다. 최적화라는 이름으로 조용히 바꾸지 않는다.
+
+Wasm의 수치 형식은 IEEE 754의 이진 형식과 부호 있는 0·NaN 등을 정의한다.
+Pure가 허용하는 값·오류와 재생 비교 규칙은 그 위에 별도로 정해야 한다.
+[WebAssembly 값 명세](https://webassembly.github.io/spec/core/syntax/values.html#floating-point)
+
+## 3. 관리 상태 확정과 외부 작업 제출 — 제안
+
+한 이벤트에서 다음 순서를 지킨다.
+
+1. 관리 상태의 다음 값을 계산하고, 필요한 버퍼 대여·요청 슬롯·완료 슬롯을 예약한다.
+ 준비 중에는 외부 작업을 시작하거나 공유 출력 버퍼를 변경하지 않는다.
+2. 검사·예약이 실패하면 준비한 자원을 반납하고 이전 관리 상태를 유지한다.
+3. 성공하면 관리 상태와 준비된 작업 목록을 함께 확정한다. 이 단계는 외부 작업의 성공을 의미하지 않는다.
+4. 어댑터가 확정된 작업을 실제로 제출한다. 제출 실패도 완료 사건으로 전달한다.
+5. 완료 사건을 후속 상태 전이의 입력으로 처리한다. 재시도·보상·사용자 알림은 앱의 명시적 정책이다.
+
+이미 확정·제출된 파일 쓰기를 이후 이벤트의 실패로 되돌렸다고 보고하지 않는다.
+처리 중 프로세스가 종료되는 경우의 내구성·중복 실행 방지는 이 메모리 내 계약에 포함하지 않는다.
+영속 작업에는 이후 별도 로그·식별자·복구 계약이 필요하다.
+
+## 4. 바이트 스트림 연산 — 첫 모듈 프로파일 제안
+
+첫 프로파일은 입력 구간 하나, 출력 구간 하나, 유지되는 문맥 하나를 받는다.
+각 입력 구간은 유효 데이터 길이, 출력 구간은 쓸 수 있는 용량을 나타낸다.
+v0 출력은 유효 길이가 0인 독점 버퍼이며 출력 오프셋은 0이다. 접두부의 유효 길이는
+완료 회수 시 `produced`로 교체한다. 기존 데이터에 덧붙이기·덮어쓰기는 이 프로파일에 없다.
+한 번에 최대 32비트 길이의 구간을 다루며 전체 스트림의 누적 길이는 검사된 64비트 정수로 센다.
+파일 전체를 한 버퍼에 넣어야 한다는 뜻은 아니다.
+
+반환값은 `consumed`, `produced`, `status`, `error`다.
+
+- `consumed`는 이번 입력 구간에서 다시 제공하지 않아도 되는 접두부 길이다.
+- `produced`는 출력 구간 시작에서 후속 작업이 사용할 수 있도록 확정된 접두부 길이다.
+ 임시로 쓴 바이트·내부 복사량과 다르다. 나머지 출력 용량은 유효 데이터가 아니다.
+- 각 길이는 제공된 구간 길이 이하여야 한다. 이전 호출의 양을 다시 포함하지 않는다.
+- 입력 소비와 출력 생성은 서로 독립적이다. 입력을 다 소비해도 출력·종료 처리가 남을 수 있다.
+- v0은 입력·출력에 같은 버퍼를 사용하는 것을 거절한다. 제자리 변환은 별도 협상할 확장이다.
+- 요청 하나의 완료와 스트림 전체의 완료는 다르다. `NEED_INPUT/NEED_OUTPUT/MORE`를
+ 반환한 요청도 대여를 종료하지만, 해당 스트림 문맥은 다음 요청을 위해 열린 상태로 남는다.
+
+| 상태 | 의미와 다음 행동 |
+|---|---|
+| `MORE` | 진전이 있었으며 다시 호출할 수 있음. 양쪽 길이가 0이면 사용할 수 없음 |
+| `NEED_INPUT` | 아직 끝나지 않음. 새 입력 또는 입력 종료 통지를 기다림 |
+| `NEED_OUTPUT` | 미처리 입력이나 내부 출력이 남음. 새 출력 용량을 마련하고 남은 입력부터 재개 |
+| `DONE` | 이 문맥의 스트림 완료. 입력 종료를 단순히 소비했다는 뜻과 다름 |
+| `FAILED` | 문맥 종료. 오류 코드 필수, 부분 소비·검증된 출력이 있으면 정확히 보고 |
+| `CANCELLED` | 최종 취소 완료. 이미 검증·공개된 부분이 있으면 정확히 보고 |
+
+종료 통지 `END_INPUT`은 마지막 입력 뒤에 더 이상 입력이 없다는 약속이다.
+부분 소비 시 남은 입력과 이 플래그를 함께 재제공한다. 마지막 입력을 모두 소비한 뒤에도
+`NEED_OUTPUT`이면 빈 입력·같은 플래그·새 출력으로 종료 처리를 계속한다.
+`END_INPUT`이 설정된 호출에서는 `NEED_INPUT`을 반환하지 않는다. 더 읽어야 하는 잘린 데이터면 `FAILED`다.
+`DONE`에 미소비 입력이 있으면 호출자가 다음 스트림·후행 데이터 정책을 결정한다.
+`DONE/FAILED/CANCELLED` 문맥은 후속 `step`을 받지 않으며 닫기만 허용한다.
+
+Zstd는 입력·출력 위치와 종료 진행을 따로 보고하며 내부 윈도 메모리도 필요로 한다.
+이 자료는 위 프로파일을 설계하는 근거이며 Zstd의 API를 Pure의 보편 규칙으로 간주하지 않는다.
+참조한 매뉴얼은 1.5.1이고 채택할 라이브러리 버전은 아직 결정하지 않았다.
+[Zstandard 스트리밍 매뉴얼](https://facebook.github.io/zstd/zstd_manual.html#Chapter7)
+
+## 5. 부분 성공과 인증
+
+위 스트림 프로파일은 바이트 변환의 결과다. 파일·네트워크 출력은 별도 효과 결과로
+실제로 전달한 바이트 수를 보고해야 한다. 변환의 `produced`를 파일에 저장된 양으로 재사용하지 않는다.
+
+인증 복호화 어댑터는 성공한 인증 단위의 평문만 유효 출력으로 공개한다.
+현재 단위의 인증에 실패하면 그 단위의 `produced`는 0이고 임시 평문은 공개하지 않는다.
+이전 호출에서 인증·공개된 단위까지 되돌렸다고 주장하지 않는다.
+단위 크기와 보류 버퍼에 예산을 두고 검증된 라이브러리의 계약을 따른다.
+암호 알고리즘을 이 명세에서 새로 정의하지 않는다.
+[libsodium 인증 암호화 API](https://doc.libsodium.org/secret-key_cryptography/secretbox)
+
+## 6. 컴파일러가 감당하는 작업
+
+현재 한도는 소스 32,768바이트, 상태 32개, 입력 8개, 출력 24개, 핸들러 64개,
+중간 명령 512개, 스택 64칸이다. JS 파서·AST·맵의 실제 최대 힙은 아직 측정되지 않았다.
+
+제안: 코어 연산 집합은 버전으로 관리하고 코덱·문서·미디어 라이브러리는 모듈로 연결한다.
+라이브러리마다 새 문법·타입별 특수화·컴파일타임 실행을 추가하지 않는다.
+모듈 호출 한 개가 적은 작업이라는 가정도 하지 않는다. 데이터 구간·문맥 메모리·한 호출의
+최대 작업량을 별도로 제한한다. 중단할 수 없는 라이브러리 호출에는 엄격한 CPU 시간 보장을 표기하지 않는다.
+
+추가 기능마다 컴파일러 산출물 크기, 빌드 시간, 피크 메모리, 생성 코드 크기와 실행 비용을 분리 측정한다.
+초기 확장에는 전역 타입 추론·사용자 컴파일타임 실행·제한 없는 특수화를 도입하지 않는다.
+특수화가 필요해지면 적용 대상을 제한한 후보와 공통 코드 후보를 비교한다.
+이는 Pure의 설계 선택이다. Rust는 타입별 코드 생성의 이득과 빌드 시간·바이너리 크기 비용을 문서화한다.
+[Rust 단형화 문서](https://rustc-dev-guide.rust-lang.org/backend/monomorph.html)
diff --git a/docs/design/002-memory-lifetime.md b/docs/design/002-memory-lifetime.md
new file mode 100644
index 0000000..a706a36
--- /dev/null
+++ b/docs/design/002-memory-lifetime.md
@@ -0,0 +1,135 @@
+# 메모리와 데이터 수명 초안 0.1
+
+상태: **제안, 실행기 미구현**. 현재 Workbench에는 바이트 버퍼·비동기 완료 큐가 없다.
+이 문서는 [연산 의미](001-operation-semantics.md)를 구현할 때의 불변조건과 회수 규칙을 정한다.
+
+## 1. 예산의 소유자
+
+각 실행 영역에 바이트 예산과 객체·요청 개수 예산을 부여한다. 영역의 소유자는 런타임이다.
+첫 구현 후보는 고정 크기 청크 풀과 세대 번호를 가진 핸들 테이블이다.
+장기 상태·스트림 문맥·작업 임시 공간은 수명이 달라 별도 항목으로 센다.
+이 정책이 최적이라고 가정하지 않으며 일반 할당 방식과 같은 작업으로 비교한다.
+
+| 계측할 공간 | 반드시 포함할 것 |
+|---|---|
+| 확보한 backing 용량 | 사용 중인 청크와 비어 있지만 보유 중인 청크, 정렬·단편화 |
+| 메타데이터 | 핸들·대여·문맥·작업·완료·대기열 슬롯 |
+| 살아 있는 데이터 | 앱·소비자·진행 중 작업이 여전히 참조하는 실제 버퍼 |
+| 모듈 내부 공간 | 코덱 윈도·사전·파싱 상태·작업 공간·라이브러리의 자체 할당 |
+| 교체 중 공간 | 이전 코드·문맥·진행 중 작업과 다음 프로그램의 준비 공간 |
+| 외부 자원 | 별도 호스트 힙·OS·GPU 자원과 추적할 수 없는 할당 |
+
+같은 물리 버퍼를 여러 독자가 대여해도 물리 용량은 한 번만 센다.
+물리 용량과 사용량은 포함 관계이므로 합산하지 않는다. 모듈이 예산 밖에서 할당하면
+그 공간을 보고서에서 제외하지 않고 외부·미계측으로 표시하며 전체 상한 보장을 중단한다.
+요청별 예산을 만들었다고 라이브러리의 숨은 할당이 자동 통제되는 것은 아니다.
+풀에서 할당한 모듈 작업 공간·메타데이터는 그 풀 확보 용량의 세부 귀속 항목이다.
+풀 용량에 다시 더하지 않는다. 확보 용량은 할당한 backing의 크기이며 OS의 상주 RAM 측정값과 다르다.
+
+현재 64 KiB는 Wasm 선형 메모리의 초기·최대 용량이다. JS 호스트·컴파일러·렌더러까지
+포함한 전체 예산이 아니다. 새 버퍼 풀을 그 공간 밖에 만들면 별도로 포함해야 한다.
+
+## 2. 버퍼 식별과 범위
+
+`BufferHandle = (slot:u32, generation:u32)`를 첫 후보로 정한다. 포인터·파일 오프셋이 아니다.
+세대 0은 무효, 처음 발급은 1이다. 슬롯 재사용마다 세대를 증가시키고 최댓값에 도달한 슬롯은
+회수 후 영구 퇴역한다. 순환으로 오래된 핸들이 다시 유효해지지 않게 한다.
+핸들은 발급한 실행 영역 안에서만 의미가 있다. 다른 영역으로 숫자만 복사해 전달할 수 없다.
+
+구간은 핸들과 `offset:u32, length:u32`다. 런타임은 다음을 검사한다.
+
+- 현재 세대·소유자·요청자 권한·접근 모드가 일치한다.
+- 읽기는 현재 유효 데이터 길이, 쓰기는 예약 용량 안에 있다.
+- `offset <= bound`를 먼저 확인하고 `length <= bound - offset`을 검사해 덧셈 오버플로를 피한다.
+- 정렬 요구를 충족한다. v0 바이트 프로파일의 기본 정렬은 1이며 더 큰 정렬은 모듈 설명에 명시한다.
+- v0 출력 버퍼는 현재 유효 길이 0, 출력 구간 오프셋 0이어야 한다. 접수 때 암묵적으로
+ 이전 데이터를 버리지 않는다. 소비가 끝난 뒤 대여가 없는 소유자가 명시적으로 유효 길이를 0으로
+ 줄여 재사용한다. 유효 길이를 늘리는 일은 검증된 쓰기 완료·유효 출력 공개로만 허용한다.
+
+같은 프로세스의 임의 네이티브 코드로부터 메모리를 격리하는 기능은 아니다.
+이 계약의 첫 대상은 계약을 지키는 내부 모듈이다. 불신 모듈의 격리는 별도 실행 경계가 필요하다.
+
+## 3. 소유권과 대여
+
+한 버퍼에는 소유자 하나가 있으며 런타임이 대여 기록을 관리한다.
+복사 없는 전달의 후보는 버퍼 내용 대신 이 소유권 또는 읽기 대여를 넘기는 것이다.
+
+| 상태 | 허용하는 일 | 금지하는 일 |
+|---|---|---|
+| 소유, 대여 없음 | 읽기·독점 쓰기·소유권 이전·반납 | 범위 밖 접근 |
+| 읽기 대여 1개 이상 | 대여받은 독자의 읽기, 추가 읽기 대여 | 쓰기·소유권 이전·재사용·반납 |
+| 독점 쓰기 대여 1개 | 지정된 작성자의 범위 내 쓰기 | 다른 읽기·쓰기·이전·재사용·반납 |
+| 반납 완료 | 같은 슬롯의 새로운 세대로 재할당 가능 | 이전 핸들 접근 |
+
+첫 구현은 **서로 다른 구간이라도 버퍼 전체 단위로 대여**한다. 구간별 동시 쓰기나
+동적 겹침 증명은 후속 연구다. 읽기·쓰기 대여가 동시에 존재하지 않는다는 조건을 단순하게 유지한다.
+
+모듈 호출을 위해 해석한 실제 포인터는 허용된 접근 기간에만 유효하다. 동기 백엔드는 함수 반환 후
+포인터를 사용하지 않는다. 비동기 백엔드는 최종 완료 게시 전에 접근을 끝낸다.
+런타임에 접수된 요청의 대여는 백엔드의 동기·비동기 여부와 관계없이 **완료 회수까지 유지**한다.
+모듈이 계속 데이터를 보유해야 한다면
+자체 문맥에 예산을 잡아 복사하거나, 별도의 추적 가능한 장기 대여가 필요하다.
+첫 프로파일은 호출 종료 뒤 입력·출력 포인터를 숨겨 보유하는 것을 금지한다.
+
+`반납`은 대여가 있으면 `BUSY`로 실패하고 소유권을 유지한다. 암묵적 지연 반납을 만들지 않는다.
+비밀 데이터 버퍼의 지우기는 마지막 접근이 끝난 뒤 수행하며 사용한 라이브러리의 보장·한계와
+복사본의 수명까지 별도로 확인한다. 단순히 슬롯 번호를 지우는 것으로 데이터 삭제를 주장하지 않는다.
+
+## 4. 비동기 요청의 수명
+
+첫 계약은 한 실행 영역의 직렬 제어 흐름을 사용한다. 모듈의 worker는 완료를 게시하고
+상태·핸들 테이블의 회수는 영역 소유자가 수행한다. 제어 API의 재진입을 허용하지 않는다.
+스트림 문맥 하나에는 진행 중 호출을 최대 하나만 허용한다.
+
+```text
+준비 → 런타임 접수 거절 : 예약 해제, 티켓 없음
+준비 → 런타임 접수/확정 → 백엔드 제출 → 완료 게시 → 완료 회수
+ → 취소 요청 → 완료 게시 → 완료 회수
+```
+
+- 접수 전 요청 슬롯·대여 슬롯·완료 보관 슬롯을 함께 확보한다. 실패하면 `WOULD_BLOCK` 또는 `LIMIT`이다.
+- 런타임 접수 전 거절은 입력·출력·문맥을 바꾸지 않는다. 접수된 요청에는 세대가 붙은 티켓 하나를 발급한다.
+ 이벤트 안의 접수는 준비된 관리 상태와 함께 확정한다. 실제 백엔드 제출은 그 이후다.
+ 백엔드 제출 거절은 기존 티켓의 실패 완료로 보고하며 티켓 없는 거절로 되돌리지 않는다.
+- 모든 접수된 요청은 성공·실패·취소 중 하나의 최종 완료로 정리해야 한다.
+ 실제 백엔드가 응답하지 않을 수 있으므로 유한 시간 안에 완료된다는 보장은 별도다.
+- 즉시 완료해도 제출 호출 안에서 앱 콜백을 재진입하지 않고 완료 큐로 전달한다.
+- 취소 호출은 **요청**이다. 거절되거나 정상 완료와 경합할 수 있다. 버퍼를 반납할 권한을 주지 않는다.
+- 완료 게시 뒤에도 앱이 완료를 회수하기 전에는 해당 요청의 대여·슬롯을 보유한다.
+- 완료 회수는 티켓·모듈 세대·길이·상태를 검증하고 유효 출력 길이와 문맥 상태를 반영한 뒤
+ 대여·요청 슬롯을 한 번만 해제한다. 중복·오래된 완료는 진단하고 두 번 반납하지 않는다.
+ v0은 출력 버퍼의 유효 길이를 해당 요청의 `produced`로 설정한다. 실패·취소도 동일하며
+ 물리적으로 썼지만 검증되지 않은 꼬리 부분은 공개하지 않는다.
+- 중복 완료를 무시하는 것만으로 잘못된 백엔드의 추가 메모리 쓰기가 안전해지는 것은 아니다.
+ 모듈은 완료 게시 전에 작업·worker·장치의 접근 종료와 필요한 동기화를 보장해야 한다.
+- 제한 시간 초과만으로 메모리를 재사용하지 않는다. 실제 접근이 종료됐다는 백엔드의 보장까지 보유한다.
+
+libuv도 취소 요청 후 완료 콜백 전에는 요청 관련 메모리를 해제하면 안 된다고 명시한다.
+이 원칙을 Pure의 대여·티켓 상태에 반영했다. 취소에 외부 효과의 롤백을 포함하지 않는다.
+[libuv 요청·취소 계약](https://docs.libuv.org/en/v1.x/request.html#c.uv_cancel)
+
+## 5. 포화·느린 소비자·교체
+
+요청·완료·버퍼 슬롯이 없으면 생산자에게 역압력을 반환한다. 완료를 조용히 버리거나
+대기 요청을 무제한 늘리지 않는다. 앱은 재시도 시점·거절·명시적 버리기 정책을 선택한다.
+대여를 오래 유지하는 소비자는 메모리를 붙잡는다. 복사량뿐 아니라 유지 용량과 바이트×시간을 센다.
+소유권 전달을 했다는 사실만으로 GPU·드라이버·프로세스 경계의 복사가 없어졌다고 주장하지 않는다.
+
+프로그램·모듈 교체의 첫 정책은 **관련 진행 작업·대여·열린 문맥이 있으면 `BUSY`로 거절**하는 것이다.
+작업을 배출하고 명시적으로 문맥을 닫은 뒤 교체한다. 시간 초과로 강제 언로드하지 않는다.
+다중 버전을 동시에 유지하는 무중단 교체는 첫 계약 밖이다.
+현재 이름 기반 숫자 상태 보존은 파일 핸들·코덱 문맥·키·GPU 자원의 자동 이전을 뜻하지 않는다.
+
+## 6. 구현 시 필수 확인
+
+아직 통과한 검사가 아니라 다음 구현의 합격 조건이다.
+
+1. 버퍼 2개와 요청 1개로 여러 번 제출·완료·반납해 슬롯 수와 예산이 보존된다.
+2. 포화된 제출은 상태·유효 길이·소유권을 변경하지 않는다.
+3. 취소 요청만 받은 출력 버퍼는 다른 읽기·쓰기·반납이 거절된다. 입력 버퍼의 공유 읽기는
+ 가능하나 쓰기·반납은 거절된다. 관련 문맥·모듈 교체도 거절되고 최종 완료 회수 전에는 해제하지 않는다.
+4. 늦은 완료·중복 완료·해제된 세대의 핸들이 새 버퍼를 회수하거나 수정하지 않는다.
+5. 실패 출력은 명시한 유효 접두부만 공개한다. 인증 실패 단위에서는 유효 길이가 0이다.
+6. 입력 소비 완료 후 남는 출력·종료 처리가 정확히 진행된다. 느린 소비자에서 사용량이 예산을 넘지 않는다.
+7. 길이·누적 크기 넘침, 세대 소진, 할당 실패를 명시적으로 처리한다.
+8. 모듈 내부 공간과 대기 작업까지 포함한 피크를 계산하고 외부 할당과 전체 RSS를 따로 보고한다.
diff --git a/docs/design/003-module-contract.md b/docs/design/003-module-contract.md
new file mode 100644
index 0000000..1fcdb76
--- /dev/null
+++ b/docs/design/003-module-contract.md
@@ -0,0 +1,119 @@
+# 모듈 계약 초안 0.1
+
+상태: **제안**. 이 문서는 논리적 호출·수명·호환 조건과 데이터 레코드를 정한다.
+동적 로더·네이티브 함수 테이블·Wasm 모듈 연결은 아직 구현하지 않았다.
+[C17 레코드 헤더](abi-v0.h)는 데이터 표현을 검토·컴파일하기 위한 초안이며 실행 가능한 모듈 SDK가 아니다.
+
+## 1. 세 가지 경계
+
+| 경계 | 첫 방침 |
+|---|---|
+| Pure 내부 연산·모듈 | 값 종류, 버퍼 접근, 길이, 예산, 진행·오류·완료 의미를 명시 |
+| 플랫폼의 네이티브 함수 호출 | 해당 타깃의 기존 C 호출 규약을 사용. 레지스터·스택 규약을 새로 발명하지 않음 |
+| 저장·전송 형식 | 별도 버전·필드 폭·바이트 순서·검증·호환 규칙을 설계한 뒤 도입 |
+
+구조체·포인터를 파일로 덤프하는 것을 영속 형식으로 삼지 않는다. 반대로 같은 프로세스에서
+모듈을 호출할 때마다 데이터 전체를 직렬화할 필요도 없다.
+Arm의 호출 규약도 데이터 모델·포인터·정렬·패딩을 다룬다. 이것이 Apple을 포함한 모든
+플랫폼의 호출 차이를 없애주는 것은 아니므로 타깃별 경계를 검증해야 한다.
+[AAPCS64 고정 원문](https://github.com/ARM-software/abi-aa/blob/0948ccc42ed2ea6f1ae88a3cbd5438d904709112/aapcs64/aapcs64.rst#L635-L695)
+
+Wasm 선형 메모리의 숫자 저장은 little-endian이다. Wasm 어댑터는 그 규칙을 따르며,
+네이티브 레코드를 포인터 그대로 다른 인스턴스나 프로세스에 넘기지 않는다.
+[WebAssembly 숫자 저장](https://webassembly.github.io/spec/core/exec/numerics.html#storage)
+
+## 2. 프로파일과 버전
+
+모듈마다 다음 정보를 로드 전에 확인한다.
+
+- 연산 계약 버전과 프로파일 ID. 첫 제안은 `0.1 / byte_stream=1`이다.
+- 모듈 구현 식별자·빌드 해시·설정, 상태 스키마 식별자. 실행·재생 기록에 보관한다.
+- 입력·출력 종류와 개수, 구간 최대 크기, 정렬, 문맥·임시 공간 예산.
+- 동기/비동기 지원, 종료·취소 동작, 모듈 내부 외부 할당의 계측 가능 여부.
+
+`0.x` 동안 호환성은 정확한 버전 일치로만 허용한다. 임의로 더 높은 minor를 받아들이지 않는다.
+기능 필드·상태·플래그를 알 수 없으면 작업 시작 전에 `UNSUPPORTED`로 거절한다.
+이후 호환 확장을 도입하려면 필수·선택 기능의 구분과 구버전 검사를 별도로 정한다.
+
+현재 Workbench의 `revision`은 순환하는 적용 횟수다. ABI 버전·상태 스키마·비동기 티켓의
+대체물로 사용하지 않는다. 현재 중간 명령 번호나 Zig `Program` 메모리 배치를 모듈 파일 형식으로 고정하지 않는다.
+
+## 3. 첫 바이트 프로파일의 데이터 레코드
+
+모든 필드는 고정 폭 정수다. 네이티브에서는 native-endian이며 C의 기본 정렬을 사용한다.
+패킹 속성·C enum·bool·플랫폼별 `long`·포인터를 레코드에 넣지 않는다.
+동일한 숫자 폭만으로 호출 ABI가 같아지는 것은 아니며, 함수 경계 검증은 별도다.
+
+| 레코드 | 크기 | 뜻 |
+|---|---:|---|
+| `pure_handle_v0` | 8 B | 슬롯·세대. 실행 영역 안에서만 유효 |
+| `pure_span_v0` | 16 B | 버퍼 핸들·오프셋·길이 |
+| `pure_step_result_v0` | 24 B | 레코드 크기·스트림 상태·오류·이번 소비량·유효 생성량·예약 필드 |
+| `pure_stream_limits_v0` | 64 B | 레코드 크기·버전·프로파일·개수·예산·구간 상한·정렬 |
+
+이는 헤더의 크기 요구조건이며 메모리 사용량·전송량의 측정값이 아니다.
+입출력 수와 `max_pending_per_context`는 첫 프로파일에서 각각 1이어야 한다.
+`flags`와 `reserved`는 0이어야 한다. `struct_bytes`는 해당 크기와 정확히 일치해야 한다.
+`max_input_bytes/max_output_bytes`는 1 이상이고 협상한 예산 이하, `buffer_alignment`는
+1 이상의 2의 거듭제곱이어야 한다. 호스트가 보장할 수 없는 정렬·예산은 로드 또는 open에서 거절한다.
+0인 문맥·임시 예산은 해당 종류의 할당을 허용하지 않는다는 뜻이지 무제한이 아니다.
+
+한 요청의 길이는 `u32`, 모듈 예산·스트림의 누적 길이는 검사된 `u64`다.
+JavaScript 어댑터는 `u64`를 BigInt 또는 명시적 두 워드로 전달하고 Number로 조용히 축약하지 않는다.
+크기·개수·누적 산술은 실제 접근·할당 전에 검사한다.
+
+결과 검증 규칙:
+
+- `status`는 헤더의 여섯 값 중 하나다. `FAILED`에만 0이 아닌 `error`가 필요하고 다른 상태는 0이다.
+- `consumed/produced`는 제공한 길이 이하이고 `MORE`는 둘 중 하나가 0보다 커야 한다.
+- `reserved=0`, 레코드 크기가 일치해야 한다. 실패해도 검증된 부분 진행을 정확히 보존한다.
+- 잘못된 완료는 모듈 프로토콜 오류다. 데이터는 공개하지 않고 문맥을 실패 상태로 만든다.
+ 접근 종료를 보장하는 신뢰 가능한 완료까지 대여를 보유한다. 길이 오류를 핑계로 진행 중 버퍼를 재사용하지 않는다.
+- 헤더의 오류 번호는 이 초안의 별도 네임스페이스다. 현재 scalar VM의 오류 번호와 혼용하지 않는다.
+
+## 4. 논리적 제어 API
+
+아래는 다음 구현의 호출 의미다. 네이티브 C 함수 시그니처나 동적 로딩 심볼을 확정한 선언은 아니다.
+첫 구현은 정적으로 등록한 내부 어댑터로 이 의미부터 검증한다.
+
+| 호출 | 결과와 수명 |
+|---|---|
+| `describe(module)` | 계약·기능·한도·구현 식별. 작업·대여 생성 없음 |
+| `open(module, config, budget)` | 문맥 생성 또는 거절. 성공 시 문맥·숨은 내부 메모리의 예산 책임 시작 |
+| `submit(context, input, output, END_INPUT)` | 런타임이 거절하거나 티켓을 접수. 준비/확정/백엔드 제출 구분은 연산 명세를 따름 |
+| `cancel(ticket)` | 취소 요청을 전달한 결과. 스트림 결과나 버퍼 회수가 아님 |
+| `reap(ticket)` | 아직 완료가 없으면 `WOULD_BLOCK`; 있으면 결과 회수·유효 길이 반영·대여 해제 |
+| `close(context)` | 진행 작업이 있으면 `BUSY`; 없으면 내부 문맥·장기 자원 반환. 이후 핸들 무효 |
+
+사용하지 않는 입력이나 출력도 유효한 버퍼 핸들과 길이 0 구간으로 표시한다.
+`open/submit`의 일시적 풀 포화는 `WOULD_BLOCK`, 고정 한도를 넘는 요구는 `LIMIT`,
+이미 진행 요청이 있는 문맥은 `BUSY`, 잘못된 핸들·범위는 `INVALID`다.
+이 접수 응답들은 `pure_step_result_v0`의 스트림 상태와 별개이며 해당 C 응답 레코드는 후속 구현에서 정한다.
+
+동기 어댑터도 `submit` 시 즉시 결과를 완료 슬롯에 보관하고 `reap`에서 전달할 수 있다.
+호스트가 최적화로 내부 호출을 합치더라도 수명·오류·관찰 가능한 순서는 유지해야 한다.
+개별 문맥은 순차 처리하며 다른 문맥 사이의 완료 순서는 제출 순서와 같다고 가정하지 않는다.
+
+`reap`은 요청의 완료다. 결과가 `NEED_INPUT`이면 문맥은 살아 있으며 다음 입력을 받을 수 있다.
+문맥은 `DONE/FAILED/CANCELLED` 이후에도 `close`까지 예산을 차지한다.
+프로그램·모듈 교체는 관련 요청·대여·열린 문맥이 모두 해소된 뒤에만 허용한다.
+
+## 5. 확장 범위
+
+압축·인증 복호화·문서·미디어는 포맷 처리 모듈의 후보이며 모두 같은 복잡도를 갖지는 않는다.
+여러 평면의 영상, 탐색 가능한 문서, 파일·네트워크의 부분 쓰기는 추가 프로파일이 필요하다.
+현재 바이트 프로파일에 의미가 다른 모든 출력을 억지로 넣지 않는다.
+
+Pure 자체를 작은 OS로 설계한다는 [현재 방향](007-execution-domains.md)에 따라 실행·자원·
+통신의 운영 모델은 Pure가 소유한다. 현재 호스트 OS는 구동 수단과 제약이며, 모듈의 의미를
+호스트의 프로세스·파일 디스크립터에 고정하지 않는다. 호스트 구동, kernel-bypass, 직접 하드웨어
+구동은 이를 실현하는 경로로 구분한다. 부팅·드라이버의 범위나 일정은 이 모듈 계약으로 확정하지 않는다.
+
+## 6. ABI를 구현했다고 말할 수 있는 조건
+
+레코드의 `_Static_assert`가 타깃별로 컴파일되는 것은 데이터 레이아웃의 제한된 검사다.
+실제 함수 호출·언어 간 호환·버전 협상·대여·완료의 검증을 대신하지 않는다.
+후속 native adapter에서 함수 테이블 크기·호출 규약·오류 경계·호스트 할당 콜백·리소스 해제 책임을
+구체적인 선언으로 작성하고, 독립 C 생산자와 Zig 소비자의 실제 왕복 호출을 검사해야 한다.
+Wasm 어댑터는 범위·리프트/로워·수명 검사와 복사량을 별도로 측정해야 한다.
+이 단계 전에는 안정된 ABI·플러그인 호환·새 포맷 지원을 구현 완료로 보고하지 않는다.
diff --git a/docs/design/004-prepared-connections.md b/docs/design/004-prepared-connections.md
new file mode 100644
index 0000000..df4ccaf
--- /dev/null
+++ b/docs/design/004-prepared-connections.md
@@ -0,0 +1,39 @@
+# 실행 준비에서 연결을 정하는 첫 범위
+
+현재 필드·동적 입력 범위 확장은 [005](005-field-connections.md)를 따른다. 아래는 첫 상수 구간 프로파일의 기준이다.
+조건부 바이트 부분 변경 `store.splice`와 네이티브 자동화 경로는 [023](../research/023-document-edits.md)에 추가했다.
+
+2026-09-23 착수 기준:
+
+- 바꿀 결정: 기존 저장·응답 순서를 C에 고정하지 않고 작성한 관계에서 접근 범위와 수명을 준비한다.
+- 남은 질문: 중첩 구간·별칭을 실행 경로에서 없애면서 범위 오류·외부 효과·소유권을 유지할 수 있는가?
+- 최소 확인: 기존 실제 TCP 저장·복원을 작성 파일로 실행하고, 일부만 필요한 응답은 최종 구간만 매핑한다.
+- 중단 기준: 작성 변경이 실제 경로에 반영되고 의미 검사를 통과하면 범용 그래프 VM·새 쿼리 엔진으로 확장하지 않는다.
+
+첫 프로파일은 `on get`·`on put` 두 요청을 다룬다. 기존 숫자/화면 DSL과 파서를 공유하지 않는
+네이티브 연결 작성 실험이며 통합 언어의 확정 문법은 아니다. 준비는 서버 시작 시 한 번 한다.
+동적 코드 생성·LLVM·JIT·요청별 그래프 순회는 필요하지 않은 범위다.
+
+값은 읽기 전용 바이트 범위와 저장 결과다. `let`은 별칭·정확한 `range` 또는 저장 호출을
+연결한다. `reply(result[, bytes])`는 결과 버전과 선택한 바이트를 호스트 응답에 연결한다.
+저장 실패는 응답 오류로 전파하며, 본문 없는 reply도 저장 호출을 생략하지 않는다.
+내구성 불확실 결과도 성공이나 롤백으로 바꾸지 않는다.
+
+읽기는 한 번의 `store.read(request.key)` 이후에 뷰를 정의한다. 쓰기는 모든 입력 뷰를
+정의한 뒤 한 번의 `store.write(request.key, request.revision, bytes)`를 호출한다.
+쓰기를 수행한 뒤 실패할 수 있는 뷰 연산을 놓는 문법은 첫 프로파일에서 거절한다.
+하나의 요청에서 여러 외부 효과·루프·동적 분기는 아직 지원하지 않는다.
+
+`range(bytes, offset, length)`는 정확한 범위를 요구한다. 잘라내거나 부족한 바이트를
+조용히 무시하지 않는다. 중첩 구간을 합칠 때 최종 범위만 검사하면 의미가 달라진다.
+예: `range(range(body, 16, 64), 16, 16)`은 최종 `[32,48)`을 쓰지만 원본이 80 B 이상이어야
+한다. 준비된 경로는 최종 범위와 원본 최소 길이를 함께 보관한다. 사용되지 않는 구간의
+오류도 보존한다. 고정된 부모 구간을 넘는 자식 범위는 작성 오류로 시작 전에 거절한다.
+
+읽기 전송은 매핑의 수명을, 쓰기 결과와 함께 입력을 돌려주는 전송은 수신 구간의 수명을
+완료·중단까지 유지한다. 개발자가 해제 함수를 작성하지 않는다. 이 수명 선택은 현재 두
+생산자의 닫힌 계약에서 도출하며 임의 외부 모듈의 소유권 추론을 구현했다고 세지 않는다.
+
+이번에 제거할 것은 뷰 정의의 실행 단계와 불필요한 전체 본문 접근이다. 별칭·부분 범위는
+원래도 본문 복사를 요구하지 않는다. 이를 실제 복사를 제거한 수치로 꾸미지 않으며,
+준비된 구간 길이를 RSS 절감으로 해석하지 않는다. 파일·커널·페이지 비용은 그대로 남는다.
diff --git a/docs/design/005-field-connections.md b/docs/design/005-field-connections.md
new file mode 100644
index 0000000..0993567
--- /dev/null
+++ b/docs/design/005-field-connections.md
@@ -0,0 +1,28 @@
+# 필드와 실제 입력 값으로 정하는 연결
+
+2026-09-23 착수 기준:
+
+- 바꿀 결정: 작성자가 바이트 위치를 직접 관리하지 않고 필드의 배치·접근과 데이터에 따른 범위를 준비한다.
+- 남은 질문: 이름·타입을 붙인 뒤에도 입력을 객체로 재구성하지 않고 실제 요청 값으로 저장·응답을 선택할 수 있는가?
+- 최소 확인: 문서와 선택 시작·길이를 받는 실제 요청에서 선택한 내용을 저장·응답한다. 잘린 입력·잘못된 범위는 저장 전에 거절한다.
+- 중단 기준: 이 경로가 검증되면 새 범용 직렬화 형식·타입 VM·동적 그래프 실행기로 범위를 늘리지 않는다.
+
+`layout`은 경계의 바이트 배치 선언이다. 저장소 스키마나 Pure 전체의 RAM 객체 모델이 아니다.
+첫 필드 종류는 `u32le`, 고정 `bytes[N]`, 마지막 가변 길이 `bytes`다. 패딩 없이 선언 순서로
+배치하며 숫자는 명시한 바이트 순서로 읽는다. 기존 바이트 경로에는 선언을 강제하지 않는다.
+
+`view(Layout, source)`는 복사·할당 없이 타입이 있는 참조를 준비한다. 필드는 이름으로 선택한다.
+고정 필드는 지정한 폭을 요구하며 마지막 bytes는 나머지 구간이다. 고정 필드만 있는 선언은
+접두부를 해석하고 여분의 바이트를 무시한다. 필드 의미·텍스트 인코딩·버전 변환까지 보장하지 않는다.
+
+`range`는 상수 또는 `u32le` 필드를 시작·길이로 사용한다. 상수만 필요한 연결은 기존처럼
+준비 단계에서 합친다. 실제 입력 값에 의존하는 범위만 요청 시 계산하며, 별칭은 실행 단계를
+추가하지 않는다. 쓰지 않는 동적 범위도 검사해 오류를 보존한다. 모든 검사가 저장 효과보다 앞선다.
+
+첫 동적 범위는 PUT 입력에 한정한다. GET의 이름 기반 고정 필드·나머지 구간 선택은 가능하나
+파일 내용의 숫자로 결정하는 동적 GET은 시작 시 거절한다. 후자는 같은 파일 버전에서 필요한
+숫자와 본문을 읽는 접근 계획이 추가로 필요하며, 전체 매핑으로 조용히 대체하지 않는다.
+
+배치 선언은 최대 4개, 선언당 필드는 16개, 입력 값에 의존하는 범위는 8단계로 제한한다.
+가변 필드 뒤의 필드·중첩 배치·동적으로 선택한 바이트 위의 새 배치 해석은 아직 지원하지 않는다.
+소비 완료까지 원본의 수명을 유지하며 입력의 일부만 선택해도 수신 할당 전체를 계상한다.
diff --git a/docs/design/006-native-protocol.md b/docs/design/006-native-protocol.md
new file mode 100644
index 0000000..9b51fec
--- /dev/null
+++ b/docs/design/006-native-protocol.md
@@ -0,0 +1,139 @@
+# Pure의 자체 통신 형식과 보안 전송 경계
+
+작성일: 2026-09-23, 구현 상태 갱신: 2026-09-24. 상태: 설계 방향과 제한된 첫 구현.
+성능 결과나 QUIC 구현은 아니다.
+
+2026-09-24 구현 상태: 선택한 scalar 앱과 `editor.pure` 문서 앱에 자체 이진 형식을
+TLS 1.3/TCP 위에 실은 피어 호스트를 검증했다. [026 — scalar 피어](../research/026-secure-peer-link.md)와
+[030 — 문서 피어·출력 소비 선택](../research/030-authenticated-document-peer.md)을 본다.
+이 설계의 일반 RPC·QUIC·새 전송 후보가 구현된 것은 아니다.
+
+## 결정
+
+Pure 간 통신은 HTTP 메서드·URL·문자열 헤더를 필수 실행 모델로 삼지 않는다.
+앱이 작성한 연결과 데이터 형식에서 자체 바이너리 통신 형식을 준비하는 방향으로 진행한다.
+HTTP는 웹·기존 도구와 연결하는 호환 경계로 유지한다. 첫 검증 전송은 TLS 1.3/TCP이며,
+최종 범용 전송 정책은 아직 선택하지 않았다.
+
+외부 런타임·서비스·프로그램과의 통신도 핵심 요구사항이다. Pure끼리의 자체 형식과 별도로
+상대가 사용하는 프로토콜·형식으로 요청을 받고 보낼 수 있어야 한다. 외부에 Pure 사용을
+요구하지 않으며, 자체 형식의 계약을 구현한 외부 프로그램과의 연결도 허용하는 방향이다.
+
+적용 범위 보완: [작은 OS로서의 Pure](007-execution-domains.md)가 연결의 의미와 운영 정책을
+소유한다. 공유가 허용된 내부 데이터에는 직접 호출·대여·소유권 전달을 사용하며, 이 문서의
+바이너리 경계 형식을 모든 내부 연결에 강제하지 않는다. 현재 호스트의 IPC·소켓은 가용한
+전달 수단이며 Pure 앱의 필수 개념이 아니다.
+
+`prototypes/connections/server.c`는 루프백 TCP 위의 평문 HTTP/1.1이며 요청마다 연결을 닫는다.
+`on get` / `on put`과 요청 키도 그 작성 프로필에 들어 있다. 별도의 선택형 피어 호스트는
+해당 scalar 앱에서 HTTP 없이 입력·상태·저장을 주고받는다. 이 둘은 아직 하나의 범용
+프로토콜 선택기로 통합되지 않았다. 기존 HTTP 검증은 저장·범위·수명에 대한 것이며,
+피어 검증도 인터넷 운영 보안이나 QUIC 대비 성능을 검증한 것이 아니다. 문서 피어는
+같은 `editor.pure` 효과를 C·Python 클라이언트에서 실행하며, 응답 본문을 소비하지 않을
+호출에서 그 바이트의 전송을 생략한다.
+
+사용자가 말한 socket 직접 통신은 일반 TCP/UDP 소켓으로도 구현할 수 있다.
+IP 패킷을 직접 구성하는 `SOCK_RAW`나 커널 우회까지 필요한 것은 아니다.
+각 선택은 실제 제거할 비용이 확인되면 별도로 판단한다.
+
+## HTTP 제거와 QUIC 대체는 다른 선택이다
+
+QUIC은 HTTP 없이도 앱의 자체 프로토콜을 운반할 수 있다.
+HTTP/3는 QUIC을 사용하는 앱 프로토콜 중 하나다.
+따라서 자체 형식을 QUIC 스트림에 직접 싣는 경로를 첫 비교 후보로 둔다.
+[RFC 9308 §1](https://www.rfc-editor.org/rfc/rfc9308.html#section-1)
+
+| 후보 | Pure가 정하는 부분 | 전송에서 사용하는 부분 |
+|---|---|---|
+| 자체 형식 / QUIC / UDP | 연결 대상, 값 배치, 호출·완료·취소 의미, 전송할 데이터 | QUIC의 보안 연결·스트림·복구·혼잡 제어 |
+| 같은 자체 형식 / TLS 1.3 / TCP | 위 의미와 메시지 경계; 필요한 경우 호출 다중화 | TLS의 데이터 보호와 TCP의 순서 있는 바이트 전달 |
+| 자체 형식 / 새 전송 / UDP | 위 부분과 새 전송의 모든 계약 | 재사용할 암호 구현 외에 전송 설계·검증도 필요 |
+
+두 번째 경로는 비교 및 UDP가 통하지 않는 환경의 연결 후보다. TCP+TLS를 QUIC과 모든 면에서
+동일하다고 보지 않는다. 예를 들어 TCP 바이트 스트림 하나에 여러 호출을 실으면 손실로 인한
+전달 대기를 공유하며, QUIC의 독립 스트림·경로 변경과 같은 기능은 자동으로 생기지 않는다.
+보안 연결에 실패했을 때 평문으로 낮추는 동작은 후보에 포함하지 않는다.
+[RFC 9308 §2](https://www.rfc-editor.org/rfc/rfc9308.html#section-2),
+[RFC 9293 §2.2](https://www.rfc-editor.org/rfc/rfc9293.html#section-2.2)
+
+QUIC의 보안은 TLS 1.3을 통한 인증·키 설정과 패킷 보호를 포함한다.
+신뢰성·안정성에는 손실 복구, 혼잡·흐름 제어, 주소 검증과 증폭 제한 등의 별도 계약도 있다.
+암호 알고리즘 하나를 붙이거나 헤더를 줄인 것만으로 이 전체와 동등하다고 평가하지 않는다.
+전송 보호와 앱의 접근 권한·저장 완료·응답 유실 후 중복 실행 처리도 구분한다.
+[RFC 9001 §2](https://www.rfc-editor.org/rfc/rfc9001.html#section-2),
+[RFC 9000 §4, §8](https://www.rfc-editor.org/rfc/rfc9000.html#section-4),
+[RFC 9002](https://www.rfc-editor.org/rfc/rfc9002.html)
+
+## 연결에서 생략할 수 있는 정보
+
+후보 흐름은 다음과 같다. 구체적인 패킷 배치나 필드 바이트 수는 아직 고정하지 않는다.
+
+1. 인증된 세션에서 허용된 입력·출력, 형식 버전, 한도와 전달 의미를 확인한다.
+2. 대상·형식을 연결이나 스트림에 결부하거나 짧은 세션 내 식별자로 정한다.
+3. 후속 메시지는 합의에서 추론할 수 없는 값과 식별 정보만 운반한다.
+4. 실행·저장 결과를 앱이 관찰할 수 있는 완료로 전달한다.
+
+예를 들어 특정 문서의 변경 입력에 스트림을 결부했다면 매번 URL·메서드·필드 이름을 보낼
+필요가 없을 수 있다. 여러 대상이 섞이면 대상 식별이 필요하고, 가변 길이면 길이 또는
+명확한 종료 규칙이 필요하다. 조건부 갱신의 기대 버전, 동시 호출의 대응 관계, 오류 의미는
+해당 동작에 필요하면 남긴다. TCP의 한 번의 `read`를 메시지 하나로 간주하지 않는다.
+
+합의 비용도 비용이다. 추가 왕복, 세션별 표, 재연결, 형식 변경과 호환성 확인에 필요한
+시간·메모리를 포함한다. 형식 불일치는 해석 전에 거부하고, 원격 식별자를 포인터나
+임의 실행 권한으로 취급하지 않는다. 경계 형식은 명시적 바이트 순서·길이·한도를 가지며
+네이티브 구조체의 패딩이나 포인터를 그대로 전송하지 않는다.
+
+0-RTT로 저장 효과를 먼저 실행하는 동작은 초기 후보에서 제외한다. 보안 전송만으로 앱의
+중복 실행 문제가 해결되지는 않으며, 0-RTT 데이터에는 재전송 공격에 대한 별도 고려가 필요하다.
+[RFC 9308 §3.1](https://www.rfc-editor.org/rfc/rfc9308.html#section-3.1)
+
+## Pure에서 확인할 연구 가설
+
+바이너리 인코딩이나 연결별 형식 합의 자체를 신규 기술이라고 주장하지 않는다.
+검증할 가설은 **준비된 연산·소비 관계를 전송까지 사용하면, 같은 앱 동작을 유지하면서
+반복 해석과 중간 보관·대기를 줄일 수 있는가**다.
+
+- 이미 정해진 대상·필드 접근을 송수신 경계에서 다시 문자열로 만들고 해석하는가?
+- 소비자가 사용할 범위만 보낼 수 있는가? 부분 전송에서 필요한 형식·버전도 일치하는가?
+- 전송의 수신 한도와 앱의 실제 소비·메모리 예산을 연결해 중복 큐를 줄일 수 있는가?
+- 아직 전송하지 않은 최신 상태를 합쳐도 되는가? 모든 사건을 보존해야 하는 연결과 구분되는가?
+
+수신 한도를 소비에 연결할 때 큰 메시지의 나머지를 받기 위해 필요한 여유까지 막으면
+교착할 수 있다. 청크 소비 또는 메시지 단위 예산 예약 등으로 진행 가능성도 확인한다.
+[RFC 9308 §4.4](https://www.rfc-editor.org/rfc/rfc9308.html#section-4.4)
+
+전송 라이브러리가 소유하는 평문·암호문·재전송 버퍼도 계산에 넣는다. 읽기 전용 저장 매핑을
+그대로 암호문으로 덮어쓸 수 없으며, `send`의 접수나 transport ACK를 앱의 저장 완료로
+취급하지 않는다. 참조 해제는 실제 전송 API의 소유권 계약에 따라 정한다.
+현재의 본문 예산만으로 전체 통신 메모리가 제한된다고 주장하지 않는다.
+
+## 추가 구현과 비교의 경계
+
+먼저 현재 get/put 전용 진입점을 앱 입력과 효과에 대한 내부 호출로 분리한다.
+HTTP와 자체 형식은 같은 조건부 저장·응답 동작으로 연결한다. 별도의 범용 메시지 객체를
+항상 만들도록 강제하지 않는다. 기존 CLI와 저장·충돌·실패·수명 검증은 유지한다.
+
+첫 TLS 1.3 지속 연결은 [026](../research/026-secure-peer-link.md)에, 실제 문서 작업의
+연결과 선택 빌드·메모리 비용은 [030](../research/030-authenticated-document-peer.md)에
+기록했다. 다음에는 전체 앱의 실패망·혼합 작업 비용과 병목을 확인한다. 보안 없는 임시 소켓 경로를
+인터넷용 완료물로 보고하지 않는다.
+새 UDP 전송은 이 단계에서 확인된 구체적인 병목을 기존 전송의 설정·연결 방식으로
+제거할 수 없을 때 별도 연구 후보로 연다.
+
+비교가 답할 질문은 분리한다.
+
+- 앱 형식의 효과: 같은 QUIC 구현에서 HTTP/3와 Pure 형식을 비교한다.
+- 전송 선택의 효과: 같은 Pure 형식·동작을 QUIC과 TCP+TLS에서 비교한다.
+- 새 전송의 효과: 동일한 보안·전달 요구를 충족한 뒤, 같은 Pure 형식을 기존 QUIC 구현과 비교한다.
+
+이 비교들을 모두 선행해야 한다는 뜻은 아니다. 실제 병목에 대한 선택이 필요할 때 해당
+비교만 수행한다. 연결 재사용·핸드셰이크·암호 설정·동시성·배치·내구성·완료 정의를 맞춘다.
+현재의 평문·요청당 연결 종료 경로는 회귀 검증에 쓰며, QUIC 우위/열위의 근거로 쓰지 않는다.
+
+대표 작업은 기존 작업물의 작은 변경·저장, 큰 내용 전달 중 작은 변경, 느린 수신자와
+연결 종료 후 결과 확인이다. 새 전송 판단에는 지연·손실·재정렬이 있는 경로도 필요하다.
+실제 성공 작업의 지연 분포, CPU, 전체 메모리와 연결별 비용, 전송 바이트·대기열을
+필요한 결정에 맞춰 기록한다. 헤더 바이트 절감만으로 전체 성능 우위를 선언하지 않는다.
+
+현재 결론은 HTTP를 내부 기본 모델로 요구하지 않는다는 것이다.
+QUIC보다 빠르다는 결과나 새 전송의 보안 동등성은 아직 없다.
diff --git a/docs/design/007-execution-domains.md b/docs/design/007-execution-domains.md
new file mode 100644
index 0000000..01edb88
--- /dev/null
+++ b/docs/design/007-execution-domains.md
@@ -0,0 +1,222 @@
+# 작은 OS로 설계하는 마이크로 런타임과 실행 영역
+
+작성일: 2026-09-23. 상태: 설계 방향. [022](../research/022-execution-core.md)에서 저장 프로필의
+영역별 작업 접수·완료·대여·회수를 구현했다. 작은 OS의 통합 코어·범용 실행·샌드박스는 아직 미완료다.
+
+## 마이크로 런타임의 크기 제약
+
+**작은 OS라는 책임 범위와 마이크로 런타임이라는 크기 제약을 함께 지킨다.**
+아래 기능 목록을 항상 포함되는 커널·서비스 목록으로 해석하지 않는다.
+
+- 공통 코어는 실제 작업에 필요한 실행 진행, 소유권·자원 한도, 접근 권한과 완료·회수 규칙에
+ 한정한다. 사용하지 않는 기능을 위한 범용 객체·관리 계층을 미리 만들지 않는다.
+- 네트워크 프로토콜·저장 구현·UI·미디어·호환 기능은 앱에 필요한 구성을 선택해 결합한다.
+ 초기 방식은 빌드 시 선택이며 동적 로더·플러그인 레지스트리를 기본 의존성으로 추가하지 않는다.
+ 기능 지원을 그 코드·상태·백그라운드 작업의 상시 포함으로 구현하지 않는다.
+- 영역마다 전용 스레드·스택·소켓·큰 큐를 예약하지 않는다. 공유 가능한 준비 코드·연결은 공유하고
+ 상태·대기 공간은 실제 수요와 명시적인 한도에 맞춘다. 유휴 풀의 보유 공간도 비용이다.
+- 파서·컴파일러·작성 도구를 실행 전용 구성의 필수 의존성으로 만들지 않는다. 준비된 실행에
+ 필요 없는 소스·AST·필드 이름표를 계속 보관하지 않는다. 특수화에 따른 코드 증가도 비용에 넣는다.
+
+코어의 코드·정적 데이터, 선택한 의존성을 포함한 배포 구성, 유휴 메모리, 영역·진행 작업별
+추가 비용을 구분한다. 실제 앱의 전체 피크와 외부 버퍼도 확인한다. 작은 코어 옆의 라이브러리나
+호스트로 비용을 옮긴 것으로 축소를 주장하지 않는다. 모듈을 분리했다는 사실만으로 미사용
+코드·상태가 빠졌다고 보지 않고 선택한 빌드와 실행에서 확인한다.
+
+새 코어 기능에는 현재 작업이 요구하는 이유와 더 작은 구현 가능성을 제시한다. 다음 구현의
+전후 크기·메모리 차이를 확인하고 설명되지 않는 증가가 있으면 범위를 줄인다. 수치 상한은
+실행 전용 코어·선택 구성·대상 기기별로 근거를 갖고 정하며 임의의 KiB 숫자를 달성치로 쓰지 않는다.
+필수 권한·정확성·보안 계약을 제거해 작게 만들지 않는다.
+
+현재 저장 프로필은 `make core`로 파서·저장·HTTP 없는 아카이브만 빌드한다. release의
+`make check-core`가 코드 섹션·구조체 상한, 아카이브 구성과 외부 의존성을 검사한다.
+상한 변경은 필요한 기능·더 작은 배치·전체 비용의 검토를 함께 기록한다. 현재 수치와
+선택 실행물의 비용 범위는 [023](../research/023-document-edits.md)에 있다. 이 제한된 코어의
+크기를 전체 앱·모든 플랫폼의 메모리 크기로 인용하지 않는다.
+
+## Pure가 소유하는 운영 모델
+
+**Pure 런타임 자체를 하나의 작은 OS로 설계한다.** 실행·메모리·보호·자원 수명·저장·통신의
+의미와 정책을 Pure가 소유하고, 앱은 그 모델 위에서 동작한다. UI는 이 기반의 한 하위 체계다.
+OS 프로세스는 현재 호스트에서 구동할 때 받는 실행·보호·자원 제약이며 Pure의 기본 개념이 아니다.
+앞선 설명처럼 프로세스 배치 관리에서 설계를 시작하지 않는다.
+
+현재 호스트는 CPU 실행 기회, 메모리, 시계, 저장·통신·장치 접근을 제공한다.
+Pure는 제공받은 범위 안에서 어떤 작업을 실행하고, 누구에게 자원을 할당하며, 어떤 연결과
+효과를 허용하고, 언제 회수할지 결정한다. 호스트의 PID·스레드·파일 디스크립터·소켓을
+앱의 정체성이나 공통 실행 계약으로 노출하지 않는다. 기존 네이티브 도구의 FFI는 별도 경계다.
+
+| Pure가 정의할 정책·의미 | 플랫폼 연결부가 제공할 수단·제약 |
+|---|---|
+| 실행 가능한 작업과 스케줄링, 기한·중단 계약 | 실행 기회, 깨우기·대기·시계, 사용 가능한 중단 수단 |
+| 메모리 배치·소유권·대여·할당·회수와 예산 | 메모리 확보·반환·매핑·보호의 가용 기능과 실패 |
+| 앱·자원 식별, 접근 권한과 실행 보호 | 해당 환경이 집행할 수 있는 보호 기능과 한계 |
+| 내부 연결, 원격 호출과 완료·실패 의미 | 바이트·패킷 전달 수단과 실제 입출력 완료 |
+| 저장 배치·공개·내구성·복구 계약 | 파일·블록 등 저장 수단, 동기화 결과와 장애 |
+| UI 입력·배치·표시의 일관된 의미 | 창·입력·접근성·그래픽 등 환경 기능 |
+
+이 표는 새 중간 객체를 매번 만드는 API를 요구하지 않는다. 준비된 연결에서 계약을 보존하며
+불필요한 경계를 제거한다. 플랫폼이 어떤 계약을 집행하지 못하면 지원 범위로 명시한다.
+호스트 밖의 메모리·CPU를 통제하거나 호스트 종료를 막는다고 주장하지 않는다.
+
+개발은 기존 OS에서 구동하는 형태로 시작한다. 직접 하드웨어를 구동하는 경로에서도
+Pure의 앱·실행 모델을 유지할 수 있도록 경계를 정하되, 드라이버·부팅 구현을 지금 완료한
+것으로 취급하지 않는다. 작은 OS라는 목표를 단순한 이름 변경이나 향후 부가 기능으로 미루지 않는다.
+
+## 외부 통신은 핵심 기능이다
+
+Pure 외부와의 연결도 운영 모델의 일부다. Pure를 사용하지 않는 서비스·런타임·프로그램과
+요청을 보내고 받을 수 있어야 한다. 작은 OS라는 설계 방향을 폐쇄된 통신 환경으로 해석하지 않는다.
+
+- Pure 내부 연결은 준비된 연산·데이터 관계를 사용한다.
+- Pure 간 원격 연결은 자체 형식과 보안 전송을 사용할 수 있다.
+- 외부 서비스와의 연결은 상대가 사용하는 프로토콜·형식·인증·완료 의미를 지원한다.
+ HTTP(S), 기존 RPC, TCP/UDP 기반 프로토콜과 로컬 IPC 등 필요한 접점을 양방향으로 제공한다.
+
+이는 지원 목표이며 위 프로토콜들을 모두 구현했다는 목록이 아니다. 자체 형식도 상대가
+그 계약을 구현하면 Pure 외부에서 사용할 수 있어야 한다. 외부 프로그램의 내부 구조까지
+Pure 실행 영역으로 옮기거나 모든 상대에게 Pure 전용 프로토콜을 강제하지 않는다.
+
+외부 형식은 필요에 따라 검증·변환하되, 내부 데이터를 항상 외부 형식으로 보관하지 않는다.
+그대로 소비할 수 있는 데이터에 불필요한 변환을 추가하지 않는다. 변환·암호화·대기·복사 비용은
+전체 경로에 포함하고, 해당 프로토콜의 주소·메서드·오류 등 앱에 필요한 의미는 접점에서 제공한다.
+호환성을 이유로 그 개념을 모든 Pure 내부 연결의 필수 모델로 올리지는 않는다.
+
+## 기본 단위
+
+**실행 영역**은 Pure 내부에서 상태·권한·수명을 귀속시키는 단위다.
+기존 [메모리 계약](002-memory-lifetime.md)의 영역을 작은 OS의 운영 모델 안에서 구체화한다.
+영역을 OS 프로세스의 대체 이름이나 컨테이너의 포장으로 정의하지 않는다.
+VM 명령 집합의 채택 여부는 이 관리 단위를 정의하는 결정과 별개다.
+
+영역은 앱이 독립적으로 관리해야 하는 상태·권한·수명의 경계에 만든다.
+함수·그래프 노드·요청마다 영역이나 메일박스를 하나씩 만들지 않는다.
+첫 후보는 영역의 관리 상태를 한 제어 흐름이 변경하고, 독립 작업의 완료를 그 흐름에서 회수하는 방식이다.
+영역마다 전용 OS 스레드·스택·소켓·이벤트 루프를 예약할 필요는 없다.
+변경하지 않는 준비 프로그램은 공유하고, 인스턴스 상태와 사용 중인 작업만 개별 보유한다.
+
+| 영역이 관리할 것 | 의미 |
+|---|---|
+| 실행 식별자와 세대 | 재시작한 인스턴스에 이전 요청·완료가 섞이지 않음 |
+| 프로그램과 상태 | 준비된 연산·연결, 영역이 소유한 변경 가능한 상태 |
+| 자원 예산 | 보유 메모리, 진행·대기·완료 요청과 외부 자원의 귀속·한도 |
+| 허용된 연결과 효과 | 호출 가능한 입력, 저장·파일·네트워크 등 접근 범위 |
+| 실행·종료 상태 | 새 작업 접수, 진행 작업 배출, 취소 요청, 실제 접근 종료와 회수 |
+
+pod·VM은 사용자가 설명한 관리 경험의 비유이며 Pure의 내부 구조를 고정하는 명칭이 아니다.
+묶음 수명과 보호 강도는 Pure의 요구에서 정한다. 영역마다 별도의 OS 이미지나 가상 장치를
+필수로 넣지 않는다.
+
+## 연결은 자원의 접근·공유 조건에서 준비한다
+
+앱은 허용된 입력과 출력의 관계를 작성한다. 연결을 준비할 때 대상의 형식·권한·수명과
+배치를 확인하고 실행 경로를 정한다. 모든 호출을 범용 객체·직렬화·소켓으로 보내지 않는다.
+경로를 선택해도 격리 정책과 관찰 가능한 실행 순서를 우회하지 않는다.
+
+| 가용 자원과 보호 조건 | 가능한 경로 | 남는 책임 |
+|---|---|---|
+| 데이터를 함께 접근할 수 있고 실행 순서를 바로 연결 가능 | 준비된 직접 호출·읽기 대여·소유권 이전 | 권한, 원본 수명, 접수 예산, 재진입·효과 순서 |
+| 데이터를 공유할 수 있으나 실행 흐름이 독립적 | 제한된 작업 큐와 데이터 참조 전달 | 동기화·공개 순서, 대여 유지, 완료 회수 |
+| 보호 경계가 직접 접근을 제한 | 허용된 공유 매핑 또는 바이트 전달 | 공유 영역의 권한·수명·동기화·검증, 종료 후 회수 |
+| 메모리를 공유할 수 없는 원격 상대 | 자체 경계 형식과 보안 전송 | 인코딩, 흐름 제어, 기한, 응답 유실과 결과 불명 |
+
+현재 호스트 연결부에서는 위 조건을 스레드·메모리 매핑·IPC·소켓 등으로 구현할 수 있다.
+이 구현 분류를 Pure 코어의 필수 프로세스·소켓 계층으로 올리지 않는다.
+
+같은 프로세스라도 격리된 샌드박스 사이에서는 임의 포인터 대여를 허용하지 않는다.
+같은 기기라도 공유 메모리를 항상 사용하는 것으로 확정하지 않는다. 공유·매핑의 관리 비용과
+격리 요구에 따라 복사나 IPC가 더 적절할 수 있다. 서로 다른 프로세스에는 포인터를 전송하지 않는다.
+
+버퍼 핸들은 기존 계약처럼 발급 영역 안에서 유효하다. 영역 간 대여는 수신 영역에서
+검사할 수 있는 접근 권한과 대여 기록으로 연결하며, 발급 영역의 핸들 숫자만 복사하지 않는다.
+물리 버퍼는 한 번만 계상하되, 각 소비자가 얼마나 오래 회수를 막는지도 기록한다.
+
+## 같은 호출 계약과 다른 실패 조건
+
+접수, 결과, 완료, 취소, 기한의 의미는 [연산 계약](001-operation-semantics.md)과
+[모듈 계약](003-module-contract.md)을 따른다. 로컬 호출이 즉시 끝나더라도 제출 도중 앱에
+예상치 못한 재진입을 만들지 않는다. 관찰 가능한 순서·권한·예산을 보존할 수 있을 때
+내부 호출이나 완료 처리를 합칠 수 있으며 모든 경계마다 큐를 강제하지 않는다.
+
+원격 호출을 로컬 함수와 똑같이 성공·실패한다고 보이게 만들지는 않는다.
+요청이 접수되기 전 거절과, 효과 실행 후 응답을 받지 못한 결과 불명은 구분한다.
+취소는 이미 발생한 저장 효과를 되돌리지 않는다. 재연결 시 자동 재실행도 기본으로 가정하지 않는다.
+같은 입력을 로컬·원격에 배치하려면 앱이 요구하는 순서·내구성·오류·공유 조건을 양쪽에서
+충족해야 한다. 충족하지 못하는 배치는 거절하거나 명시적으로 다른 계약을 선택한다.
+
+준비된 연결은 대상의 실행 세대와 결부한다. 대상이 재시작하면 이전 연결을 무효화하고
+형식·권한을 다시 확인한다. 늦은 완료로 새 인스턴스의 상태·버퍼를 변경하지 않는다.
+이전 작업이 이미 실행됐을 가능성이 있으면 새 인스턴스에 조용히 재전달하지 않는다.
+네트워크의 인증된 상대 식별과 영역 내부의 슬롯·세대는 별개이며 세대 번호 자체는 인증 수단이 아니다.
+
+## 자원 관리와 강제 격리
+
+첫 단계의 신뢰하는 네이티브 코드 사이에서 가능한 것은 관리 계약에 따른 상태·자원 분리다.
+현재 C 코드에 영역 구조체를 추가하는 것으로 임의 메모리 접근이나 프로세스 크래시를
+격리했다고 주장할 수 없다. 프로세스를 공유하면 OS 수준의 종료·주소 공간 장애도 공유한다.
+
+불신 코드에 필요한 격리 강도는 배치의 입력 조건으로 둔다. 후보는 제한된 실행 형식의
+검증·메모리 접근 제어, Wasm 같은 샌드박스, 별도 OS 프로세스 또는 VM 경계다.
+메모리 안전한 실행 형식도 네이티브 확장·호스트 호출의 권한과 안전성을 자동 보장하지 않는다.
+예를 들어 Wasmtime은 인스턴스 메모리 격리를 제공하고 호스트 API의 안전성도 별도로 다룬다.
+이 문서는 Wasmtime 도입 결정이 아니다. [Wasmtime 보안 모델](https://docs.wasmtime.dev/security.html)
+
+메모리 예산에는 진행 작업뿐 아니라 완료 슬롯, 큐, 암호·재전송·외부 라이브러리의 보유 공간도
+포함하거나 미계측으로 명시한다. 같은 물리 공간의 중복 합산과 외부로 비용을 숨기는 일을 피한다.
+공유 코드·스케줄러·유휴 풀은 런타임 공통 비용으로 따로 보고한다.
+
+CPU 시간의 강제 제한에는 중단 가능한 실행이나 OS의 집행 수단이 필요하다.
+협력적 스케줄러의 실행 예산만으로 멈추지 않는 네이티브 함수나 동기 파일 호출을 제어할 수는 없다.
+현재 서버의 동기 저장 호출은 이벤트 루프를 막을 수 있다. 영역을 나누는 것만으로 해결됐다고 세지 않는다.
+
+종료 요청은 새 접수를 막고 진행 작업·대여를 배출하는 단계다. 시간 초과만으로 참조 중인
+메모리를 재사용하지 않는다. 영역을 관리 목록에서 제외하더라도 남은 자원은 접근이 끝날 때까지
+명시적인 회수 책임과 예산 아래 둔다. 강제 종료·무중단 이동·복제는 별도 구현과 복구 계약이 필요하다.
+
+## BSD socket·Kitex 수준의 목표를 평가하는 방법
+
+BSD socket은 통신 API이므로 단일 성능 수치를 뜻하지 않는다. 요구를 **같은 일을 하는 직접
+소켓 구현에 비해 런타임의 추가 비용을 작게 유지하고, 실제 RPC에서는 Kitex와 경쟁하는 것**으로 둔다.
+그 수준에 도달했다는 결과는 아직 없다.
+
+Kitex는 Netpoll을 기본 전송 구현으로 사용하지만 다른 전송 구현도 연결할 수 있다.
+연결 풀·프로토콜·실행 경로를 포함해 비교해야 한다.
+[Kitex 전송 확장](https://www.cloudwego.io/docs/kitex/tutorials/framework-exten/transport/)
+
+현재 공식 문서는 긴 연결 풀을 기본으로 설명한다. `netpollmux`에 의존하는
+`WithMuxConnection` / `WithMuxTransport`는 유지보수 중단으로 deprecated 상태다.
+이는 QUIC이나 gRPC를 포함한 모든 다중화가 불필요하다는 뜻이 아니다.
+과거 벤치마크 숫자나 설정을 그대로 합격선으로 삼지 않는다.
+[Kitex 연결 유형](https://www.cloudwego.io/docs/kitex/tutorials/basic-feature/connection_type/)
+
+비교는 실제 선택에 필요할 때만 수행한다.
+
+- 같은 주소 공간의 연결: 같은 작업·권한·수명·완료 조건을 가진 직접 구현에 비해 추가된
+ 할당·큐·복사·스케줄링을 확인한다. 소켓을 생략한 결과를 네트워크 전송 성능으로 발표하지 않는다.
+- 프로세스·기기 간 RPC: 성공 결과·형식·인증/암호화·연결 재사용·동시성·배치·내구성과
+ 타임아웃·재시도 조건을 맞춘 직접 소켓 구현 및 유지보수되는 Kitex 구성과 비교한다.
+- 기존 변경·저장 작업에서 지연 분포와 성공 처리량, 클라이언트·서버 CPU·전체 메모리,
+ 연결별 보유량을 확인한다. 큰 전달·느린 수신자·과부하가 작은 작업에 주는 영향도 포함한다.
+
+영역·핸들·바이너리 형식을 만들었다는 사실은 신규성이나 성능의 증명이 아니다.
+연구 가설은 작성된 연결의 의미를 보존하면서 **배치에 불필요한 전송·복사·중간 보관을
+준비 단계에서 제거하고, 필요한 격리와 자원 관리는 유지할 수 있는가**다.
+
+## 다음 구현의 구체적 범위
+
+[006](006-native-protocol.md)의 진입점 분리를 **Pure가 운영 정책을 소유하는 코어와 호스트
+수단의 분리**로 진행한다. 기존 선택·조건부 저장·응답 작업을 재사용해 실제 효과까지 연결한다.
+기존 구현에서 필요한 책임만 분리하며, 사용처 없는 서비스 관리자·범용 모듈 체계를 먼저 만들지 않는다.
+이번 경로에 필요한 코어 크기와 실행 비용을 기준으로 유지하고, 추가 기능의 비용은 선택 구성에 귀속시킨다.
+
+1. Pure가 요청 접수·진행 작업·완료·자원 회수를 소유하고, 호스트 연결부는 저장·전송·시계 등
+ 실제 수단과 결과를 제공하도록 책임을 분리한다. PID·파일 디스크립터를 앱의 식별자로 삼지 않는다.
+2. 영역별 프로그램·상태·예산·접근 권한을 이 코어에 귀속시킨다. 두 영역의 기존 작업을
+ 내부 연결로 실행하고 외부 요청도 같은 앱 의미로 접수한다. 사용자에게 수명 관리를 떠넘기지 않는다.
+3. 한 영역의 포화·정상 종료·재생성과 이전 완료 처리에서 다른 영역의 관리 상태를 보존하고,
+ 호스트의 자원 부족·입출력 실패가 Pure 결과로 정확히 전달되는지 확인한다.
+4. 호스트에서 집행할 수 있는 격리와 보안 원격 경로를 확장한다. 각 기능의 검증 범위와
+ 호스트 제약을 기록하며 관리 상태 분리를 네이티브 크래시 격리로 해석하지 않는다.
+
+첫 구현에 클러스터 스케줄러, 게스트 OS, 범용 바이트코드 VM, 자동 복제·라이브 이동을 추가하지 않는다.
+고정 바이트 예산과 처리량 목표는 대상 작업·기기·보장을 확정한 뒤 결정한다.
diff --git a/docs/design/abi-v0.h b/docs/design/abi-v0.h
new file mode 100644
index 0000000..dc53310
--- /dev/null
+++ b/docs/design/abi-v0.h
@@ -0,0 +1,76 @@
+/* Draft data records for Pure's in-process byte-stream profile (0.1).
+ * No module loader or callable function table is implemented by this header.
+ * These records use native endianness and are NOT a file/wire format.
+ */
+#ifndef PURE_DRAFT_ABI_V0_H
+#define PURE_DRAFT_ABI_V0_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#define PURE_ABI_MAJOR_V0 UINT32_C(0)
+#define PURE_ABI_MINOR_V0 UINT32_C(1)
+#define PURE_PROFILE_BYTE_STREAM_V0 UINT32_C(1)
+
+#define PURE_STEP_MORE_V0 UINT32_C(0)
+#define PURE_STEP_NEED_INPUT_V0 UINT32_C(1)
+#define PURE_STEP_NEED_OUTPUT_V0 UINT32_C(2)
+#define PURE_STEP_DONE_V0 UINT32_C(3)
+#define PURE_STEP_FAILED_V0 UINT32_C(4)
+#define PURE_STEP_CANCELLED_V0 UINT32_C(5)
+
+#define PURE_ERROR_NONE_V0 UINT32_C(0)
+#define PURE_ERROR_INVALID_V0 UINT32_C(1)
+#define PURE_ERROR_LIMIT_V0 UINT32_C(2)
+#define PURE_ERROR_UNSUPPORTED_V0 UINT32_C(3)
+#define PURE_ERROR_BACKEND_V0 UINT32_C(4)
+#define PURE_ERROR_TRUNCATED_V0 UINT32_C(5)
+#define PURE_ERROR_AUTH_V0 UINT32_C(6)
+
+typedef struct pure_handle_v0 {
+ uint32_t slot;
+ uint32_t generation;
+} pure_handle_v0;
+
+typedef struct pure_span_v0 {
+ pure_handle_v0 buffer;
+ uint32_t offset;
+ uint32_t length;
+} pure_span_v0;
+
+typedef struct pure_step_result_v0 {
+ uint32_t struct_bytes;
+ uint32_t status;
+ uint32_t error;
+ uint32_t consumed;
+ uint32_t produced;
+ uint32_t reserved;
+} pure_step_result_v0;
+
+typedef struct pure_stream_limits_v0 {
+ uint32_t struct_bytes;
+ uint32_t abi_major;
+ uint32_t abi_minor;
+ uint32_t profile;
+ uint32_t flags;
+ uint32_t input_count;
+ uint32_t output_count;
+ uint32_t max_pending_per_context;
+ uint64_t context_budget_bytes;
+ uint64_t scratch_budget_bytes;
+ uint32_t max_input_bytes;
+ uint32_t max_output_bytes;
+ uint32_t buffer_alignment;
+ uint32_t reserved;
+} pure_stream_limits_v0;
+
+_Static_assert(sizeof(pure_handle_v0) == 8, "handle record size");
+_Static_assert(sizeof(pure_span_v0) == 16, "span record size");
+_Static_assert(offsetof(pure_span_v0, offset) == 8, "span offset field");
+_Static_assert(sizeof(pure_step_result_v0) == 24, "step result size");
+_Static_assert(offsetof(pure_step_result_v0, produced) == 16, "produced field");
+_Static_assert(sizeof(pure_stream_limits_v0) == 64, "stream limits size");
+_Static_assert(offsetof(pure_stream_limits_v0, context_budget_bytes) == 32, "context budget field");
+_Static_assert(offsetof(pure_stream_limits_v0, max_input_bytes) == 48, "input bound field");
+
+#endif
diff --git a/docs/design/check-abi-layout.py b/docs/design/check-abi-layout.py
new file mode 100644
index 0000000..7832aff
--- /dev/null
+++ b/docs/design/check-abi-layout.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+"""Compile draft record assertions only; does not test a callable module ABI."""
+import argparse
+from datetime import datetime, timezone
+import hashlib
+import json
+import os
+from pathlib import Path
+import shutil
+import subprocess
+import tempfile
+
+root = Path(__file__).resolve().parent
+parser = argparse.ArgumentParser(description=__doc__)
+parser.add_argument('--zig', default='zig')
+parser.add_argument('--output', type=Path)
+args = parser.parse_args()
+zig = shutil.which(args.zig)
+if not zig:
+ parser.error('Zig 0.15.2 required; use --zig /path/to/zig')
+version = subprocess.check_output([zig, 'version'], text=True).strip()
+if version != '0.15.2':
+ parser.error(f'This check is pinned to Zig 0.15.2; found {version}')
+header = root / 'abi-v0.h'
+checks = []
+with tempfile.TemporaryDirectory(prefix='pure-abi-layout-') as cache:
+ env = dict(os.environ, ZIG_GLOBAL_CACHE_DIR=cache)
+ for target in ['aarch64-linux-gnu', 'aarch64-macos-none', 'wasm32-freestanding']:
+ command = [zig, 'cc', '-target', target, '-std=c17', '-ffreestanding',
+ '-Wall', '-Wextra', '-Werror', '-x', 'c', '-c', str(header),
+ '-o', str(Path(cache) / f'{target}.o')]
+ result = subprocess.run(command, env=env, capture_output=True, text=True)
+ checks.append({'target': target, 'command': command, 'exitCode': result.returncode,
+ 'stdout': result.stdout, 'stderr': result.stderr})
+report = {'recordedUtc': datetime.now(timezone.utc).isoformat(), 'zigVersion': version,
+ 'scope': 'Cross-compilation of C17 record sizes/offset assertions only. No target execution, function calls, module loading, memory enforcement, or performance measurement.',
+ 'headerSha256': hashlib.sha256(header.read_bytes()).hexdigest(),
+ 'checkerSha256': hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
+ 'assertionsPerTarget': 8, 'checks': checks,
+ 'passed': all(check['exitCode'] == 0 for check in checks)}
+encoded = json.dumps(report, indent=2) + '\n'
+if args.output:
+ with args.output.open('x') as stream:
+ stream.write(encoded)
+print(encoded, end='')
+raise SystemExit(0 if report['passed'] else 1)
diff --git a/docs/design/validation/2026-09-22-record-layout.json b/docs/design/validation/2026-09-22-record-layout.json
new file mode 100644
index 0000000..7158525
--- /dev/null
+++ b/docs/design/validation/2026-09-22-record-layout.json
@@ -0,0 +1,80 @@
+{
+ "recordedUtc": "2026-09-22T11:52:02.452411+00:00",
+ "zigVersion": "0.15.2",
+ "scope": "Cross-compilation of C17 record sizes/offset assertions only. No target execution, function calls, module loading, memory enforcement, or performance measurement.",
+ "headerSha256": "bbdd54e9b55df26c654a6f5fed2f16cd6f90aeca2d17f88f42774beec214e637",
+ "checkerSha256": "07bd674d124b74e7926dab8ada525b570c727bbaf94a5c17d98e8438b8ada56a",
+ "assertionsPerTarget": 8,
+ "checks": [
+ {
+ "target": "aarch64-linux-gnu",
+ "command": [
+ "/tmp/pure-zig-0.15.2/zig",
+ "cc",
+ "-target",
+ "aarch64-linux-gnu",
+ "-std=c17",
+ "-ffreestanding",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-x",
+ "c",
+ "-c",
+ "/home/eunhhu/work/pure/docs/design/abi-v0.h",
+ "-o",
+ "/tmp/pure-abi-layout-w__551sp/aarch64-linux-gnu.o"
+ ],
+ "exitCode": 0,
+ "stdout": "",
+ "stderr": ""
+ },
+ {
+ "target": "aarch64-macos-none",
+ "command": [
+ "/tmp/pure-zig-0.15.2/zig",
+ "cc",
+ "-target",
+ "aarch64-macos-none",
+ "-std=c17",
+ "-ffreestanding",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-x",
+ "c",
+ "-c",
+ "/home/eunhhu/work/pure/docs/design/abi-v0.h",
+ "-o",
+ "/tmp/pure-abi-layout-w__551sp/aarch64-macos-none.o"
+ ],
+ "exitCode": 0,
+ "stdout": "",
+ "stderr": ""
+ },
+ {
+ "target": "wasm32-freestanding",
+ "command": [
+ "/tmp/pure-zig-0.15.2/zig",
+ "cc",
+ "-target",
+ "wasm32-freestanding",
+ "-std=c17",
+ "-ffreestanding",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-x",
+ "c",
+ "-c",
+ "/home/eunhhu/work/pure/docs/design/abi-v0.h",
+ "-o",
+ "/tmp/pure-abi-layout-w__551sp/wasm32-freestanding.o"
+ ],
+ "exitCode": 0,
+ "stdout": "",
+ "stderr": ""
+ }
+ ],
+ "passed": true
+}