aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile58
-rw-r--r--README.md18
-rw-r--r--benchmarks/http/README.md2
-rw-r--r--benchmarks/http/run.py5
-rw-r--r--cli/edit-module.c (renamed from prototypes/connections/edit-module.c)0
-rw-r--r--cli/pure-run.c (renamed from prototypes/connections/pure-run.c)0
-rw-r--r--core/flow.c (renamed from prototypes/connections/flow.c)0
-rw-r--r--core/flow.h (renamed from prototypes/connections/flow.h)0
-rw-r--r--core/module-list.c (renamed from prototypes/connections/module-list.c)0
-rw-r--r--core/module-list.h (renamed from prototypes/connections/module-list.h)0
-rw-r--r--core/module-save.c (renamed from prototypes/connections/module-save.c)0
-rw-r--r--core/module-save.h (renamed from prototypes/connections/module-save.h)0
-rw-r--r--core/module-store.c (renamed from prototypes/connections/module-store.c)0
-rw-r--r--core/module-store.h (renamed from prototypes/connections/module-store.h)0
-rw-r--r--core/module-text.c (renamed from prototypes/connections/module-text.c)0
-rw-r--r--core/module-text.h (renamed from prototypes/connections/module-text.h)0
-rw-r--r--core/module.c (renamed from prototypes/connections/module.c)0
-rw-r--r--core/module.h (renamed from prototypes/connections/module.h)0
-rw-r--r--core/result.h (renamed from prototypes/connections/result.h)0
-rw-r--r--core/runtime.c (renamed from prototypes/connections/runtime.c)0
-rw-r--r--core/runtime.h (renamed from prototypes/connections/runtime.h)0
-rw-r--r--core/state.h (renamed from prototypes/connections/state.h)0
-rw-r--r--core/store.h (renamed from prototypes/connections/store.h)0
-rw-r--r--core/test-module.c (renamed from prototypes/connections/test-module.c)0
-rw-r--r--docs/design/008-module-format.md4
-rw-r--r--docs/design/009-layout.md60
-rw-r--r--docs/research/018-native-connections.md2
-rw-r--r--docs/research/019-byte-storage.md2
-rw-r--r--docs/research/030-authenticated-document-peer.md2
-rw-r--r--docs/research/064-release-callback-reentrancy.md2
-rw-r--r--docs/research/066-application-boundary.md2
-rw-r--r--docs/research/073-single-file-persistent-tree.md2
-rw-r--r--docs/research/074-runtime-owned-drafts.md4
-rw-r--r--docs/research/075-http-host-against-axum.md2
-rw-r--r--docs/research/076-one-sync-commit.md2
-rw-r--r--prototypes/connections/Makefile80
-rw-r--r--prototypes/connections/README.md5
-rw-r--r--prototypes/connections/check.py8
-rw-r--r--prototypes/connections/package_source.py2
-rwxr-xr-xresearch/experiments/009-runtime-drafts/run.py8
-rw-r--r--research/experiments/010-one-sync-commit/run.py15
-rwxr-xr-xresearch/experiments/012-tail-records/run.py15
-rw-r--r--serve/deliver.c (renamed from prototypes/connections/deliver.c)0
-rw-r--r--serve/deliver.h (renamed from prototypes/connections/deliver.h)0
-rw-r--r--serve/message-json.c (renamed from prototypes/connections/message-json.c)0
-rw-r--r--serve/message-json.h (renamed from prototypes/connections/message-json.h)0
-rw-r--r--serve/serve.c (renamed from prototypes/connections/serve.c)0
-rw-r--r--store/store-tree.c (renamed from prototypes/connections/store-tree.c)0
-rw-r--r--store/test-tree-store.c (renamed from prototypes/connections/test-tree-store.c)0
50 files changed, 222 insertions, 79 deletions
diff --git a/.gitignore b/.gitignore
index c00450a..4d30289 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ __pycache__/
/benchmarks/http/axum-baseline/target/
/benchmarks/http/load
/benchmarks/http/*.pmod
+/build/
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..50448da
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,58 @@
+CC ?= cc
+AR ?= ar
+CFLAGS ?= -O2 -g
+CFLAGS += -std=c17 -Wall -Wextra -Wpedantic -Werror
+BUILD ?= build
+
+# Pure is a small core with the rest selected around it:
+# core/ execution, ownership, limits and completion (runtime), and the app
+# model: modules verified before they run, events as transactions,
+# states as drafts; state.h and store.h are what it asks of storage.
+# store/ the tree store (one file; commits are one contiguous write and one
+# sync; formats PURETRE3 and PUREREC1).
+# serve/ pure-serve: the HTTP host, outbound delivery, JSON in place.
+# cli/ command-line hosts.
+# libpure.a is the app model with the tree store: what a host embeds (Vega's
+# surfaces link it). prototypes/ keeps the earlier document runtime (000-077).
+INCLUDES = -Icore
+MODEL = core/module.c core/module-list.c core/module-save.c core/module-text.c core/module-store.c core/flow.c
+STORE = store/store-tree.c
+SERVE = serve/serve.c serve/deliver.c serve/message-json.c
+HEADERS = $(wildcard core/*.h) $(wildcard serve/*.h)
+OBJECTS = $(patsubst %.c,$(BUILD)/obj/%.o,$(MODEL) $(STORE))
+
+.PHONY: all check
+all: $(BUILD)/libpure.a $(BUILD)/pure-serve $(BUILD)/pure-run $(BUILD)/pure-edit-module
+
+$(BUILD)/obj/%.o: %.c $(HEADERS)
+ @mkdir -p $(dir $@)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) -c $< -o $@
+
+$(BUILD)/libpure.a: $(OBJECTS)
+ rm -f $@
+ $(AR) rcs $@ $^
+
+# The runtime's tickets and budgets, with effects completed off the owner thread.
+$(BUILD)/pure-serve: $(SERVE) core/runtime.c $(BUILD)/libpure.a $(HEADERS)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) -Iserve -DPURE_ASYNC_EFFECTS $(SERVE) core/runtime.c $(BUILD)/libpure.a \
+ $(LDFLAGS) -lssl -lcrypto -lm -pthread $(LDLIBS) -o $@
+
+$(BUILD)/pure-run: cli/pure-run.c $(BUILD)/libpure.a $(HEADERS)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) cli/pure-run.c $(BUILD)/libpure.a $(LDFLAGS) -lm $(LDLIBS) -o $@
+
+# The document CLI contract, driven by a module on the tree store.
+$(BUILD)/pure-edit-module: cli/edit-module.c $(BUILD)/libpure.a $(HEADERS)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) cli/edit-module.c $(BUILD)/libpure.a $(LDFLAGS) -lm $(LDLIBS) -o $@
+
+# Tests build their own copies: the store's fault hooks exist only under PURE_STORE_TEST.
+$(BUILD)/test-module: core/test-module.c $(MODEL) $(STORE) $(HEADERS)
+ @mkdir -p $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) -DPURE_STORE_TEST core/test-module.c $(MODEL) $(STORE) $(LDFLAGS) -pthread -lm $(LDLIBS) -o $@
+
+$(BUILD)/test-tree-store: store/test-tree-store.c $(STORE) $(HEADERS)
+ @mkdir -p $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) -DPURE_STORE_TEST store/test-tree-store.c $(STORE) $(LDFLAGS) $(LDLIBS) -o $@
+
+check: all $(BUILD)/test-module $(BUILD)/test-tree-store
+ $(BUILD)/test-tree-store
+ $(BUILD)/test-module
diff --git a/README.md b/README.md
index 3108736..c7c7958 100644
--- a/README.md
+++ b/README.md
@@ -11,8 +11,22 @@ batches, and a receiving app applies each message once. Measurements against axu
are in [075](docs/research/075-http-host-against-axum.md), [077](docs/research/077-apps-as-http-services.md),
[080](docs/research/080-snapshot-reads.md), [081](docs/research/081-tail-records.md),
[082](docs/research/082-json-in-place.md) and [083](docs/research/083-delivery-over-http.md); the status table is
-[CHECKPOINT.md](CHECKPOINT.md). The text below
-records the earlier document runtime this grew from.
+[CHECKPOINT.md](CHECKPOINT.md).
+
+The source follows the principle below, a small core with the rest selected around it
+([layout](docs/design/009-layout.md)):
+
+| Directory | What | Built as |
+|---|---|---|
+| `core/` | execution, ownership, limits and completion (`runtime.c`); the app model: modules verified before they run, events as transactions, states as drafts (`module*.c`); what the core asks of storage (`state.h`, `store.h`) | `build/libpure.a` (with the store) |
+| `store/` | the tree store: one file, a commit is one contiguous write and one sync (formats `PURETRE3`, `PUREREC1`) | in `libpure.a` |
+| `serve/` | `pure-serve`: the HTTP host, outbound delivery, JSON read in place | `build/pure-serve` |
+| `cli/` | command-line hosts | `build/pure-run`, `build/pure-edit-module` |
+| `prototypes/` | the earlier document runtime (000-077), built against `core/` and `store/` | `make -C prototypes/connections` |
+
+`make` builds the library and the hosts, `make check` runs the store's and the app model's tests. Interfaces for
+people are [Vega](/srv/git/vega.git), which links `libpure.a`. The text below records the earlier document runtime
+this grew from.
A standalone native micro runtime being designed as a small operating
system. Pure owns the application model for execution, memory, protection,
diff --git a/benchmarks/http/README.md b/benchmarks/http/README.md
index af9f62d..22fc6d3 100644
--- a/benchmarks/http/README.md
+++ b/benchmarks/http/README.md
@@ -7,7 +7,7 @@ Pure의 문서 서버들과 같은 계약의 axum(Rust)·drogon(C++) 서비스�
cc -O2 -std=c17 -o load load.c
(cd axum-baseline && cargo build --release)
drogon-baseline/build.sh # Debian의 drogon 패키지를 설치하지 않고 .deps에 풀어 빌드한다
-make -C ../../prototypes/connections build/pure-serve
+make -C ../.. build/pure-serve
make -C ../../prototypes/connections BUILD=build/tree STORE=store-tree.c build/tree/pure-connections
aup build ../../../aup/examples/editor.aup -o editor.pmod
python3 run.py --module editor.pmod --directory /var/tmp # 저장소를 둘 장치에서
diff --git a/benchmarks/http/run.py b/benchmarks/http/run.py
index bad9cc4..4605226 100644
--- a/benchmarks/http/run.py
+++ b/benchmarks/http/run.py
@@ -38,7 +38,8 @@ import http.client
from pathlib import Path
HERE = Path(__file__).resolve().parent
-PURE = HERE.parent.parent / 'prototypes' / 'connections'
+PURE = HERE.parent.parent # build/pure-serve; the earlier document server stays in prototypes/connections
+PROTOTYPES = PURE / "prototypes" / "connections"
def start(args):
@@ -145,7 +146,7 @@ def main():
drogon = HERE / 'drogon-baseline/drogon-baseline'
base = Path(tempfile.mkdtemp(dir=args.directory, prefix='pure-http-bench-'))
servers = {
- 'pure-program': lambda d: [PURE / 'build/tree/pure-connections', '--program', PURE / 'examples/editor.pure',
+ 'pure-program': lambda d: [PROTOTYPES / 'build/tree/pure-connections', '--program', PROTOTYPES / 'examples/editor.pure',
'--store', d, '--port', '0', '--budget', str(args.budget)],
'pure-serve': lambda d: [PURE / 'build/pure-serve', '--module', args.module, '--store', d, '--port', '0',
'--budget', str(args.budget)],
diff --git a/prototypes/connections/edit-module.c b/cli/edit-module.c
index 3ce272e..3ce272e 100644
--- a/prototypes/connections/edit-module.c
+++ b/cli/edit-module.c
diff --git a/prototypes/connections/pure-run.c b/cli/pure-run.c
index cfc3b5c..cfc3b5c 100644
--- a/prototypes/connections/pure-run.c
+++ b/cli/pure-run.c
diff --git a/prototypes/connections/flow.c b/core/flow.c
index 1070c70..1070c70 100644
--- a/prototypes/connections/flow.c
+++ b/core/flow.c
diff --git a/prototypes/connections/flow.h b/core/flow.h
index 6e27c58..6e27c58 100644
--- a/prototypes/connections/flow.h
+++ b/core/flow.h
diff --git a/prototypes/connections/module-list.c b/core/module-list.c
index 2cd2b1c..2cd2b1c 100644
--- a/prototypes/connections/module-list.c
+++ b/core/module-list.c
diff --git a/prototypes/connections/module-list.h b/core/module-list.h
index a721ff0..a721ff0 100644
--- a/prototypes/connections/module-list.h
+++ b/core/module-list.h
diff --git a/prototypes/connections/module-save.c b/core/module-save.c
index 4149316..4149316 100644
--- a/prototypes/connections/module-save.c
+++ b/core/module-save.c
diff --git a/prototypes/connections/module-save.h b/core/module-save.h
index bc7adcc..bc7adcc 100644
--- a/prototypes/connections/module-save.h
+++ b/core/module-save.h
diff --git a/prototypes/connections/module-store.c b/core/module-store.c
index 7e759fd..7e759fd 100644
--- a/prototypes/connections/module-store.c
+++ b/core/module-store.c
diff --git a/prototypes/connections/module-store.h b/core/module-store.h
index d14ab3d..d14ab3d 100644
--- a/prototypes/connections/module-store.h
+++ b/core/module-store.h
diff --git a/prototypes/connections/module-text.c b/core/module-text.c
index 68c03b0..68c03b0 100644
--- a/prototypes/connections/module-text.c
+++ b/core/module-text.c
diff --git a/prototypes/connections/module-text.h b/core/module-text.h
index 4843928..4843928 100644
--- a/prototypes/connections/module-text.h
+++ b/core/module-text.h
diff --git a/prototypes/connections/module.c b/core/module.c
index 697e918..697e918 100644
--- a/prototypes/connections/module.c
+++ b/core/module.c
diff --git a/prototypes/connections/module.h b/core/module.h
index f62326b..f62326b 100644
--- a/prototypes/connections/module.h
+++ b/core/module.h
diff --git a/prototypes/connections/result.h b/core/result.h
index 8abb0f2..8abb0f2 100644
--- a/prototypes/connections/result.h
+++ b/core/result.h
diff --git a/prototypes/connections/runtime.c b/core/runtime.c
index 4a857c7..4a857c7 100644
--- a/prototypes/connections/runtime.c
+++ b/core/runtime.c
diff --git a/prototypes/connections/runtime.h b/core/runtime.h
index 70f5d08..70f5d08 100644
--- a/prototypes/connections/runtime.h
+++ b/core/runtime.h
diff --git a/prototypes/connections/state.h b/core/state.h
index 2bf78b0..2bf78b0 100644
--- a/prototypes/connections/state.h
+++ b/core/state.h
diff --git a/prototypes/connections/store.h b/core/store.h
index dbfa8f8..dbfa8f8 100644
--- a/prototypes/connections/store.h
+++ b/core/store.h
diff --git a/prototypes/connections/test-module.c b/core/test-module.c
index ccb3371..ccb3371 100644
--- a/prototypes/connections/test-module.c
+++ b/core/test-module.c
diff --git a/docs/design/008-module-format.md b/docs/design/008-module-format.md
index 3fd4d52..84aa97b 100644
--- a/docs/design/008-module-format.md
+++ b/docs/design/008-module-format.md
@@ -1,7 +1,7 @@
# Pure 모듈 형식 v5
-2026-09-25. 구현 `prototypes/connections/module.{h,c}`, `module-text.c`, `module-list.c`, 상태 저장 `module-save.c`,
-트리 저장소 연결 `module-store.c`.
+2026-09-25. 구현 `core/module.{h,c}`, `module-text.c`, `module-list.c`, 상태 저장 `module-save.c`,
+모듈 파일 읽기 `module-store.c`, 트리 저장소 `store/store-tree.c`, HTTP 호스트 `serve/`.
Pure가 실행하는 앱 정의의 형식이다. JVM이 class 파일 형식을 소유하듯 Pure가 이 형식과
검증 규칙을 소유한다. 생산자는 [aup](/srv/git/aup.git) 같은 툴체인이다. Pure는 소스·문법을 모르며,
diff --git a/docs/design/009-layout.md b/docs/design/009-layout.md
new file mode 100644
index 0000000..8cb9a78
--- /dev/null
+++ b/docs/design/009-layout.md
@@ -0,0 +1,60 @@
+# 009 — 배치: 코어와 고르는 부품
+
+2026-09-27. 저장소 경계와 범위가 일관되지 않다는 지적에서 정한 것.
+
+## 문제
+
+- README의 원칙은 "항상 있는 코어는 실행, 소유권, 자원 한도, 완료 규칙만 다룬다. 프로토콜, 저장소 구현, UI, 코덱은 앱에
+ 맞게 고른다"였다. 그런데 소스는 원칙과 다르게 놓여 있었다.
+- 지금 세대의 코어(모듈 검증·실행 `module*.c`), 트리 저장소(`store-tree.c`), HTTP 호스트(`serve.c`, `deliver.c`,
+ `message-json.c`)가 모두 `prototypes/connections/` 한 디렉터리에 이전 세대(000–077의 문서 런타임: `program.c`,
+ `store.c`, `server.c`, 편집기들)와 섞여 있었다. 이름만 보면 저장소는 형식 매직(`PURETRE2`)으로만 드러났고, 코어가
+ 어디서 끝나는지 알 수 없었다.
+- 소비자는 소스 파일 목록으로 연결했다. Vega는 Pure의 `.c` 여섯 개를 경로로 나열해 컴파일했다. Pure에 파일이 하나
+ 늘면 Vega가 깨진다.
+- 반면 사람을 위한 인터페이스(Vega)는 따로 된 저장소였다. 저장소와 네트워크는 "호스트 안"처럼 보이고 UI만 부품처럼
+ 보였다.
+
+## 규칙
+
+1. **역할로 나누고 역할로 부른다.** 코어, 저장소, HTTP 호스트, 명령행 호스트. 형식 이름(`PURETRE3`, `PUREREC1`)은
+ 형식의 이름일 뿐 부품의 이름이 아니다.
+2. **부품은 라이브러리와 헤더로 쓴다.** 소비자는 파일 목록이 아니라 `libpure.a`와 `core/`의 헤더로 연결한다.
+3. **저장소(git) 경계는 결합도로 정한다.** 함께 바뀌는 것은 한 저장소에 두고 디렉터리로 나누며, 따로 바뀌는 것은 저장소를
+ 나눈다. 부품이 된 디렉터리는 나중에 `git subtree split`으로 그대로 떼어 낼 수 있다.
+
+## 배치
+
+| 디렉터리 | 역할 | 만드는 것 |
+|---|---|---|
+| `core/` | 실행·소유권·한도·완료(`runtime.c`, `flow.c`), 앱 모델(`module*.c`: 실행 전에 검증한 모듈, 트랜잭션인 이벤트, draft인 상태), 코어가 저장소에 요구하는 것(`state.h`, `store.h`) | `build/libpure.a`(저장소와 함께) |
+| `store/` | 트리 저장소. 한 파일, 커밋은 한 연속 쓰기와 동기화 한 번 | `libpure.a` 안 |
+| `serve/` | `pure-serve`: HTTP 호스트, 나가는 전달, 제자리 JSON | `build/pure-serve` |
+| `cli/` | 명령행 호스트 | `build/pure-run`, `build/pure-edit-module` |
+| `prototypes/` | 이전 문서 런타임. `core/`와 `store/`를 가져다 빌드한다 | `make -C prototypes/connections` |
+
+저장소 계약(`state.h`, `store.h`)은 코어 쪽에 둔다. 코어가 필요한 것을 정하고 저장소 구현이 그것을 채운다. 트리
+저장소는 그 계약의 한 구현이다(이전 세대의 `store.c`, `store-paged.c`도 `store.h`의 구현이다).
+
+## 왜 저장소를 따로 된 git 저장소로 떼지 않았나
+
+트리 저장소를 바꾼 최근 커밋 12개 중 9개가 계약(`state.h`, `store.h`)을 바꿨고, 그중 5개는 같은 커밋에서 코어나 호스트도
+바꿨다. 스냅숏(`571824a`: 저장소 동결 + 모듈 리스트 공유 + 모듈 스냅숏), 대여(`1a3586d`: 저장소 익스텐트 + serve), 그룹
+커밋(`d4b01a7`), 샤딩(`694b60f`), 매핑을 나누는 핸들(`89d1777`: + 모듈 파일 읽기). 계약이 아직 코어와 함께 움직이고
+소비자가 Pure 하나뿐이다. 따로 된 저장소면 이런
+변경마다 두 저장소의 버전을 맞춰야 한다. 두 번째 소비자(예: 메신저의 메시지 저장)가 생기거나 계약이 멈추면 `store/`를
+그대로 떼어 낸다.
+
+## 왜 Vega는 따로이고 이름이 pure-ui가 아닌가
+
+Vega는 두 가지다. aup 라이브러리(`use vega`: 목록·표·포커스·톤 같은 인터페이스 어휘)와 그 어휘를 사람에게 보이는
+표면들(TUI, CLI, NUI, 웹, 심볼과 GPU)이다. 어휘는 aup의 언어 기능과 함께 바뀌고, 표면은 Pure의 모듈 API(`libpure.a`)
+위에 있다. Vega의 최근 커밋은 모두 Vega 안에서 끝났다. `pure-serve`가 Pure 안에 있는 것은 프로그램을 위한 표면(보기가
+GET, 입력이 POST)에는 어휘가 필요 없기 때문이다. 모듈 형식만으로 정해진다. 사람을 위한 표면은 어휘가 필요하다. JDK가
+`java.net`과 HTTP 서버를 담고 JavaFX를 따로 두는 것과 같은 선이다. `pure-ui`라는 이름은 UI가 런타임의 일부라는 뜻이
+되어, 런타임이 화면을 모른다는 분리와 어긋난다.
+
+## 확인
+
+최상위 `make check`(저장소와 앱 모델의 검사), `prototypes/connections`의 `make check`·`check-tree`·`check-core`, aup
+`make check`, Vega `make check`가 새 배치에서 통과한다. Vega는 이제 `libpure.a`를 링크한다.
diff --git a/docs/research/018-native-connections.md b/docs/research/018-native-connections.md
index f2c26bc..6747dd8 100644
--- a/docs/research/018-native-connections.md
+++ b/docs/research/018-native-connections.md
@@ -66,7 +66,7 @@ DB 호출은 아직 동기식이므로 디스크 작업 중 다른 연결 처리
동적 링크한 SQLite 자체를 sanitizer로 다시 빌드한 것은 아니다.
[원자료·재현](../../prototypes/connections/results/2026-09-23-native-connections/README.md),
-[전송 수명](../../prototypes/connections/flow.c),
+[전송 수명](../../core/flow.c),
[DB 연결](../../prototypes/connections/store.c),
[호스트](../../prototypes/connections/server.c),
[기존 CLI 연결](../../prototypes/workbench/remote.mjs).
diff --git a/docs/research/019-byte-storage.md b/docs/research/019-byte-storage.md
index faefecf..b58adcd 100644
--- a/docs/research/019-byte-storage.md
+++ b/docs/research/019-byte-storage.md
@@ -72,7 +72,7 @@ Linux AArch64에서 일반 빌드와 ASan·UBSan 빌드가 모두 통과했다.
[원자료와 재현](../../prototypes/connections/results/2026-09-23-byte-storage/README.md),
[직접 저장 구현](../../prototypes/connections/store.c),
-[구간·수명 API](../../prototypes/connections/store.h).
+[구간·수명 API](../../core/store.h).
018의 원자료는 당시 SQLite 구현의 기록으로 별도 보존한다.
## 다음 결정
diff --git a/docs/research/030-authenticated-document-peer.md b/docs/research/030-authenticated-document-peer.md
index 1ff569d..6e1fa23 100644
--- a/docs/research/030-authenticated-document-peer.md
+++ b/docs/research/030-authenticated-document-peer.md
@@ -9,7 +9,7 @@
`pure-document-peer`는 TLS 1.3/TCP의 상호 인증, 인증서 SAN 이름 확인, `pure-doc/1`
ALPN 뒤에 자체 이진 메시지를 사용한다. 이미 구현한 scalar 피어의 소켓·TLS 부분을
[`tls-link.c`](../../prototypes/common/tls-link.c)로 분리해 두 피어가 재사용한다.
-코어의 [`runtime.c`](../../prototypes/connections/runtime.c), 저장소, `editor.pure`는
+코어의 [`runtime.c`](../../core/runtime.c), 저장소, `editor.pure`는
문서 CLI와 같다. 전송 코드는 선택 빌드의 호스트에만 있다.
서버가 보내는 40 B hello는 `PDOC`, 버전 1, 예약 3 B, **원본 .pure 소스** SHA-256이다.
diff --git a/docs/research/064-release-callback-reentrancy.md b/docs/research/064-release-callback-reentrancy.md
index 68ce819..f35f6ec 100644
--- a/docs/research/064-release-callback-reentrancy.md
+++ b/docs/research/064-release-callback-reentrancy.md
@@ -5,7 +5,7 @@
`running`이 꺼져 있었다. 콜백이 같은 영역의 티켓을 해제하거나 새 작업을
받아들이면, 바깥쪽 회수 코드가 작업 슬롯과 예산 장부를 계속 수정할 수 있었다.
-[`runtime.c`](../../prototypes/connections/runtime.c)는 자원 해제 콜백 동안 해당
+[`runtime.c`](../../core/runtime.c)는 자원 해제 콜백 동안 해당
영역을 실행 중으로 표시하고 이전 상태를 복원한다. 새 상태 필드나 작업별
할당은 없다. [`test-runtime.c`](../../prototypes/connections/test-runtime.c)는
취소, 대기 작업 해제, 유효하지 않은 호스트 할당 반환에서 콜백이 같은 티켓을
diff --git a/docs/research/066-application-boundary.md b/docs/research/066-application-boundary.md
index 44e6d86..bb96bed 100644
--- a/docs/research/066-application-boundary.md
+++ b/docs/research/066-application-boundary.md
@@ -5,7 +5,7 @@
## 현재 코드가 증명하는 것과 못 하는 것
-`prototypes/connections/runtime.c`는 입력 접수, 바이트 예산, 작업 슬롯, 완료,
+`core/runtime.c`는 입력 접수, 바이트 예산, 작업 슬롯, 완료,
대여와 다른 영역으로의 무복사 전달을 소유한다. 하지만 실행 단계에서
`PureProgram`의 저장 전용 `read`/`write`/`splice`를 직접 해석하고
`PureHost.read`/`write`/`splice`를 호출한다. 따라서 현재 5,980 B 코어는
diff --git a/docs/research/073-single-file-persistent-tree.md b/docs/research/073-single-file-persistent-tree.md
index 13884e3..4386e93 100644
--- a/docs/research/073-single-file-persistent-tree.md
+++ b/docs/research/073-single-file-persistent-tree.md
@@ -74,7 +74,7 @@ Ctrl+S부터 저장 완료 프레임까지 잰다. 1 MiB 문서, 저장소별 3�
## 검증
-[`test-tree-store.c`](../../prototypes/connections/test-tree-store.c)는 ASan·UBSan에서도 통과했다.
+[`test-tree-store.c`](../../store/test-tree-store.c)는 ASan·UBSan에서도 통과했다.
- 4개 키에 6,000회 무작위 편집을 평면 배열 오라클과 매번 비교했다(최대 333,510 B, 높이 2).
매 편집 뒤 저장된 모든 비루트 노드가 기준 이상으로 채워졌는지 확인했다.
diff --git a/docs/research/074-runtime-owned-drafts.md b/docs/research/074-runtime-owned-drafts.md
index 71ac8c9..42fd417 100644
--- a/docs/research/074-runtime-owned-drafts.md
+++ b/docs/research/074-runtime-owned-drafts.md
@@ -1,7 +1,7 @@
# 074 — 작업 중인 값을 런타임이 소유한다
2026-09-25. [073](073-single-file-persistent-tree.md)의 선택형 트리 저장소 위에 런타임 API
-[`state.h`](../../prototypes/connections/state.h)를 추가했다. 기본 빌드와 기본 저장 형식은 바뀌지 않았다.
+[`state.h`](../../core/state.h)를 추가했다. 기본 빌드와 기본 저장 형식은 바뀌지 않았다.
Pure는 JVM과 같은 위치의 런타임이다. 앱 기능은 별도 저장소에서 만들고, 이 저장소의 CLI·TUI·
HTTP 호스트는 런타임을 검사하는 호스트다. 따라서 이번 단계는 편집기 기능이 아니라 모든 앱이 쓰는
@@ -61,7 +61,7 @@ draft가 가진 옛 매핑에서 필요한 노드를 새 파일로 복사한다(
## 검증
-[`test-tree-store.c`](../../prototypes/connections/test-tree-store.c) 추가 검사는 ASan·UBSan을 포함해 통과했다.
+[`test-tree-store.c`](../../store/test-tree-store.c) 추가 검사는 ASan·UBSan을 포함해 통과했다.
- 20,000회 무작위 편집을 draft에서 평면 오라클과 비교하고 1,000회마다 커밋했다(최종 419,324 B, 커밋 20회).
커밋 뒤에는 저장본 일치, revision 증가, 빈 arena를 확인했다.
diff --git a/docs/research/075-http-host-against-axum.md b/docs/research/075-http-host-against-axum.md
index 17cfe39..77be305 100644
--- a/docs/research/075-http-host-against-axum.md
+++ b/docs/research/075-http-host-against-axum.md
@@ -55,7 +55,7 @@ PUT은 연결마다 자기 키 앞에 16 B를 넣고 받은 ETag로 다음 `If-M
## 1단계 결과: `pure-serve` (소유 스레드 하나)
-새 호스트 [`serve.c`](../../prototypes/connections/serve.c): 지속 연결·파이프라이닝, edge-triggered epoll, 연결
+새 호스트 [`serve.c`](../../serve/serve.c): 지속 연결·파이프라이닝, edge-triggered epoll, 연결
최대 1,024(받을 때 할당), `writev` 응답, 같은 런타임 코어와 묶음 커밋. 같은 조건에서 다시 쟀다.
`strace -c`로 보니 GET 하나마다 저장소 draft를 여닫느라 시스템 호출이 9번(파일·디렉터리 열기, `fstat` 두 번,
diff --git a/docs/research/076-one-sync-commit.md b/docs/research/076-one-sync-commit.md
index 9f010e7..4b9afa6 100644
--- a/docs/research/076-one-sync-commit.md
+++ b/docs/research/076-one-sync-commit.md
@@ -94,7 +94,7 @@ p99는 장치 쪽 잡음이 지배한다. 꼬리를 늘리는 단위를 64 KiB,
## 검증
-[`test-tree-store.c`](../../prototypes/connections/test-tree-store.c)는 ASan·UBSan에서도 통과했다. 새로 넣은 검사:
+[`test-tree-store.c`](../../store/test-tree-store.c)는 ASan·UBSan에서도 통과했다. 새로 넣은 검사:
- **잃어버린 커밋**: 최신 커밋의 바이트 하나를 바꾸고 프로세스의 기억을 지우면(재부팅 뒤의 새 프로세스와 같다)
읽기, 핸들, writer가 모두 이전 커밋을 쓴다. 다음 커밋은 잃어버린 커밋이 있던 자리부터 쓴다.
diff --git a/prototypes/connections/Makefile b/prototypes/connections/Makefile
index 2dd85c7..9c9f485 100644
--- a/prototypes/connections/Makefile
+++ b/prototypes/connections/Makefile
@@ -2,19 +2,23 @@ CC ?= cc
CFLAGS ?= -O2 -g
CFLAGS += -std=c17 -Wall -Wextra -Wpedantic -Werror
BUILD ?= build
-
-.PHONY: all core async-core editor fixed-editor fixed-server fixed-tui source-tui compiler mirror window server async-server document-peer document-server check check-policy check-policy-peer check-portable check-portable-tui check-paged-portable check-tree check-module check-portable-peer check-native-checkpoint check-mirror check-core check-async check-async-server check-async-service-scale check-profile check-fixed-profile check-fixed-server check-service-scale check-tui-profile check-source-tui-profile check-tui check-source-tui check-release check-micro-memory check-hybrid check-flat-export check-copy-range check-peer-profile check-document-server-profile check-window-profile check-document-peer check-document-server FORCE
-CORE = runtime.c
+# The core (runtime, flow, the storage contracts) and the tree store now live
+# in ../../core and ../../store; this earlier document runtime builds on them.
+PURE_ROOT = ../..
+CFLAGS += -I$(PURE_ROOT)/core
+FLOW = $(PURE_ROOT)/core/flow.c
+
+.PHONY: all core async-core editor fixed-editor fixed-server fixed-tui source-tui compiler mirror window server async-server document-peer document-server check check-policy check-policy-peer check-portable check-portable-tui check-paged-portable check-tree check-portable-peer check-native-checkpoint check-mirror check-core check-async check-async-server check-async-service-scale check-profile check-fixed-profile check-fixed-server check-service-scale check-tui-profile check-source-tui-profile check-tui check-source-tui check-release check-micro-memory check-hybrid check-flat-export check-copy-range check-peer-profile check-document-server-profile check-window-profile check-document-peer check-document-server FORCE
+CORE = $(PURE_ROOT)/core/runtime.c
STORE ?= store.c
FIXED_PROGRAM ?= examples/editor.pure
-HOST = $(STORE) store-port.c evaluate.c
+STORE_FILE = $(if $(filter store-tree.c,$(STORE)),$(PURE_ROOT)/store/store-tree.c,$(STORE))
+HOST = $(STORE_FILE) store-port.c evaluate.c
# Document browsers list keys through the store. The tree store keeps its own
# catalog; per-object file stores share a directory listing.
KEYS = $(if $(filter store-tree.c,$(STORE)),,store-keys.c)
-HEADERS = runtime.h program.h store.h store-port.h state.h flow.h result.h
-# Defined before any rule names them: prerequisites expand when a rule is read.
-MODULE = module.c module-list.c module-save.c module-text.c store-tree.c
-MODULE_HEADERS = module.h module-list.h module-save.h module-text.h $(HEADERS)
+CORE_HEADERS = $(addprefix $(PURE_ROOT)/core/,runtime.h store.h state.h flow.h result.h)
+HEADERS = $(CORE_HEADERS) program.h store-port.h
all: core fixed-editor
core: $(BUILD)/libpure-execution.a
async-core: $(BUILD)/libpure-execution-async.a
@@ -34,21 +38,17 @@ document-server: $(BUILD)/pure-document-server
$(BUILD):
mkdir -p $@
-$(BUILD)/pure-connections: server.c $(HOST) flow.c program.c $(CORE) $(HEADERS) | $(BUILD)
- $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS server.c $(HOST) flow.c program.c $(CORE) $(LDFLAGS) $(LDLIBS) -o $@
-
-$(BUILD)/pure-connections-async: server.c $(HOST) flow.c program.c $(CORE) $(HEADERS) | $(BUILD)
- $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_ASYNC_EFFECTS -DPURE_HTTP_ASYNC server.c $(HOST) flow.c program.c $(CORE) $(LDFLAGS) -pthread $(LDLIBS) -o $@
+$(BUILD)/pure-connections: server.c $(HOST) $(FLOW) program.c $(CORE) $(HEADERS) | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS server.c $(HOST) $(FLOW) program.c $(CORE) $(LDFLAGS) $(LDLIBS) -o $@
-$(BUILD)/pure-connections-async-gated: server.c $(HOST) flow.c program.c $(CORE) test-async-server-gate.c $(HEADERS) | $(BUILD)
- $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_ASYNC_EFFECTS -DPURE_HTTP_ASYNC -DPURE_STORE_TEST server.c $(HOST) flow.c program.c $(CORE) test-async-server-gate.c $(LDFLAGS) -pthread $(LDLIBS) -o $@
+$(BUILD)/pure-connections-async: server.c $(HOST) $(FLOW) program.c $(CORE) $(HEADERS) | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_ASYNC_EFFECTS -DPURE_HTTP_ASYNC server.c $(HOST) $(FLOW) program.c $(CORE) $(LDFLAGS) -pthread $(LDLIBS) -o $@
-# The HTTP host for aup modules: persistent connections, epoll, group commits.
-$(BUILD)/pure-serve: serve.c deliver.c message-json.c flow.c module-store.c $(MODULE) $(CORE) deliver.h message-json.h module-store.h $(MODULE_HEADERS) | $(BUILD)
- $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_ASYNC_EFFECTS serve.c deliver.c message-json.c flow.c module-store.c $(MODULE) $(CORE) $(LDFLAGS) -lssl -lcrypto -lm $(LDLIBS) -o $@
+$(BUILD)/pure-connections-async-gated: server.c $(HOST) $(FLOW) program.c $(CORE) test-async-server-gate.c $(HEADERS) | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_ASYNC_EFFECTS -DPURE_HTTP_ASYNC -DPURE_STORE_TEST server.c $(HOST) $(FLOW) program.c $(CORE) test-async-server-gate.c $(LDFLAGS) -pthread $(LDLIBS) -o $@
-$(BUILD)/pure-connections-fixed: server.c $(HOST) flow.c $(CORE) $(HEADERS) $(BUILD)/embedded-plan.h | $(BUILD)
- $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_EMBEDDED_PROGRAM -I$(BUILD) server.c $(HOST) flow.c $(CORE) $(LDFLAGS) $(LDLIBS) -o $@
+$(BUILD)/pure-connections-fixed: server.c $(HOST) $(FLOW) $(CORE) $(HEADERS) $(BUILD)/embedded-plan.h | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_EMBEDDED_PROGRAM -I$(BUILD) server.c $(HOST) $(FLOW) $(CORE) $(LDFLAGS) $(LDLIBS) -o $@
$(BUILD)/pure-edit: edit.c $(HOST) program.c $(CORE) $(HEADERS) | $(BUILD)
$(CC) $(CPPFLAGS) $(CFLAGS) edit.c $(HOST) program.c $(CORE) $(LDFLAGS) $(LDLIBS) -o $@
@@ -87,13 +87,13 @@ $(BUILD)/pure-edit-window: edit-window.c $(HOST) program.c $(CORE) $(HEADERS) |
pkg-config --atleast-version=4.10 gtk4
$(CC) $(CPPFLAGS) $(CFLAGS) $$(pkg-config --cflags gtk4) edit-window.c $(HOST) program.c $(CORE) $(LDFLAGS) $$(pkg-config --libs gtk4) $(LDLIBS) -o $@
-$(BUILD)/runtime.o: runtime.c $(HEADERS) | $(BUILD)
- $(CC) $(CPPFLAGS) $(CFLAGS) -c runtime.c -o $@
+$(BUILD)/runtime.o: $(CORE) $(HEADERS) | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $(CORE) -o $@
-$(BUILD)/runtime-async.o: runtime.c $(HEADERS) | $(BUILD)
- $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_ASYNC_EFFECTS -c runtime.c -o $@
+$(BUILD)/runtime-async.o: $(CORE) $(HEADERS) | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_ASYNC_EFFECTS -c $(CORE) -o $@
-$(BUILD)/evaluate.o: evaluate.c program.h flow.h | $(BUILD)
+$(BUILD)/evaluate.o: evaluate.c program.h $(PURE_ROOT)/core/flow.h | $(BUILD)
$(CC) $(CPPFLAGS) $(CFLAGS) -c evaluate.c -o $@
$(BUILD)/libpure-execution.a: $(BUILD)/runtime.o
@@ -104,13 +104,13 @@ $(BUILD)/libpure-execution-async.a: $(BUILD)/runtime-async.o
rm -f $@
$(AR) rcs $@ $^
-$(BUILD)/test-flow: test-flow.c store.c flow.c store.h flow.h result.h | $(BUILD)
- $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_STORE_TEST test-flow.c store.c flow.c $(LDFLAGS) $(LDLIBS) -o $@
+$(BUILD)/test-flow: test-flow.c store.c $(FLOW) $(PURE_ROOT)/core/store.h $(PURE_ROOT)/core/flow.h $(PURE_ROOT)/core/result.h | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_STORE_TEST test-flow.c store.c $(FLOW) $(LDFLAGS) $(LDLIBS) -o $@
-$(BUILD)/test-program: test-program.c program.c evaluate.c program.h store.h flow.h result.h | $(BUILD)
+$(BUILD)/test-program: test-program.c program.c evaluate.c program.h $(PURE_ROOT)/core/store.h $(PURE_ROOT)/core/flow.h $(PURE_ROOT)/core/result.h | $(BUILD)
$(CC) $(CPPFLAGS) $(CFLAGS) test-program.c program.c evaluate.c $(LDFLAGS) $(LDLIBS) -o $@
-$(BUILD)/test-fields: test-fields.c program.c evaluate.c program.h store.h flow.h result.h | $(BUILD)
+$(BUILD)/test-fields: test-fields.c program.c evaluate.c program.h $(PURE_ROOT)/core/store.h $(PURE_ROOT)/core/flow.h $(PURE_ROOT)/core/result.h | $(BUILD)
$(CC) $(CPPFLAGS) $(CFLAGS) test-fields.c program.c evaluate.c $(LDFLAGS) $(LDLIBS) -o $@
$(BUILD)/test-runtime: test-runtime.c program.c $(CORE) $(HOST) $(HEADERS) | $(BUILD)
@@ -122,24 +122,8 @@ $(BUILD)/test-async: test-async.c program.c $(CORE) $(HOST) $(HEADERS) | $(BUILD
$(BUILD)/test-splice: test-splice.c program.c $(CORE) $(HOST) $(HEADERS) | $(BUILD)
$(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_STORE_TEST test-splice.c program.c $(CORE) $(HOST) $(LDFLAGS) $(LDLIBS) -o $@
-# Pure modules: loader/verifier/executor, its tests and a test host.
-# Text states are runtime-owned drafts, so the executor links the tree engine.
-
-$(BUILD)/test-module: test-module.c module-store.c $(MODULE) module-store.h $(MODULE_HEADERS) | $(BUILD)
- $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_STORE_TEST test-module.c module-store.c $(MODULE) $(LDFLAGS) -pthread -lm $(LDLIBS) -o $@
-
-$(BUILD)/pure-run: pure-run.c module-store.c $(MODULE) module-store.h $(MODULE_HEADERS) | $(BUILD)
- $(CC) $(CPPFLAGS) $(CFLAGS) pure-run.c module-store.c $(MODULE) $(LDFLAGS) -lm $(LDLIBS) -o $@
-
-# The document CLI contract driven by a module on the tree store.
-$(BUILD)/pure-edit-module: edit-module.c module-store.c $(MODULE) module-store.h $(MODULE_HEADERS) | $(BUILD)
- $(CC) $(CPPFLAGS) $(CFLAGS) edit-module.c module-store.c $(MODULE) $(LDFLAGS) -lm $(LDLIBS) -o $@
-
-check-module: $(BUILD)/test-module $(BUILD)/pure-run $(BUILD)/pure-edit-module $(BUILD)/pure-serve
- $(BUILD)/test-module
-
-$(BUILD)/test-tree-store: test-tree-store.c store-tree.c $(HEADERS) | $(BUILD)
- $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_STORE_TEST test-tree-store.c store-tree.c $(LDFLAGS) $(LDLIBS) -o $@
+$(BUILD)/test-tree-store: $(PURE_ROOT)/store/test-tree-store.c $(PURE_ROOT)/store/store-tree.c $(HEADERS) | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_STORE_TEST $(PURE_ROOT)/store/test-tree-store.c $(PURE_ROOT)/store/store-tree.c $(LDFLAGS) $(LDLIBS) -o $@
$(BUILD)/test-paged-store: test-paged-store.c store-paged.c $(HEADERS) | $(BUILD)
$(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_STORE_TEST test-paged-store.c store-paged.c $(LDFLAGS) $(LDLIBS) -o $@
@@ -248,7 +232,7 @@ check: $(BUILD)/test-flow $(BUILD)/test-program $(BUILD)/test-fields $(BUILD)/te
$(BUILD)/test-flow
$(BUILD)/test-program
$(BUILD)/test-fields
- python3 check.py --server $(BUILD)/pure-connections --runtime-test $(BUILD)/test-runtime --splice-test $(BUILD)/test-splice --editor $(BUILD)/pure-edit --store-source $(STORE) $(if $(EVIDENCE),--output "$(EVIDENCE)")
+ python3 check.py --server $(BUILD)/pure-connections --runtime-test $(BUILD)/test-runtime --splice-test $(BUILD)/test-splice --editor $(BUILD)/pure-edit --store-source $(STORE_FILE) $(if $(EVIDENCE),--output "$(EVIDENCE)")
check-policy: editor server source-tui
$(MAKE) BUILD=$(BUILD)/policy FIXED_PROGRAM=examples/bounded-editor.pure fixed-editor fixed-server fixed-tui
diff --git a/prototypes/connections/README.md b/prototypes/connections/README.md
index 94d05f0..569fe41 100644
--- a/prototypes/connections/README.md
+++ b/prototypes/connections/README.md
@@ -1,5 +1,10 @@
# Pure: 작성한 연결을 준비해 실행하는 네이티브 경로
+2026-09-27부터 실행 코어(`runtime.c`, `flow.c`, 저장소 계약 `store.h`·`state.h`)와 트리 저장소는 저장소 최상위의
+[`core/`](../../core)와 [`store/`](../../store)에 있다. 여기의 이전 문서 런타임(000–077)은 그것들을 가져다 빌드한다
+(`make -C prototypes/connections check`, `check-tree`). 모듈 앱의 호스트(`pure-serve`, `pure-run`)는 최상위 `make`가
+만든다. [배치](../../docs/design/009-layout.md).
+
기존 Workbench에서 만든 코드·배치를 실제 TCP 요청으로 저장하고 새 실행기에서 복원한다.
서버는 C17 네이티브 실행 파일이다. SQL·SQLite 의존성을 제거했고, 호출자의 바이트를
그대로 파일에 기록한다. 저장할 구간과 응답할 구간은 `.pure` 파일로 작성하며 서버 시작 때
diff --git a/prototypes/connections/check.py b/prototypes/connections/check.py
index 7719537..8a51858 100644
--- a/prototypes/connections/check.py
+++ b/prototypes/connections/check.py
@@ -500,6 +500,12 @@ def rpc_bytes(path):
return json.dumps(json.loads(path.read_text()), ensure_ascii=False, separators=(',', ':')).encode()
+def source(name):
+ """A source file of this document runtime; the core's live in ../../core."""
+ here = ROOT / name
+ return here if here.exists() else ROOT.parent.parent / 'core' / name
+
+
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--server', type=Path, default=ROOT / 'build/pure-connections')
@@ -532,7 +538,7 @@ def main():
result['environment'] = {'platform': platform.platform(), 'machine': platform.machine(),
'python': platform.python_version(), 'node': subprocess.check_output(['node', '--version'], text=True).strip()}
result['source_sha256'] = {str(path.relative_to(ROOT.parent.parent)): hashlib.sha256(path.read_bytes()).hexdigest()
- for path in [args.store_source.resolve(), *(ROOT / name for name in ('flow.c', 'flow.h', 'store.h', 'program.c', 'program.h',
+ for path in [args.store_source.resolve(), *(source(name) for name in ('flow.c', 'flow.h', 'store.h', 'program.c', 'program.h',
'runtime.c', 'runtime.h', 'result.h', 'evaluate.c', 'store-port.c', 'store-port.h', 'test-runtime.c',
'server.c', 'check.py', 'check_edits.py', 'edit.c', 'test-splice.c',
'test-flow.c', 'test-program.c', 'test-fields.c', 'Makefile',
diff --git a/prototypes/connections/package_source.py b/prototypes/connections/package_source.py
index 4a2487c..fa0fb4a 100644
--- a/prototypes/connections/package_source.py
+++ b/prototypes/connections/package_source.py
@@ -10,7 +10,7 @@ import tarfile
ROOT = Path(__file__).resolve().parents[2]
PREFIX = 'pure-source-preview'
-SOURCE_ROOTS = ('prototypes/connections', 'prototypes/workbench', 'prototypes/common')
+SOURCE_ROOTS = ('core', 'store', 'serve', 'cli', 'prototypes/connections', 'prototypes/workbench', 'prototypes/common')
SKIP_DIRS = {'build', 'results', '__pycache__', 'node_modules', '.git', '.playwright-cli'}
SUFFIXES = {'.c', '.h', '.py', '.mjs', '.js', '.zig', '.json', '.pure',
'.html', '.css', '.svg', '.wasm', '.md', '.txt'}
diff --git a/research/experiments/009-runtime-drafts/run.py b/research/experiments/009-runtime-drafts/run.py
index 08ed55d..eb87a25 100755
--- a/research/experiments/009-runtime-drafts/run.py
+++ b/research/experiments/009-runtime-drafts/run.py
@@ -8,12 +8,12 @@ import subprocess
from pathlib import Path
HERE = Path(__file__).resolve().parent
-CONNECTIONS = HERE.parents[2] / 'prototypes' / 'connections'
+ROOT = HERE.parents[2]
def main():
parser = argparse.ArgumentParser()
- parser.add_argument('--work', type=Path, default=CONNECTIONS / 'build' / 'bench-drafts')
+ parser.add_argument('--work', type=Path, default=ROOT / 'build' / 'bench-drafts')
parser.add_argument('--size', type=int, default=1048576)
parser.add_argument('--saves', type=int, default=24)
parser.add_argument('--rounds', type=int, default=3)
@@ -24,8 +24,8 @@ def main():
device = subprocess.check_output(['findmnt', '-n', '-T', str(args.work), '-o', 'SOURCE,FSTYPE'], text=True).split()
assert device[1] != 'tmpfs', 'fsync is free on tmpfs'
binary = args.work / 'bench'
- subprocess.run(['cc', '-std=c17', '-O2', '-Wall', '-Wextra', '-Werror', f'-I{CONNECTIONS}',
- str(HERE / 'bench.c'), str(CONNECTIONS / 'store-tree.c'), '-o', str(binary)], check=True)
+ subprocess.run(['cc', '-std=c17', '-O2', '-Wall', '-Wextra', '-Werror', f'-I{ROOT / "core"}',
+ str(HERE / 'bench.c'), str(ROOT / 'store' / 'store-tree.c'), '-o', str(binary)], check=True)
runs = []
for round_number in range(args.rounds):
for mode in (('copy', 'draft') if round_number % 2 == 0 else ('draft', 'copy')):
diff --git a/research/experiments/010-one-sync-commit/run.py b/research/experiments/010-one-sync-commit/run.py
index 9a01c07..c729358 100644
--- a/research/experiments/010-one-sync-commit/run.py
+++ b/research/experiments/010-one-sync-commit/run.py
@@ -16,11 +16,18 @@ from pathlib import Path
HERE = Path(__file__).resolve().parent
ROOT = HERE.parents[2]
-PURE = ROOT / 'prototypes' / 'connections'
+CORE = ROOT / 'core' # the store's headers
+STORE = ROOT / 'store' / 'store-tree.c'
+
+
+def stored_at(revision):
+ """Where the tree store was at a revision: store/ now, prototypes/connections/ before."""
+ moved = subprocess.run(['git', '-C', str(ROOT), 'cat-file', '-e', f'{revision}:store/store-tree.c'], capture_output=True)
+ return 'store/store-tree.c' if moved.returncode == 0 else 'prototypes/connections/store-tree.c'
def build(output, sources):
- subprocess.run(['cc', '-O2', '-std=c17', f'-I{PURE}', '-o', str(output)] + [str(s) for s in sources] + ['-lpthread'],
+ subprocess.run(['cc', '-O2', '-std=c17', f'-I{CORE}', '-o', str(output)] + [str(s) for s in sources] + ['-lpthread'],
check=True)
@@ -34,12 +41,12 @@ def main():
with tempfile.TemporaryDirectory() as work:
work = Path(work)
before = work / 'store-tree-before.c'
- before.write_text(subprocess.run(['git', '-C', str(ROOT), 'show', f'{args.before}:prototypes/connections/store-tree.c'],
+ before.write_text(subprocess.run(['git', '-C', str(ROOT), 'show', f'{args.before}:{stored_at(args.before)}'],
capture_output=True, text=True, check=True).stdout)
build(work / 'probe', [HERE / 'probe.c'])
builds = {'two syncs': work / 'commits-before', 'one sync': work / 'commits-after'}
build(builds['two syncs'], [HERE / 'commits.c', before])
- build(builds['one sync'], [HERE / 'commits.c', PURE / 'store-tree.c'])
+ build(builds['one sync'], [HERE / 'commits.c', STORE])
results = {'rounds': []}
for round_ in range(args.rounds):
probe = subprocess.run([str(work / 'probe'), str(args.directory)], capture_output=True, text=True, check=True)
diff --git a/research/experiments/012-tail-records/run.py b/research/experiments/012-tail-records/run.py
index 7fc342e..ed8630b 100755
--- a/research/experiments/012-tail-records/run.py
+++ b/research/experiments/012-tail-records/run.py
@@ -18,12 +18,19 @@ from pathlib import Path
HERE = Path(__file__).resolve().parent
ROOT = HERE.parents[2]
-PURE = ROOT / 'prototypes' / 'connections'
+CORE = ROOT / 'core' # the store's headers
+STORE = ROOT / 'store' / 'store-tree.c'
COMMITS = HERE.parent / '010-one-sync-commit' / 'commits.c'
+def stored_at(revision):
+ """Where the tree store was at a revision: store/ now, prototypes/connections/ before."""
+ moved = subprocess.run(['git', '-C', str(ROOT), 'cat-file', '-e', f'{revision}:store/store-tree.c'], capture_output=True)
+ return 'store/store-tree.c' if moved.returncode == 0 else 'prototypes/connections/store-tree.c'
+
+
def build(output, sources):
- subprocess.run(['cc', '-O2', '-std=c17', f'-I{PURE}', '-o', str(output)] + [str(s) for s in sources] + ['-lpthread'],
+ subprocess.run(['cc', '-O2', '-std=c17', f'-I{CORE}', '-o', str(output)] + [str(s) for s in sources] + ['-lpthread'],
check=True)
@@ -37,12 +44,12 @@ def main():
with tempfile.TemporaryDirectory() as work:
work = Path(work)
before = work / 'store-tree-before.c'
- before.write_text(subprocess.run(['git', '-C', str(ROOT), 'show', f'{args.before}:prototypes/connections/store-tree.c'],
+ before.write_text(subprocess.run(['git', '-C', str(ROOT), 'show', f'{args.before}:{stored_at(args.before)}'],
capture_output=True, text=True, check=True).stdout)
build(work / 'probe', [HERE / 'probe.c'])
builds = {'heads in slots': work / 'commits-before', 'heads as records': work / 'commits-after'}
build(builds['heads in slots'], [COMMITS, before])
- build(builds['heads as records'], [COMMITS, PURE / 'store-tree.c'])
+ build(builds['heads as records'], [COMMITS, STORE])
results = {'rounds': []}
for round_ in range(args.rounds):
measured = {'probe': [], 'commits': {}}
diff --git a/prototypes/connections/deliver.c b/serve/deliver.c
index 0d3da64..0d3da64 100644
--- a/prototypes/connections/deliver.c
+++ b/serve/deliver.c
diff --git a/prototypes/connections/deliver.h b/serve/deliver.h
index 2d1da29..2d1da29 100644
--- a/prototypes/connections/deliver.h
+++ b/serve/deliver.h
diff --git a/prototypes/connections/message-json.c b/serve/message-json.c
index 66c812d..66c812d 100644
--- a/prototypes/connections/message-json.c
+++ b/serve/message-json.c
diff --git a/prototypes/connections/message-json.h b/serve/message-json.h
index 61211d6..61211d6 100644
--- a/prototypes/connections/message-json.h
+++ b/serve/message-json.h
diff --git a/prototypes/connections/serve.c b/serve/serve.c
index 2ea7adb..2ea7adb 100644
--- a/prototypes/connections/serve.c
+++ b/serve/serve.c
diff --git a/prototypes/connections/store-tree.c b/store/store-tree.c
index 146e919..146e919 100644
--- a/prototypes/connections/store-tree.c
+++ b/store/store-tree.c
diff --git a/prototypes/connections/test-tree-store.c b/store/test-tree-store.c
index 1130acd..1130acd 100644
--- a/prototypes/connections/test-tree-store.c
+++ b/store/test-tree-store.c