aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/design/028-bytes-state.md77
1 files changed, 77 insertions, 0 deletions
diff --git a/docs/design/028-bytes-state.md b/docs/design/028-bytes-state.md
new file mode 100644
index 0000000..9396105
--- /dev/null
+++ b/docs/design/028-bytes-state.md
@@ -0,0 +1,77 @@
+# 028 — 바이트 하나인 상태
+
+작성일: 2026-10-19. 상태: 설계. [140](../research/140-spec-suite.md)의 "027 뒤의 결정점"에서 써서 닿은 명세가 둘(inflate,
+HTTP/1.1)이 된 틈이다. 쌓임을 막는 규칙(둘 이상의 명세)을 넘으므로 핵에 들인다. 같은 결정점의 다른 하나(바이트의 `==`)는
+TEXT_COMPARE의 인자 비트로 이미 만들었다(008).
+
+## 쉬운 말로
+
+- **지금.** 상태의 종류는 수, text, 앵커, 리스트, bool, i64다. 바이트 하나를 상태로 두려면 항목 하나의 리스트로 우회한다.
+ inflate는 풀어낸 바이트를, HTTP/1.1은 패킷 사이에 남은 바이트를 그렇게 둔다. 이벤트마다 항목을 지우고 다시 붙인다.
+- **이 설계.** 상태의 타입에 bytes를 더한다. 표현은 text와 하나(draft)이고 타입만 다르다(027의 의심: "표현은 하나이고 타입만
+ 둘이다"). 새 명령은 없다. TEXT_LOAD와 TEXT_SET이 상태의 타입대로 바이트를 내고 받는다.
+- **옮기기.** 이름이 같은 text와 bytes는 정확할 때만 서로 옮긴다(5단계의 규칙): text는 언제나 bytes가 되고, bytes는 UTF-8일
+ 때만 text가 된다.
+
+## 꼴
+
+- **형식.** 상태 타입 6이 bytes다. 8바이트 값은 text처럼 u32 초기 상수다. 상수는 UTF-8을 묻는 표에 있으므로 초기값은 UTF-8의
+ 바이트다(보통 빈 것). 판은 v7 그대로다. v6에 i64를 더할 때처럼 1.0 전이라 판을 올리지 않는다.
+- **런타임.** text 상태와 같은 draft(`app->texts`)에 담고, 모듈의 `state_bytes[i]`가 그 타입을 적는다. 상태의 종류(PureStateType)는
+ text 그대로다. text를 다루는 길(교체, 저장, 메모리 셈, 스냅숏)이 모두 그대로 쓰인다.
+- **검증.** bytes 상태의 TEXT_LOAD는 바이트를 놓고, TEXT_SET은 바이트를 받는다. 앵커는 bytes 상태를 가리키지 못한다. 그래서 커서를
+ 받는 TEXT_INSERT, TEXT_REMOVE, TEXT_LINE도 쓰이지 않는다.
+- **저장.** 파일은 text와 같은 `text-이름` 하나다. bytes 상태를 열 때는 UTF-8을 묻지 않는다. 그 상태가 bytes라는 것은 `values`
+ 기록(`PVS1`)에 적는다: 수·bool·i64·앵커의 항목 옆에, bytes 상태마다 종류 7(저장의 표시)과 이름의 항목(값 8바이트는 0)이다.
+ `values`는 저장할 때마다 새로 짠 것과 견줘 다르면 다시 쓰이므로, bytes 상태를 처음 저장하는 커밋이 그 표시도 함께 쓴다.
+- **손상과 옮김을 가르기.** text 상태의 파일이 UTF-8이 아닐 때, `values`가 그 이름을 bytes로 적고 있으면 타입이 바뀐 것이다(옮김의
+ 규칙으로 초기값). 적고 있지 않으면 손상이다(시작을 `store_error`로 멈춘다, 조용히 버리지 않는다).
+- **교체와 시작.** 실행 중의 교체는 앞 모듈의 타입을 알므로 기록 없이 옮긴다(text → bytes는 그대로, UTF-8인 bytes → text는
+ 그대로, 아니면 초기값). 저장소에서 시작할 때는 위의 기록으로 가른다. 파일이 하나라 A(text) → B(bytes) → A를 오가도 낡은 값이
+ 되살아나지 않는다: A는 B가 쓴 바이트를 같은 규칙으로 읽는다.
+ - 레코드 필드는 지금 bytes → text가 기본값이다(008). 메시지 필드는 UTF-8이면 옮긴다. 셋을 "정확할 때"로 하나 맞추는 것은
+ 따로 한다.
+- **보기와 경계.** bytes 상태를 읽는 보기는 바이트 보기다(027의 4e). HTTP의 GET은 `application/octet-stream`이다. pure-run은
+ 16진 문자열로 보여 준다.
+- **메모리.** text처럼 그 바이트를 상태의 예산에 센다.
+- **Vega.** text 상태를 직접 읽지 않고 보기를 읽으므로 바뀌지 않는다.
+
+## aup
+
+- `state data: bytes`는 빈 바이트로 시작한다. `state data: bytes = "..."`는 그 문자열의 UTF-8로 시작한다.
+- 이름은 바이트 값으로 읽힌다(`data.bytes`, `data[i]`, `data[a .. b]`, 비교, 잇기). `data = …`가 바이트를 쓴다. 문자열은 바이트를
+ 만나므로 `data = "x"`도 된다.
+- `cursor in data`, `mark in data`는 거절한다.
+
+## 검증
+
+- Pure 단위 시험: bytes 상태의 읽기와 쓰기(0x00, 0xff), 거절(앵커, text를 받는 TEXT_SET, bytes를 받는 text의 TEXT_SET), 저장소에서
+ 다시 시작(UTF-8이 아닌 바이트가 남는다), 교체(text → bytes, UTF-8인 bytes → text, 아닌 것은 초기값), 저장소에서 타입이 바뀐 시작.
+ text → bytes → text를 두 번의 다시 시작으로(사이에 UTF-8이 아닌 저장), 그리고 실행 중의 교체로. 기록이 없는데 UTF-8이 아닌 text
+ 파일은 여전히 `store_error`다.
+- 모듈의 모양을 견주는 곳(교체의 `was == now`, 질의 모듈과 교체를 받아들이는 serve의 길)이 bytes의 표시도 견주는지 본다.
+- aup 검사: 진단(커서와 마크), 저장소에서 여러 번 다시 시작하는 앱.
+- 명령 수: 041의 다섯 일, 은행 질의. 실행기의 걸음을 건드리지 않아야 한다(TEXT_LOAD와 TEXT_SET은 같은 걸음이다).
+- 140의 우회 걷어내기: inflate의 `inflated`, HTTP의 `pending`. 줄 수와 시간을 다시 잰다.
+
+## 대안과 왜 아닌가
+
+- **새 런타임 종류(PURE_STATE_BYTES).** text를 다루는 곳(교체, 저장, 스냅숏, 메모리 셈)마다 갈래가 는다. 표현이 같으므로 표시
+ 하나가 압축이다.
+- **저장소의 이름을 둘로(`bytes-이름`).** 손상과 옮김을 이름으로 가를 수 있지만, 타입이 바뀔 때 다른 이름의 파일이 남는다.
+ 저장소에는 draft를 지우는 길이 없으므로, A(text) → B(bytes) → A에서 A가 낡은 `text-이름`을 되살린다. 그래서 파일은 하나로 두고
+ 타입을 `values`에 적는다.
+- **바이트를 담는 리스트 항목(지금의 우회).** 뜻은 같지만 앱이 "항목 하나"라는 꼴을 지어야 한다. 그 꼴이 명세의 개념(바이트)이 아니다.
+
+## 따로 남긴 것
+
+- **리스트 값의 나눔.** let의 리스트를 값으로 넘기면 Pure의 LIST_VALUE가 항목을 하나씩 복사한다. 복사 없이 나누려면 이벤트
+ 도중의 리스트가 쓰기 전 복사(copy-on-write)를 해야 한다. 지금의 `pure_list_share`는 이벤트 사이의, 다른 스레드의 읽는 쪽을 위한
+ 것이다. 명세가 그 비용에 닿으면 정한다.
+- **한 번에 비우기.** 블록 안의 let 리스트와 `xs = [...]`는 항목을 하나씩 지운다. 명령 하나로 비울지는 그 비용이 보이면 정한다.
+
+## 착수 기준
+
+- **바꿀 결정.** bytes를 상태의 타입으로 들인다.
+- **최소 확인.** 위 검증 모두.
+- **중단 기준.** 실행기만의 길이나 묶음 실행기의 명령 수가 1%를 넘게 바뀌면 멈추고 어디를 건드렸는지 찾는다.