From 5a2292a389989b71b99ea582cf306cf1719d8aae Mon Sep 17 00:00:00 2001 From: eunhhu Date: Mon, 19 Oct 2026 04:09:58 +0100 Subject: 028: bytes alone as a state (140's decision point: inflate and HTTP both met it): state type 6 a module's bytes, held as a text is (one draft, app->texts) with state_bytes marking it, no new opcode (TEXT_LOAD gives and TEXT_SET takes bytes for it), no anchor in it; one store file text-NAME, the values record (PVS1) marking each bytes state (kind 7, its name) so a text file that is no UTF-8 is a move when the record says bytes (the initial value) and corruption when it does not (store_error, as before); text and bytes carried over each other when exact (text to bytes always, bytes to text when UTF-8), on a replace and on a start, A to B to A raising no stale value; aup's state x: bytes; the checks planned, two names for the file and a new runtime kind turned down, list sharing and emptying left for when their cost shows --- docs/design/028-bytes-state.md | 77 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 docs/design/028-bytes-state.md (limited to 'docs/design') 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%를 넘게 바뀌면 멈추고 어디를 건드렸는지 찾는다. -- cgit v1.2.3