aboutsummaryrefslogtreecommitdiffstats
path: root/prototypes/connections/results/2026-09-23-document-edits
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-24 17:14:54 +0100
committereunhhu <[email protected]>2026-09-24 17:14:54 +0100
commitb1ce1927022d374198441afafeb27199fc8a052a (patch)
tree6021f175f4c67ed03b44240eaa2f90d846f12f6f /prototypes/connections/results/2026-09-23-document-edits
parentd34f9426d5317a1948f12f229439946728bc342a (diff)
downloadpure-b1ce1927022d374198441afafeb27199fc8a052a.tar.gz
pure-b1ce1927022d374198441afafeb27199fc8a052a.zip
Establish native micro runtime checkpoint
Diffstat (limited to 'prototypes/connections/results/2026-09-23-document-edits')
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/README.md27
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/boundary-checks.json34
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/core.json53
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/native.json635
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sanitized.json635
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/Makefile59
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/check.py551
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/check_core.py74
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/check_edits.py108
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/core-budget.json15
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/core-layout.c11
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/edit.c153
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/evaluate.c53
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/editor.pure19
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/excerpt.pure13
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/select-text.py72
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/selection.pure19
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/storage.pure11
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/flow.c41
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/flow.h25
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/program.c366
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/program.h44
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/result.h8
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/runtime.c273
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/runtime.h88
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/server.c372
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store-port.c44
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store-port.h6
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store.c258
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store.h44
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-fields.c153
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-flow.c183
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-program.c111
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-runtime.c285
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-splice.c172
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/cli.mjs127
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/examples/direct.pure47
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/remote.mjs89
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/compiler.mjs496
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/core.wasmbin0 -> 61072 bytes
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/project.mjs47
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/runtime.mjs350
-rw-r--r--prototypes/connections/results/2026-09-23-document-edits/verification.json32
43 files changed, 6203 insertions, 0 deletions
diff --git a/prototypes/connections/results/2026-09-23-document-edits/README.md b/prototypes/connections/results/2026-09-23-document-edits/README.md
new file mode 100644
index 0000000..ee6ed76
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/README.md
@@ -0,0 +1,27 @@
+# 문서 부분 변경과 micro 비용 경계
+
+2026-09-23, Linux AArch64 / GCC 14.2.0. 정확성·구조 비용 검증이며 성능 순위 자료가 아니다.
+
+- `native.json`, `sanitized.json`: 각 36개 통합 시나리오, 실행 코어와 splice 단위 검사, 바이너리·소스 해시.
+- `core.json`: 실행 전용 아카이브의 섹션·심볼·구조체 비용과 검사 상한.
+- `boundary-checks.json`: 코어만 선택한 빌드의 파일, 비용 증가 시 검사 실패, 전체 CLI/서버 ELF 비용.
+- `verification.json`: 두 빌드의 소스와 바이너리 확인, 서버 종료 시 회수 확인.
+- `sources/`: 해시가 일치하는 소스·기존 클라이언트 37개. 검증에 사용한 Workbench Wasm도 포함한다.
+
+실행 명령 (`prototypes/connections` 기준):
+
+```sh
+make all
+make check EVIDENCE=results/2026-09-23-document-edits/native.json
+make check BUILD=build/sanitized CFLAGS='-std=c17 -O1 -g -Wall -Wextra -Wpedantic -Werror -fsanitize=address,undefined -fno-omit-frame-pointer' EVIDENCE=results/2026-09-23-document-edits/sanitized.json
+make check-core CORE_EVIDENCE=results/2026-09-23-document-edits/core.json
+```
+
+기존 결과를 덮어쓰지 않는다. 재현 시 출력 인자를 생략하거나 새 경로를 사용한다.
+동결 소스의 `sources/prototypes/connections`에서도 같은 빌드·검사가 가능하다.
+C17 컴파일러·make·Python·Node·로컬 TCP/자식 프로세스 실행이 필요하며, 크기 검사는
+GNU 호환 ar/nm/size를 사용한다. ASan 계측물에는 release 크기 상한을 적용하지 않는다.
+
+1 MiB 문서 편집의 11 B는 입력 크레딧이다. 파일을 재작성하는 4 KiB 호스트 스택 버퍼,
+커널·파일·allocator·파서·서버 비용을 포함한 전체 메모리라고 해석하지 않는다.
+[구현, 수치 범위와 한계](../../../../docs/research/023-document-edits.md).
diff --git a/prototypes/connections/results/2026-09-23-document-edits/boundary-checks.json b/prototypes/connections/results/2026-09-23-document-edits/boundary-checks.json
new file mode 100644
index 0000000..c24fa21
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/boundary-checks.json
@@ -0,0 +1,34 @@
+{
+ "core_only_build_files": [
+ "evaluate.o",
+ "libpure-execution.a",
+ "runtime.o"
+ ],
+ "reject_smaller_budget": [
+ "domain_bytes: 200 > 199"
+ ],
+ "reject_added_dependency_and_static_state": [
+ "unexpected archive members",
+ "bss: 4096 > 0",
+ "unexpected dependencies: ['malloc']"
+ ],
+ "selected_binaries": {
+ "pure-edit": {
+ "debug_file_bytes": 177384,
+ "stripped_file_bytes": 67904,
+ "sections": " text\t data\t bss\t dec\t hex\tfilename\n 35807\t 944\t 16\t 36767\t 8f9f\t/home/eunhhu/work/pure/prototypes/connections/build/pure-edit\n",
+ "direct_dynamic_libraries": [
+ "0x0000000000000001 (NEEDED) Shared library: [libc.so.6]"
+ ]
+ },
+ "pure-connections": {
+ "debug_file_bytes": 199080,
+ "stripped_file_bytes": 68000,
+ "sections": " text\t data\t bss\t dec\t hex\tfilename\n 42761\t 1040\t 16\t 43817\t ab29\t/home/eunhhu/work/pure/prototypes/connections/build/pure-connections\n",
+ "direct_dynamic_libraries": [
+ "0x0000000000000001 (NEEDED) Shared library: [libc.so.6]"
+ ]
+ }
+ },
+ "scope": "Selected files and direct ELF dependencies, not complete dependency memory, RSS, stack or latency."
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/core.json b/prototypes/connections/results/2026-09-23-document-edits/core.json
new file mode 100644
index 0000000..8c0caf7
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/core.json
@@ -0,0 +1,53 @@
+{
+ "passed": true,
+ "failures": [],
+ "budget": {
+ "profile": "current-storage-execution-core",
+ "max_text_bytes": 6144,
+ "max_data_bytes": 0,
+ "max_bss_bytes": 0,
+ "layout_max_bytes": {
+ "domain_bytes": 200,
+ "work_slot_bytes": 224,
+ "ticket_bytes": 24,
+ "prepared_program_bytes": 680
+ },
+ "archive_members": [
+ "runtime.o",
+ "evaluate.o"
+ ],
+ "external_symbols_allowed": [
+ "memcpy",
+ "memmove",
+ "memset",
+ "strlen"
+ ],
+ "scope": "Release object sections and C bookkeeping, validated with GNU tools on Linux AArch64. Not total RAM, process RSS, stack, linked libraries, parser, storage, network or UI. 6 KiB is a regression ceiling for this profile, not a universal runtime size promise."
+ },
+ "layout": {
+ "domain_bytes": 200,
+ "work_slot_bytes": 224,
+ "ticket_bytes": 24,
+ "prepared_program_bytes": 680,
+ "pointer_bytes": 8
+ },
+ "sections": {
+ "text": 5932,
+ "data": 0,
+ "bss": 0
+ },
+ "members": [
+ "runtime.o",
+ "evaluate.o"
+ ],
+ "external_symbols": [
+ "memcpy",
+ "strlen"
+ ],
+ "size_output": " text\t data\t bss\t dec\t hex\tfilename\n 5012\t 0\t 0\t 5012\t 1394\truntime.o (ex /home/eunhhu/work/pure/prototypes/connections/build/libpure-execution.a)\n 920\t 0\t 0\t 920\t 398\tevaluate.o (ex /home/eunhhu/work/pure/prototypes/connections/build/libpure-execution.a)\n",
+ "archive_sha256": "d56c50e38c6c0949cfad069d34568da2ac45b1d60097cf9e7c4bf804f44c8128",
+ "layout_binary_sha256": "47cf1803007fc1ec85f119bd46195ad39d9f01ef0146bf5cc45e1af31eb18098",
+ "budget_sha256": "b4eceaffce900144470dd29076164039b8729bad4ba849789d212e7c952f5082",
+ "platform": "Linux-6.18.39+rpt-rpi-2712-aarch64-with-glibc2.41",
+ "size_tool": "GNU size (GNU Binutils for Debian) 2.44"
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/native.json b/prototypes/connections/results/2026-09-23-document-edits/native.json
new file mode 100644
index 0000000..c9bb1d4
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/native.json
@@ -0,0 +1,635 @@
+{
+ "kind": "prepared-connection-correctness-not-performance",
+ "checks": [
+ "fragmented request and binary bytes round trip",
+ "conditional create and stale revision preserve committed bytes",
+ "writer contention and invalid extent fail without overwriting data",
+ "two native writers cannot both create the same expected revision",
+ "incomplete request never commits and releases its allocation",
+ "borrowed read remains the same snapshot during another commit",
+ "receiver reset aborts an outstanding borrowed transfer",
+ "unsupported framing and oversized payload are rejected before effects",
+ "existing workbench manipulation restores in a fresh runtime and reports conflict",
+ "invalid or non-idle restore preserves local state and does not adopt remote revision",
+ "revision above JavaScript safe integer round trips without numeric coercion",
+ "unread acknowledgment does not undo commit or permit a stale retry",
+ "empty body has a valid lifetime and stored revision",
+ "committed authoring state survives process restart",
+ "slow consumer retains its lease; budget rejects another; deadline releases it",
+ "connection slots stay bounded and recover after header deadlines",
+ "authored nested read maps only final demand while preserving parent bounds and revision",
+ "unused checked view still fails even when response range would be valid",
+ "authored write and reply share selected input; invalid parent prevents the storage effect",
+ "body-free response preserves read existence and malformed-object errors",
+ "input-backed response survives partial send and releases on finish or abort without undoing commit",
+ "invalid authored program fails preparation before creating storage or accepting requests",
+ "text client uses character selection; named numeric fields select and persist the matching UTF-8 bytes",
+ "truncated layouts and invalid data-dependent ranges never change storage; empty and end selections remain valid",
+ "changed declaration order and unaligned numeric fields determine access; aliases add no dynamic steps",
+ "unused dynamic field selection retains its validation before the write effect",
+ "named variable tail reads use the same file version and charge only the selected suffix",
+ "data-dependent response keeps and charges the original input through partial transmission",
+ "native authored byte edit and fresh native process restore UTF-8 content",
+ "native stale revision and invalid byte position preserve the committed document",
+ "native convenience editor derives unaligned reordered field positions from the authored program",
+ "raw native apply runs another authored input contract without changing the executor",
+ "native CLI and external HTTP share revisions and the same authored storage effect in both directions",
+ "partial or invalid edit input never modifies the stored document",
+ "two processes cannot both splice the same expected document revision",
+ "1 MiB document changes with 11 input credits; larger input is rejected before an effect"
+ ],
+ "prepared_connections": {
+ "excerpt": {
+ "read": {
+ "to_end": false,
+ "offset": 32,
+ "length": 16,
+ "minimum_source_bytes": 80
+ },
+ "write": {
+ "to_end": true,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 0
+ },
+ "reply_input": false,
+ "view_definitions": 2,
+ "range_definitions": 2,
+ "runtime_view_steps": 0,
+ "write_step": 0,
+ "reply_step": 0,
+ "prepared_program_bytes": 680,
+ "steps": [],
+ "write_effect": "write",
+ "splice_offset": {
+ "value": 0,
+ "from_u32le": false
+ },
+ "splice_remove": {
+ "value": 0,
+ "from_u32le": false
+ }
+ },
+ "write": {
+ "read": {
+ "to_end": true,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 0
+ },
+ "write": {
+ "to_end": false,
+ "offset": 5,
+ "length": 4,
+ "minimum_source_bytes": 12
+ },
+ "reply_input": true,
+ "view_definitions": 3,
+ "range_definitions": 2,
+ "runtime_view_steps": 0,
+ "write_step": 0,
+ "reply_step": 0,
+ "prepared_program_bytes": 680,
+ "steps": [],
+ "write_effect": "write",
+ "splice_offset": {
+ "value": 0,
+ "from_u32le": false
+ },
+ "splice_remove": {
+ "value": 0,
+ "from_u32le": false
+ }
+ }
+ },
+ "field_connections": {
+ "selection": {
+ "read": {
+ "to_end": true,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 0
+ },
+ "write": {
+ "to_end": false,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 8
+ },
+ "reply_input": true,
+ "view_definitions": 2,
+ "range_definitions": 1,
+ "runtime_view_steps": 1,
+ "write_step": 1,
+ "reply_step": 1,
+ "prepared_program_bytes": 680,
+ "steps": [
+ {
+ "source_step": 0,
+ "source": {
+ "offset": 8,
+ "length": 0,
+ "to_end": true
+ },
+ "offset": {
+ "value": 0,
+ "from_u32le": true
+ },
+ "length": {
+ "value": 4,
+ "from_u32le": true
+ }
+ }
+ ],
+ "write_effect": "write",
+ "splice_offset": {
+ "value": 0,
+ "from_u32le": false
+ },
+ "splice_remove": {
+ "value": 0,
+ "from_u32le": false
+ }
+ },
+ "reordered": {
+ "read": {
+ "to_end": true,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 0
+ },
+ "write": {
+ "to_end": false,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 11
+ },
+ "reply_input": true,
+ "view_definitions": 4,
+ "range_definitions": 1,
+ "runtime_view_steps": 1,
+ "write_step": 1,
+ "reply_step": 1,
+ "prepared_program_bytes": 680,
+ "steps": [
+ {
+ "source_step": 0,
+ "source": {
+ "offset": 11,
+ "length": 0,
+ "to_end": true
+ },
+ "offset": {
+ "value": 7,
+ "from_u32le": true
+ },
+ "length": {
+ "value": 3,
+ "from_u32le": true
+ }
+ }
+ ],
+ "write_effect": "write",
+ "splice_offset": {
+ "value": 0,
+ "from_u32le": false
+ },
+ "splice_remove": {
+ "value": 0,
+ "from_u32le": false
+ }
+ },
+ "field_get": {
+ "read": {
+ "to_end": true,
+ "offset": 11,
+ "length": 0,
+ "minimum_source_bytes": 11
+ },
+ "write": {
+ "to_end": true,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 0
+ },
+ "reply_input": false,
+ "view_definitions": 1,
+ "range_definitions": 0,
+ "runtime_view_steps": 0,
+ "write_step": 0,
+ "reply_step": 0,
+ "prepared_program_bytes": 680,
+ "steps": [],
+ "write_effect": "write",
+ "splice_offset": {
+ "value": 0,
+ "from_u32le": false
+ },
+ "splice_remove": {
+ "value": 0,
+ "from_u32le": false
+ }
+ }
+ },
+ "document_edits": {
+ "large_document_bytes": 1048576,
+ "small_edit_input_bytes": 11,
+ "storage_rewrites_full_extent": true,
+ "storage_scratch_bytes": 4096,
+ "kind": "correctness-and-admission-not-total-memory-or-performance"
+ },
+ "server_runs": [
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 6,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 1,
+ "commits": 0,
+ "gets": 0,
+ "conflicts": 1,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 1,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 0,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 1048583,
+ "payload_budget": 4194304,
+ "peak_connections": 2,
+ "accepted": 41,
+ "commits": 12,
+ "gets": 14,
+ "conflicts": 4,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 31,
+ "ingress_prefix_copy_bytes": 11674,
+ "borrowed_output_bytes": 2115416,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 2553,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 2,
+ "commits": 0,
+ "gets": 2,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 2,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 2556,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 1048576,
+ "payload_budget": 1048576,
+ "peak_connections": 8,
+ "accepted": 12,
+ "commits": 0,
+ "gets": 3,
+ "conflicts": 0,
+ "budget_rejections": 1,
+ "expired": 9,
+ "releases": 3,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 1048582,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 80,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 2,
+ "commits": 2,
+ "gets": 0,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 2,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 0,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 16,
+ "payload_budget": 16,
+ "peak_connections": 1,
+ "accepted": 3,
+ "commits": 0,
+ "gets": 1,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 1,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 16,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 16,
+ "payload_budget": 16,
+ "peak_connections": 1,
+ "accepted": 2,
+ "commits": 0,
+ "gets": 1,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 1,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 16,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 12,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 5,
+ "commits": 1,
+ "gets": 2,
+ "conflicts": 1,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 5,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 12,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 0,
+ "payload_budget": 1,
+ "peak_connections": 1,
+ "accepted": 3,
+ "commits": 0,
+ "gets": 1,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 0,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 0,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 1048576,
+ "payload_budget": 1048576,
+ "peak_connections": 2,
+ "accepted": 7,
+ "commits": 2,
+ "gets": 3,
+ "conflicts": 0,
+ "budget_rejections": 2,
+ "expired": 0,
+ "releases": 5,
+ "ingress_prefix_copy_bytes": 8006,
+ "borrowed_output_bytes": 3145734,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 54,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 20,
+ "commits": 3,
+ "gets": 4,
+ "conflicts": 1,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 17,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 57,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 19,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 2,
+ "commits": 1,
+ "gets": 1,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 2,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 8,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 14,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 4,
+ "commits": 1,
+ "gets": 1,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 3,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 3,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 34,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 3,
+ "commits": 3,
+ "gets": 0,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 3,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 0,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 23,
+ "payload_budget": 23,
+ "peak_connections": 1,
+ "accepted": 3,
+ "commits": 0,
+ "gets": 2,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 1,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 23,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 1048584,
+ "payload_budget": 1048584,
+ "peak_connections": 2,
+ "accepted": 4,
+ "commits": 1,
+ "gets": 2,
+ "conflicts": 0,
+ "budget_rejections": 1,
+ "expired": 0,
+ "releases": 3,
+ "ingress_prefix_copy_bytes": 3998,
+ "borrowed_output_bytes": 2097091,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 9,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 1,
+ "commits": 0,
+ "gets": 0,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 1,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 0,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 29,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 10,
+ "commits": 2,
+ "gets": 4,
+ "conflicts": 1,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 10,
+ "ingress_prefix_copy_bytes": 7,
+ "borrowed_output_bytes": 114,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 11,
+ "payload_budget": 11,
+ "peak_connections": 1,
+ "accepted": 2,
+ "commits": 1,
+ "gets": 0,
+ "conflicts": 0,
+ "budget_rejections": 1,
+ "expired": 0,
+ "releases": 1,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 3,
+ "server_structure_bytes": 41528
+ }
+ ],
+ "storage": "immutable-byte-extents-v1",
+ "execution_core": {
+ "runtime_tests": "passed",
+ "domain_bytes": 200,
+ "work_slot_bytes": 224,
+ "ticket_bytes": 24,
+ "prepared_program_bytes": 680,
+ "forwarding_chain": 1024,
+ "native_storage_pipeline": true
+ },
+ "execution_core_test_sha256": "07c328c98769d02d544aea2fc5389048a7620c00d9b3ea49b9c7ba45e33984b1",
+ "document_edit_units": {
+ "splice_tests": "passed",
+ "checks": [
+ "authored-fields-and-atomic-parse-failure",
+ "binary-edit-oracle-and-old-snapshot",
+ "bounds-conflict-size-overflow",
+ "publication-failures-and-uncertain-durability",
+ "cancel-admission-and-borrowed-reply"
+ ]
+ },
+ "document_edit_test_sha256": "0e4ec2c78334af2056af376a6ba9aef7416a34c6d4fbd9082f4abb640e6de28c",
+ "editor_sha256": "b5c6ec82a1e9c8a1391d1c4ac680e7f33e53dafe5c29ac8a956d5097653b1a03",
+ "binary_sha256": "e76d4c0a721c9ceb7142db0edbaa1f5c44bd78a2c55029658109c83e8076875f",
+ "environment": {
+ "platform": "Linux-6.18.39+rpt-rpi-2712-aarch64-with-glibc2.41",
+ "machine": "aarch64",
+ "python": "3.14.7",
+ "node": "v24.20.0"
+ },
+ "source_sha256": {
+ "prototypes/connections/flow.c": "3957de06e33985a8310954af07b33c2a1d02a4afdf9bd112d06c99c0b5df7749",
+ "prototypes/connections/flow.h": "289ff43d191270066e238235023f096946f3f561ec5825d2f6c26006db5fc421",
+ "prototypes/connections/store.c": "44702e9414c26d1ee336b2e36e6713560013c2c8d0091a8900042e2468f88015",
+ "prototypes/connections/store.h": "e3cf5f169be02e40f1274105046f29a63a46cd153beaf204d33d6100b9c869b8",
+ "prototypes/connections/program.c": "d7186634d2bfd83bbaf87ea3bafdec8d14be8f556cbf3d9877d07e0074b4b389",
+ "prototypes/connections/program.h": "b9ea0af3759150637ccba9362ccb73be374ed85b449b0461fc61fb14ee50e8bc",
+ "prototypes/connections/runtime.c": "a6c068c6a2cee214b3fe30241459394833917dfb6c0d33052460eab4c6a539a2",
+ "prototypes/connections/runtime.h": "ff03c0be92dcc482247a58a0be54d2dc5c270325b51ceeed37afc2ffa5480b1f",
+ "prototypes/connections/result.h": "00b6cf02262039fd90b197eb781f38c9771beaa8d65f394cba6d3f8d0b2ae79d",
+ "prototypes/connections/evaluate.c": "ee8b91efc733b9d305711b7cbb7b502ae5d3917e06f750b7f62b632ed0ea6d04",
+ "prototypes/connections/store-port.c": "d6bf17878b325e039360816edcbf8d68e41b373cf3e6128d7795e11ae21fdd6f",
+ "prototypes/connections/store-port.h": "a262bac93463bfe9939ca0bdc5989d1665aafc007d61e93c28ffc36478b1fde6",
+ "prototypes/connections/test-runtime.c": "5d08639b5a71572553bda47cbd35562805d601aaa81f20731cd9154768ec025e",
+ "prototypes/connections/server.c": "76645bafe8e4e429155efe96c2d05a59aed506ba89736283e4fdae71a3d9a60f",
+ "prototypes/connections/check.py": "e1735316769b4ce4d5904b9587ccfa3ebeafa26517c53dba4491191d58c97b8e",
+ "prototypes/connections/check_edits.py": "7699eb4bda57ad860acf7be6da3e6de56d6b9a3dcf3b9ff9c7df104f5bcb9224",
+ "prototypes/connections/edit.c": "793d0bde277563c9e11f1225804fb1646e4ce495979d16e8d70d00322a7bec7b",
+ "prototypes/connections/test-splice.c": "2415188c89ff413f10d55a8cf1902e76c585cc4102f01d504bbf84dbe8d90a8f",
+ "prototypes/connections/test-flow.c": "2cd2618015ba6806b1a733af0fc7d0ed6aec48fdec117d18c3a8160f534e130b",
+ "prototypes/connections/test-program.c": "a1b65be05ab2e4e5ccbc56cd1e03e17b0d885f15dc027bf295371ec821e19cc8",
+ "prototypes/connections/test-fields.c": "e5856ae1985dc8407565ebf7b65702478a34a05081c955f127a10d3cdc900507",
+ "prototypes/connections/Makefile": "b5e7ed077be1333f3a948844608785dbab98bdc9c4ae6fe9c6a4805655fc9c63",
+ "prototypes/connections/core-layout.c": "e802b4976c53755ffc045ae9114ebdcf2989d526d8c871c3cfe89d057f4b82b0",
+ "prototypes/connections/check_core.py": "f80ead11764e870f0bde434c93233d518e5874fdb32f77444e7bd8bbe7398a10",
+ "prototypes/connections/core-budget.json": "b4eceaffce900144470dd29076164039b8729bad4ba849789d212e7c952f5082",
+ "prototypes/connections/examples/editor.pure": "8ca6c191b98bf53a592ce24f2b5cd040e41f05c4ccdda7a072d5d7f79870c06a",
+ "prototypes/connections/examples/storage.pure": "6f2fd3733f46b762836405f40a9720de0b865f92a8bcbf9388dda0532c903c74",
+ "prototypes/connections/examples/excerpt.pure": "7ca1b9a4b6a06c32b95e37bcdeb2202ef912ffbf16163f7eea2b00574c703c16",
+ "prototypes/connections/examples/selection.pure": "90a19a080dd31b532163b8063057beee4701d8f74163ac4083833a1d664fe986",
+ "prototypes/connections/examples/select-text.py": "3211ce21bf6058f0131544959272587af4edb3fd5a956aee0a940ab19888f944",
+ "prototypes/workbench/remote.mjs": "6f5aa2bc5a3c88749b2b688c5631eed9e4a5ab41d72eca168bfb67941a8cff2f",
+ "prototypes/workbench/cli.mjs": "55a5ead56fc8ad4c3f2391505fc3dbfa477ccff5b68fc208f700da24d5e194da",
+ "prototypes/workbench/web/core.wasm": "9f760e4a2ce6ea11f2be07693fceca74088884885cc545a70ceef5003d0b2479",
+ "prototypes/workbench/web/runtime.mjs": "9cf12270bb39b3d6ce0384c56df8bdfabfd9459d3375cc7819290a5fe3e5db54",
+ "prototypes/workbench/web/compiler.mjs": "349139612d1f7da5f75ef21c65aa697963b760cb35321150fc36f67f3b40adf1",
+ "prototypes/workbench/web/project.mjs": "8af4cd1a60bbb217c896be20c7c6b8d33989f2166d06e736bf1479d8ecdc8b35",
+ "prototypes/workbench/examples/direct.pure": "57177e5197d75a6185cd3ac5df2be920ddba9a9b0fcc2dddab3560b815249f0a"
+ }
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sanitized.json b/prototypes/connections/results/2026-09-23-document-edits/sanitized.json
new file mode 100644
index 0000000..0e2dbe4
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sanitized.json
@@ -0,0 +1,635 @@
+{
+ "kind": "prepared-connection-correctness-not-performance",
+ "checks": [
+ "fragmented request and binary bytes round trip",
+ "conditional create and stale revision preserve committed bytes",
+ "writer contention and invalid extent fail without overwriting data",
+ "two native writers cannot both create the same expected revision",
+ "incomplete request never commits and releases its allocation",
+ "borrowed read remains the same snapshot during another commit",
+ "receiver reset aborts an outstanding borrowed transfer",
+ "unsupported framing and oversized payload are rejected before effects",
+ "existing workbench manipulation restores in a fresh runtime and reports conflict",
+ "invalid or non-idle restore preserves local state and does not adopt remote revision",
+ "revision above JavaScript safe integer round trips without numeric coercion",
+ "unread acknowledgment does not undo commit or permit a stale retry",
+ "empty body has a valid lifetime and stored revision",
+ "committed authoring state survives process restart",
+ "slow consumer retains its lease; budget rejects another; deadline releases it",
+ "connection slots stay bounded and recover after header deadlines",
+ "authored nested read maps only final demand while preserving parent bounds and revision",
+ "unused checked view still fails even when response range would be valid",
+ "authored write and reply share selected input; invalid parent prevents the storage effect",
+ "body-free response preserves read existence and malformed-object errors",
+ "input-backed response survives partial send and releases on finish or abort without undoing commit",
+ "invalid authored program fails preparation before creating storage or accepting requests",
+ "text client uses character selection; named numeric fields select and persist the matching UTF-8 bytes",
+ "truncated layouts and invalid data-dependent ranges never change storage; empty and end selections remain valid",
+ "changed declaration order and unaligned numeric fields determine access; aliases add no dynamic steps",
+ "unused dynamic field selection retains its validation before the write effect",
+ "named variable tail reads use the same file version and charge only the selected suffix",
+ "data-dependent response keeps and charges the original input through partial transmission",
+ "native authored byte edit and fresh native process restore UTF-8 content",
+ "native stale revision and invalid byte position preserve the committed document",
+ "native convenience editor derives unaligned reordered field positions from the authored program",
+ "raw native apply runs another authored input contract without changing the executor",
+ "native CLI and external HTTP share revisions and the same authored storage effect in both directions",
+ "partial or invalid edit input never modifies the stored document",
+ "two processes cannot both splice the same expected document revision",
+ "1 MiB document changes with 11 input credits; larger input is rejected before an effect"
+ ],
+ "prepared_connections": {
+ "excerpt": {
+ "read": {
+ "to_end": false,
+ "offset": 32,
+ "length": 16,
+ "minimum_source_bytes": 80
+ },
+ "write": {
+ "to_end": true,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 0
+ },
+ "reply_input": false,
+ "view_definitions": 2,
+ "range_definitions": 2,
+ "runtime_view_steps": 0,
+ "write_step": 0,
+ "reply_step": 0,
+ "prepared_program_bytes": 680,
+ "steps": [],
+ "write_effect": "write",
+ "splice_offset": {
+ "value": 0,
+ "from_u32le": false
+ },
+ "splice_remove": {
+ "value": 0,
+ "from_u32le": false
+ }
+ },
+ "write": {
+ "read": {
+ "to_end": true,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 0
+ },
+ "write": {
+ "to_end": false,
+ "offset": 5,
+ "length": 4,
+ "minimum_source_bytes": 12
+ },
+ "reply_input": true,
+ "view_definitions": 3,
+ "range_definitions": 2,
+ "runtime_view_steps": 0,
+ "write_step": 0,
+ "reply_step": 0,
+ "prepared_program_bytes": 680,
+ "steps": [],
+ "write_effect": "write",
+ "splice_offset": {
+ "value": 0,
+ "from_u32le": false
+ },
+ "splice_remove": {
+ "value": 0,
+ "from_u32le": false
+ }
+ }
+ },
+ "field_connections": {
+ "selection": {
+ "read": {
+ "to_end": true,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 0
+ },
+ "write": {
+ "to_end": false,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 8
+ },
+ "reply_input": true,
+ "view_definitions": 2,
+ "range_definitions": 1,
+ "runtime_view_steps": 1,
+ "write_step": 1,
+ "reply_step": 1,
+ "prepared_program_bytes": 680,
+ "steps": [
+ {
+ "source_step": 0,
+ "source": {
+ "offset": 8,
+ "length": 0,
+ "to_end": true
+ },
+ "offset": {
+ "value": 0,
+ "from_u32le": true
+ },
+ "length": {
+ "value": 4,
+ "from_u32le": true
+ }
+ }
+ ],
+ "write_effect": "write",
+ "splice_offset": {
+ "value": 0,
+ "from_u32le": false
+ },
+ "splice_remove": {
+ "value": 0,
+ "from_u32le": false
+ }
+ },
+ "reordered": {
+ "read": {
+ "to_end": true,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 0
+ },
+ "write": {
+ "to_end": false,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 11
+ },
+ "reply_input": true,
+ "view_definitions": 4,
+ "range_definitions": 1,
+ "runtime_view_steps": 1,
+ "write_step": 1,
+ "reply_step": 1,
+ "prepared_program_bytes": 680,
+ "steps": [
+ {
+ "source_step": 0,
+ "source": {
+ "offset": 11,
+ "length": 0,
+ "to_end": true
+ },
+ "offset": {
+ "value": 7,
+ "from_u32le": true
+ },
+ "length": {
+ "value": 3,
+ "from_u32le": true
+ }
+ }
+ ],
+ "write_effect": "write",
+ "splice_offset": {
+ "value": 0,
+ "from_u32le": false
+ },
+ "splice_remove": {
+ "value": 0,
+ "from_u32le": false
+ }
+ },
+ "field_get": {
+ "read": {
+ "to_end": true,
+ "offset": 11,
+ "length": 0,
+ "minimum_source_bytes": 11
+ },
+ "write": {
+ "to_end": true,
+ "offset": 0,
+ "length": 0,
+ "minimum_source_bytes": 0
+ },
+ "reply_input": false,
+ "view_definitions": 1,
+ "range_definitions": 0,
+ "runtime_view_steps": 0,
+ "write_step": 0,
+ "reply_step": 0,
+ "prepared_program_bytes": 680,
+ "steps": [],
+ "write_effect": "write",
+ "splice_offset": {
+ "value": 0,
+ "from_u32le": false
+ },
+ "splice_remove": {
+ "value": 0,
+ "from_u32le": false
+ }
+ }
+ },
+ "document_edits": {
+ "large_document_bytes": 1048576,
+ "small_edit_input_bytes": 11,
+ "storage_rewrites_full_extent": true,
+ "storage_scratch_bytes": 4096,
+ "kind": "correctness-and-admission-not-total-memory-or-performance"
+ },
+ "server_runs": [
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 6,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 1,
+ "commits": 0,
+ "gets": 0,
+ "conflicts": 1,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 1,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 0,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 1048583,
+ "payload_budget": 4194304,
+ "peak_connections": 2,
+ "accepted": 41,
+ "commits": 12,
+ "gets": 14,
+ "conflicts": 4,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 31,
+ "ingress_prefix_copy_bytes": 11674,
+ "borrowed_output_bytes": 2115416,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 2553,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 2,
+ "commits": 0,
+ "gets": 2,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 2,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 2556,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 1048576,
+ "payload_budget": 1048576,
+ "peak_connections": 8,
+ "accepted": 12,
+ "commits": 0,
+ "gets": 3,
+ "conflicts": 0,
+ "budget_rejections": 1,
+ "expired": 9,
+ "releases": 3,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 1048582,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 80,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 2,
+ "commits": 2,
+ "gets": 0,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 2,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 0,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 16,
+ "payload_budget": 16,
+ "peak_connections": 1,
+ "accepted": 3,
+ "commits": 0,
+ "gets": 1,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 1,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 16,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 16,
+ "payload_budget": 16,
+ "peak_connections": 1,
+ "accepted": 2,
+ "commits": 0,
+ "gets": 1,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 1,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 16,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 12,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 5,
+ "commits": 1,
+ "gets": 2,
+ "conflicts": 1,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 5,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 12,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 0,
+ "payload_budget": 1,
+ "peak_connections": 1,
+ "accepted": 3,
+ "commits": 0,
+ "gets": 1,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 0,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 0,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 1048576,
+ "payload_budget": 1048576,
+ "peak_connections": 2,
+ "accepted": 7,
+ "commits": 2,
+ "gets": 3,
+ "conflicts": 0,
+ "budget_rejections": 2,
+ "expired": 0,
+ "releases": 5,
+ "ingress_prefix_copy_bytes": 8006,
+ "borrowed_output_bytes": 3145734,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 54,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 20,
+ "commits": 3,
+ "gets": 4,
+ "conflicts": 1,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 17,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 57,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 19,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 2,
+ "commits": 1,
+ "gets": 1,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 2,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 8,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 14,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 4,
+ "commits": 1,
+ "gets": 1,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 3,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 3,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 34,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 3,
+ "commits": 3,
+ "gets": 0,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 3,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 0,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 23,
+ "payload_budget": 23,
+ "peak_connections": 1,
+ "accepted": 3,
+ "commits": 0,
+ "gets": 2,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 1,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 23,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 1048584,
+ "payload_budget": 1048584,
+ "peak_connections": 2,
+ "accepted": 4,
+ "commits": 1,
+ "gets": 2,
+ "conflicts": 0,
+ "budget_rejections": 1,
+ "expired": 0,
+ "releases": 3,
+ "ingress_prefix_copy_bytes": 3998,
+ "borrowed_output_bytes": 2097091,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 9,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 1,
+ "commits": 0,
+ "gets": 0,
+ "conflicts": 0,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 1,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 0,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 29,
+ "payload_budget": 4194304,
+ "peak_connections": 1,
+ "accepted": 10,
+ "commits": 2,
+ "gets": 4,
+ "conflicts": 1,
+ "budget_rejections": 0,
+ "expired": 0,
+ "releases": 10,
+ "ingress_prefix_copy_bytes": 7,
+ "borrowed_output_bytes": 114,
+ "server_structure_bytes": 41528
+ },
+ {
+ "active": 0,
+ "retained_payload_bytes": 0,
+ "peak_retained_payload_bytes": 11,
+ "payload_budget": 11,
+ "peak_connections": 1,
+ "accepted": 2,
+ "commits": 1,
+ "gets": 0,
+ "conflicts": 0,
+ "budget_rejections": 1,
+ "expired": 0,
+ "releases": 1,
+ "ingress_prefix_copy_bytes": 0,
+ "borrowed_output_bytes": 3,
+ "server_structure_bytes": 41528
+ }
+ ],
+ "storage": "immutable-byte-extents-v1",
+ "execution_core": {
+ "runtime_tests": "passed",
+ "domain_bytes": 200,
+ "work_slot_bytes": 224,
+ "ticket_bytes": 24,
+ "prepared_program_bytes": 680,
+ "forwarding_chain": 1024,
+ "native_storage_pipeline": true
+ },
+ "execution_core_test_sha256": "776be59b5e35de39587fd5a8f703160572b3a6c098a22af635e597208bba1950",
+ "document_edit_units": {
+ "splice_tests": "passed",
+ "checks": [
+ "authored-fields-and-atomic-parse-failure",
+ "binary-edit-oracle-and-old-snapshot",
+ "bounds-conflict-size-overflow",
+ "publication-failures-and-uncertain-durability",
+ "cancel-admission-and-borrowed-reply"
+ ]
+ },
+ "document_edit_test_sha256": "ec0db33c9937034148d934c658c98aa98a2fdb279a92f96a2d7374e2d292468e",
+ "editor_sha256": "23ee47873d7924163ace86cad44946e71fd21a6122930f35eff1c36f5e418bdc",
+ "binary_sha256": "f145f0f30c944e400ef8d1594bd0387f42f42569290f28c7a1272a4ee8849d4c",
+ "environment": {
+ "platform": "Linux-6.18.39+rpt-rpi-2712-aarch64-with-glibc2.41",
+ "machine": "aarch64",
+ "python": "3.14.7",
+ "node": "v24.20.0"
+ },
+ "source_sha256": {
+ "prototypes/connections/flow.c": "3957de06e33985a8310954af07b33c2a1d02a4afdf9bd112d06c99c0b5df7749",
+ "prototypes/connections/flow.h": "289ff43d191270066e238235023f096946f3f561ec5825d2f6c26006db5fc421",
+ "prototypes/connections/store.c": "44702e9414c26d1ee336b2e36e6713560013c2c8d0091a8900042e2468f88015",
+ "prototypes/connections/store.h": "e3cf5f169be02e40f1274105046f29a63a46cd153beaf204d33d6100b9c869b8",
+ "prototypes/connections/program.c": "d7186634d2bfd83bbaf87ea3bafdec8d14be8f556cbf3d9877d07e0074b4b389",
+ "prototypes/connections/program.h": "b9ea0af3759150637ccba9362ccb73be374ed85b449b0461fc61fb14ee50e8bc",
+ "prototypes/connections/runtime.c": "a6c068c6a2cee214b3fe30241459394833917dfb6c0d33052460eab4c6a539a2",
+ "prototypes/connections/runtime.h": "ff03c0be92dcc482247a58a0be54d2dc5c270325b51ceeed37afc2ffa5480b1f",
+ "prototypes/connections/result.h": "00b6cf02262039fd90b197eb781f38c9771beaa8d65f394cba6d3f8d0b2ae79d",
+ "prototypes/connections/evaluate.c": "ee8b91efc733b9d305711b7cbb7b502ae5d3917e06f750b7f62b632ed0ea6d04",
+ "prototypes/connections/store-port.c": "d6bf17878b325e039360816edcbf8d68e41b373cf3e6128d7795e11ae21fdd6f",
+ "prototypes/connections/store-port.h": "a262bac93463bfe9939ca0bdc5989d1665aafc007d61e93c28ffc36478b1fde6",
+ "prototypes/connections/test-runtime.c": "5d08639b5a71572553bda47cbd35562805d601aaa81f20731cd9154768ec025e",
+ "prototypes/connections/server.c": "76645bafe8e4e429155efe96c2d05a59aed506ba89736283e4fdae71a3d9a60f",
+ "prototypes/connections/check.py": "e1735316769b4ce4d5904b9587ccfa3ebeafa26517c53dba4491191d58c97b8e",
+ "prototypes/connections/check_edits.py": "7699eb4bda57ad860acf7be6da3e6de56d6b9a3dcf3b9ff9c7df104f5bcb9224",
+ "prototypes/connections/edit.c": "793d0bde277563c9e11f1225804fb1646e4ce495979d16e8d70d00322a7bec7b",
+ "prototypes/connections/test-splice.c": "2415188c89ff413f10d55a8cf1902e76c585cc4102f01d504bbf84dbe8d90a8f",
+ "prototypes/connections/test-flow.c": "2cd2618015ba6806b1a733af0fc7d0ed6aec48fdec117d18c3a8160f534e130b",
+ "prototypes/connections/test-program.c": "a1b65be05ab2e4e5ccbc56cd1e03e17b0d885f15dc027bf295371ec821e19cc8",
+ "prototypes/connections/test-fields.c": "e5856ae1985dc8407565ebf7b65702478a34a05081c955f127a10d3cdc900507",
+ "prototypes/connections/Makefile": "b5e7ed077be1333f3a948844608785dbab98bdc9c4ae6fe9c6a4805655fc9c63",
+ "prototypes/connections/core-layout.c": "e802b4976c53755ffc045ae9114ebdcf2989d526d8c871c3cfe89d057f4b82b0",
+ "prototypes/connections/check_core.py": "f80ead11764e870f0bde434c93233d518e5874fdb32f77444e7bd8bbe7398a10",
+ "prototypes/connections/core-budget.json": "b4eceaffce900144470dd29076164039b8729bad4ba849789d212e7c952f5082",
+ "prototypes/connections/examples/editor.pure": "8ca6c191b98bf53a592ce24f2b5cd040e41f05c4ccdda7a072d5d7f79870c06a",
+ "prototypes/connections/examples/storage.pure": "6f2fd3733f46b762836405f40a9720de0b865f92a8bcbf9388dda0532c903c74",
+ "prototypes/connections/examples/excerpt.pure": "7ca1b9a4b6a06c32b95e37bcdeb2202ef912ffbf16163f7eea2b00574c703c16",
+ "prototypes/connections/examples/selection.pure": "90a19a080dd31b532163b8063057beee4701d8f74163ac4083833a1d664fe986",
+ "prototypes/connections/examples/select-text.py": "3211ce21bf6058f0131544959272587af4edb3fd5a956aee0a940ab19888f944",
+ "prototypes/workbench/remote.mjs": "6f5aa2bc5a3c88749b2b688c5631eed9e4a5ab41d72eca168bfb67941a8cff2f",
+ "prototypes/workbench/cli.mjs": "55a5ead56fc8ad4c3f2391505fc3dbfa477ccff5b68fc208f700da24d5e194da",
+ "prototypes/workbench/web/core.wasm": "9f760e4a2ce6ea11f2be07693fceca74088884885cc545a70ceef5003d0b2479",
+ "prototypes/workbench/web/runtime.mjs": "9cf12270bb39b3d6ce0384c56df8bdfabfd9459d3375cc7819290a5fe3e5db54",
+ "prototypes/workbench/web/compiler.mjs": "349139612d1f7da5f75ef21c65aa697963b760cb35321150fc36f67f3b40adf1",
+ "prototypes/workbench/web/project.mjs": "8af4cd1a60bbb217c896be20c7c6b8d33989f2166d06e736bf1479d8ecdc8b35",
+ "prototypes/workbench/examples/direct.pure": "57177e5197d75a6185cd3ac5df2be920ddba9a9b0fcc2dddab3560b815249f0a"
+ }
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/Makefile b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/Makefile
new file mode 100644
index 0000000..d1b46e2
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/Makefile
@@ -0,0 +1,59 @@
+CC ?= cc
+CFLAGS ?= -O2 -g
+CFLAGS += -std=c17 -Wall -Wextra -Wpedantic -Werror
+BUILD ?= build
+
+.PHONY: all core editor server check check-core
+CORE = runtime.c evaluate.c
+HOST = store.c store-port.c
+HEADERS = runtime.h program.h store.h store-port.h flow.h result.h
+all: core editor server
+core: $(BUILD)/libpure-execution.a
+editor: $(BUILD)/pure-edit
+server: $(BUILD)/pure-connections
+
+$(BUILD):
+ mkdir -p $@
+
+$(BUILD)/pure-connections: server.c $(HOST) flow.c program.c $(CORE) $(HEADERS) | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) server.c $(HOST) flow.c program.c $(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 $@
+
+$(BUILD)/runtime.o: runtime.c $(HEADERS) | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c runtime.c -o $@
+
+$(BUILD)/evaluate.o: evaluate.c program.h flow.h | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c evaluate.c -o $@
+
+$(BUILD)/libpure-execution.a: $(BUILD)/runtime.o $(BUILD)/evaluate.o
+ $(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-program: test-program.c program.c evaluate.c program.h store.h flow.h 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)
+ $(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)
+ $(CC) $(CPPFLAGS) $(CFLAGS) test-runtime.c program.c $(CORE) $(HOST) $(LDFLAGS) $(LDLIBS) -o $@
+
+$(BUILD)/test-splice: test-splice.c program.c $(CORE) $(HOST) $(HEADERS) | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_STORE_TEST test-splice.c program.c $(CORE) $(HOST) $(LDFLAGS) $(LDLIBS) -o $@
+
+$(BUILD)/core-layout: core-layout.c $(HEADERS) | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) core-layout.c $(LDFLAGS) $(LDLIBS) -o $@
+
+# Run on the release build, separately from sanitizer-instrumented objects.
+check-core: core $(BUILD)/core-layout
+ python3 check_core.py --archive $(BUILD)/libpure-execution.a --layout $(BUILD)/core-layout $(if $(CORE_EVIDENCE),--output "$(CORE_EVIDENCE)")
+
+check: $(BUILD)/test-flow $(BUILD)/test-program $(BUILD)/test-fields $(BUILD)/test-runtime $(BUILD)/test-splice $(BUILD)/pure-edit $(BUILD)/pure-connections
+ $(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 $(if $(EVIDENCE),--output "$(EVIDENCE)")
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/check.py b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/check.py
new file mode 100644
index 0000000..4538995
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/check.py
@@ -0,0 +1,551 @@
+#!/usr/bin/env python3
+"""Exercise local TCP, immutable byte extents, and the existing workbench CLI."""
+import argparse
+from contextlib import contextmanager
+from concurrent.futures import ThreadPoolExecutor
+import fcntl
+import hashlib
+import http.client
+import json
+import platform
+from pathlib import Path
+import select
+import socket
+import struct
+import subprocess
+import sys
+import tempfile
+import time
+from check_edits import check_edits
+
+ROOT = Path(__file__).resolve().parent
+WORKBENCH = ROOT.parent / 'workbench'
+OBJECT_LIMIT = (2 * 6 + 32) * 32768 + 8192
+
+
+class Server:
+ def __init__(self, binary, storage, budget=4 * 1024 * 1024, timeout=5000, program=None):
+ self.process = subprocess.Popen([str(binary), '--store', str(storage), '--port', '0',
+ '--program', str(program or ROOT / 'examples/storage.pure'),
+ '--budget', str(budget), '--timeout-ms', str(timeout), '--send-buffer', '4096'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
+ if not select.select([self.process.stdout], [], [], 15)[0]:
+ self.process.kill()
+ raise AssertionError('server readiness timed out')
+ line = self.process.stdout.readline()
+ if not line:
+ raise AssertionError(self.process.communicate(timeout=5))
+ self.ready = json.loads(line)
+ self.port = self.ready['port']
+ self.stats = None
+
+ def close(self):
+ if self.process.poll() is None:
+ self.process.terminate()
+ try:
+ stdout, stderr = self.process.communicate(timeout=10)
+ except subprocess.TimeoutExpired:
+ self.process.kill()
+ self.process.communicate()
+ raise
+ assert self.process.returncode == 0, (stdout, stderr)
+ self.stats = json.loads(stderr)
+ assert self.stats['active'] == self.stats['retained_payload_bytes'] == 0
+ assert self.stats['peak_retained_payload_bytes'] <= self.stats['payload_budget']
+ assert self.stats['peak_connections'] <= 8
+
+
+@contextmanager
+def serving(*args, **kwargs):
+ server = Server(*args, **kwargs)
+ try:
+ yield server
+ finally:
+ server.close()
+
+
+def rpc(server, method, key, body=b'', expected=None):
+ headers = {'Content-Length': str(len(body))}
+ if expected is not None:
+ headers['If-None-Match' if expected == 0 else 'If-Match'] = '*' if expected == 0 else f'"{expected}"'
+ connection = http.client.HTTPConnection('127.0.0.1', server.port, timeout=8)
+ try:
+ connection.request(method, f'/objects/{key}', body, headers)
+ response = connection.getresponse()
+ return response.status, dict(response.getheaders()), response.read()
+ finally:
+ connection.close()
+
+
+def wire(server, request, chunks=None):
+ with socket.create_connection(('127.0.0.1', server.port), timeout=8) as sock:
+ if chunks:
+ for chunk in chunks:
+ sock.sendall(chunk)
+ else:
+ sock.sendall(request)
+ response = http.client.HTTPResponse(sock)
+ response.begin()
+ return response.status, dict(response.getheaders()), response.read()
+
+
+def header(method, key, size=0, condition=b''):
+ return (f'{method} /objects/{key} HTTP/1.1\r\nHost: localhost\r\n'
+ f'Content-Length: {size}\r\n'.encode() + condition + b'\r\n')
+
+
+def cli(server, commands, source=None, expected_code=0):
+ result = subprocess.run(['node', str(WORKBENCH / 'cli.mjs'), *([str(source)] if source else [])],
+ input=commands.replace('$URL', f'http://127.0.0.1:{server.port}'), text=True,
+ capture_output=True, timeout=30)
+ assert result.returncode == expected_code, (result.stdout, result.stderr)
+ return [json.loads(line) for line in result.stdout.splitlines()], result.stderr
+
+
+def check(binary, directory, editor=None):
+ storage = directory / 'objects'
+ checks, records = [], []
+ with serving(binary, storage) as server:
+ assert rpc(server, 'GET', 'absent')[0] == 404
+ payload = b'\x00\xffbinary\r\n\r\n' + bytes(range(256)) * 41
+ request = header('PUT', 'binary', len(payload), b'If-None-Match: *\r\n') + payload
+ status, headers, _ = wire(server, request, [request[:7], request[7:51], request[51:57], request[57:]])
+ assert status == 200 and headers['ETag'] == '"1"'
+ assert rpc(server, 'GET', 'binary')[2] == payload
+ checks.append('fragmented request and binary bytes round trip')
+ assert rpc(server, 'PUT', 'binary', b'new', 0)[0] == 412
+ assert rpc(server, 'PUT', 'binary', b'new', 1)[0] == 200
+ assert rpc(server, 'PUT', 'binary', b'stale', 1)[0] == 412
+ assert rpc(server, 'GET', 'binary')[2] == b'new'
+ checks.append('conditional create and stale revision preserve committed bytes')
+
+ with (storage / '.writer.lock').open('r+b') as lock:
+ fcntl.lockf(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
+ assert rpc(server, 'PUT', 'binary', b'blocked', 2)[0] == 503
+ fcntl.lockf(lock, fcntl.LOCK_UN)
+ broken = storage / 'obj-broken'
+ broken.write_bytes(b'incomplete')
+ assert rpc(server, 'GET', 'broken')[0] == 500
+ assert rpc(server, 'PUT', 'broken', b'failure', 0)[0] == 500
+ assert broken.read_bytes() == b'incomplete'
+ assert rpc(server, 'GET', 'binary')[2] == b'new'
+ checks.append('writer contention and invalid extent fail without overwriting data')
+
+ with serving(binary, storage) as second_writer:
+ with ThreadPoolExecutor(max_workers=2) as pool:
+ tasks = [pool.submit(rpc, target, 'PUT', 'race', value, 0)
+ for target, value in [(server, b'first'), (second_writer, b'second')]]
+ statuses = [task.result()[0] for task in tasks]
+ assert statuses.count(200) == 1 and all(status in [200, 412, 503] for status in statuses)
+ status, headers, body = rpc(server, 'GET', 'race')
+ assert status == 200 and headers['ETag'] == '"1"' and body in [b'first', b'second']
+ records.append(second_writer.stats)
+ checks.append('two native writers cannot both create the same expected revision')
+
+ sock = socket.create_connection(('127.0.0.1', server.port), timeout=8)
+ sock.sendall(header('PUT', 'incomplete', 100, b'If-None-Match: *\r\n') + b'partial')
+ sock.shutdown(socket.SHUT_WR)
+ assert sock.recv(1) == b''
+ sock.close()
+ assert rpc(server, 'GET', 'incomplete')[0] == 404
+ checks.append('incomplete request never commits and releases its allocation')
+
+ # Force genuine partial socket sends. A write on another connection must
+ # not alter the immutable file whose bytes are still being transmitted.
+ large = bytes(range(256)) * 4096
+ assert rpc(server, 'PUT', 'large', large, 0)[0] == 200
+ sock = socket.create_connection(('127.0.0.1', server.port), timeout=8)
+ sock.sendall(header('GET', 'large'))
+ response = http.client.HTTPResponse(sock)
+ response.begin()
+ assert response.status == 200 and response.getheader('ETag') == '"1"'
+ assert response.read(17) == large[:17]
+ assert rpc(server, 'PUT', 'large', b'changed', 1)[0] == 200
+ assert response.read() == large[17:]
+ sock.close()
+ assert rpc(server, 'GET', 'large')[2] == b'changed'
+ checks.append('borrowed read remains the same snapshot during another commit')
+
+ assert rpc(server, 'PUT', 'large', large, 2)[0] == 200
+ sock = socket.create_connection(('127.0.0.1', server.port), timeout=8)
+ sock.sendall(header('GET', 'large'))
+ assert sock.recv(1)
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
+ sock.close()
+ assert rpc(server, 'GET', 'binary')[2] == b'new'
+ checks.append('receiver reset aborts an outstanding borrowed transfer')
+
+ assert wire(server, header('PUT', 'too_large', OBJECT_LIMIT + 1, b'If-None-Match: *\r\n'))[0] == 413
+ malformed = [
+ b'PUT /objects/bad HTTP/1.1\r\nHost: x\r\nContent-Length: 1\r\nContent-Length: 1\r\nIf-None-Match: *\r\n\r\nx',
+ b'PUT /objects/bad HTTP/1.1\r\nHost: x\r\nTransfer-Encoding: chunked\r\n\r\n',
+ b'GET /objects/bad HTTP/1.1\r\nHost: x\x00hidden\r\n\r\n',
+ ]
+ for request in malformed:
+ assert wire(server, request)[0] == 400
+ assert rpc(server, 'GET', 'bad')[0] == 404
+ checks.append('unsupported framing and oversized payload are rejected before effects')
+
+ # Existing authoring path: define, manipulate, save remotely, reconstruct
+ # in a fresh runtime. No fabricated project fixture or mock storage.
+ source = WORKBENCH / 'examples' / 'direct.pure'
+ saved = directory / 'restored.json'
+ lines, _ = cli(server, 'point drag down 80 180\npoint drag move 210 210\npoint drag up 210 210\n'
+ 'connect $URL authored\npush 0\nquit\n', source)
+ snapshots = [line for line in lines if 'states' in line]
+ assert snapshots
+ expected_states = snapshots[-1]['states']
+ assert expected_states['x'] == 210 and expected_states['y'] == 190 and expected_states['dragging'] == 0
+ lines, _ = cli(server, f'connect $URL authored\npull\nsave-project {saved}\nquit\n')
+ assert [line for line in lines if 'states' in line][-1]['states'] == expected_states
+ document = json.loads(saved.read_text())
+ assert document['version'] == 2 and document['source'] == source.read_text()
+ lines, error = cli(server, 'connect $URL authored\npush 0\nquit\n', source, 1)
+ assert '412' in error
+ checks.append('existing workbench manipulation restores in a fresh runtime and reports conflict')
+
+ assert rpc(server, 'PUT', 'invalid_project', b'{"format":"pure-workbench","version":2,"source":"state x=1","states":[]}', 0)[0] == 200
+ lines, error = cli(server, 'show\nconnect $URL invalid_project\npull\nshow\nquit\n', source, 1)
+ states = [line['states'] for line in lines if 'states' in line]
+ assert states[0] == states[-1] and error
+ lines, error = cli(server, 'point drag down 90 170\nconnect $URL authored\npull\npush\nshow\nquit\n', source, 1)
+ states = [line['states'] for line in lines if 'states' in line]
+ assert states[0] == states[-1] and states[-1]['dragging'] == 1
+ assert len(error.strip().splitlines()) == 2
+ checks.append('invalid or non-idle restore preserves local state and does not adopt remote revision')
+
+ assert rpc(server, 'PUT', 'wide_revision', rpc_bytes(saved), 0)[0] == 200
+ wide = storage / 'obj-wide_revision'
+ raw = wide.read_bytes()
+ wide.write_bytes(raw[:8] + struct.pack('<Q', 9007199254740993) + raw[16:])
+ lines, _ = cli(server, 'connect $URL wide_revision\npull\npush\nquit\n')
+ revisions = [line['revision'] for line in lines if 'remote' in line and 'revision' in line]
+ assert revisions == ['9007199254740993', '9007199254740994']
+ checks.append('revision above JavaScript safe integer round trips without numeric coercion')
+
+ sock = socket.create_connection(('127.0.0.1', server.port), timeout=8)
+ sock.sendall(header('PUT', 'unread_ack', 4, b'If-None-Match: *\r\n') + b'done')
+ try:
+ deadline = time.monotonic() + 3
+ while True:
+ committed = storage / 'obj-unread_ack'
+ if committed.exists():
+ assert committed.read_bytes()[24:] == b'done'
+ break
+ assert time.monotonic() < deadline
+ time.sleep(0.01)
+ finally:
+ sock.close() # Client never consumes the successful response.
+ assert rpc(server, 'PUT', 'unread_ack', b'again', 0)[0] == 412
+ assert rpc(server, 'GET', 'unread_ack')[2] == b'done'
+ checks.append('unread acknowledgment does not undo commit or permit a stale retry')
+
+ # A disconnect after commit can hide the ACK; retries remain conditional.
+ assert rpc(server, 'PUT', 'empty', b'', 0)[0] == 200
+ assert rpc(server, 'GET', 'empty')[2] == b''
+ checks.append('empty body has a valid lifetime and stored revision')
+ records.append(server.stats)
+
+ with serving(binary, storage) as restarted:
+ assert rpc(restarted, 'GET', 'binary')[2] == b'new'
+ assert rpc(restarted, 'GET', 'authored')[2] == rpc_bytes(saved)
+ checks.append('committed authoring state survives process restart')
+ records.append(restarted.stats)
+
+ # Fixed small payload budget is an admission test, not a throughput workload.
+ with serving(binary, storage, budget=1024 * 1024, timeout=1200) as limited:
+ sock = socket.create_connection(('127.0.0.1', limited.port), timeout=8)
+ sock.sendall(header('GET', 'large'))
+ response = http.client.HTTPResponse(sock)
+ response.begin()
+ assert response.status == 200
+ assert response.read(1) == large[:1]
+ status, headers, _ = rpc(limited, 'GET', 'large')
+ assert status == 503 and headers['X-Pure-Error'] == 'payload_budget'
+ # Leave the first receiver stalled until the absolute connection deadline.
+ time.sleep(1.4)
+ assert rpc(limited, 'GET', 'binary')[2] == b'new'
+ response.close()
+ sock.close()
+ checks.append('slow consumer retains its lease; budget rejects another; deadline releases it')
+
+ idle = [socket.create_connection(('127.0.0.1', limited.port), timeout=8) for _ in range(8)]
+ try:
+ for s in idle:
+ s.sendall(b'G')
+ for s in idle:
+ assert s.recv(1) == b''
+ finally:
+ for s in idle:
+ s.close()
+ assert rpc(limited, 'GET', 'binary')[0] == 200
+ checks.append('connection slots stay bounded and recover after header deadlines')
+ assert limited.stats['budget_rejections'] >= 1 and limited.stats['expired'] >= 9
+ records.append(limited.stats)
+ prepared = authored_connections(binary, directory, storage, records, checks)
+ fields = field_connections(binary, directory, storage, records, checks)
+ edits = check_edits(editor, binary, ROOT, directory, serving, rpc, header, records, checks) if editor else None
+ return {'kind': 'prepared-connection-correctness-not-performance', 'checks': checks,
+ 'prepared_connections': prepared,
+ 'field_connections': fields,
+ 'document_edits': edits,
+ 'server_runs': records, 'storage': server.ready['storage']}
+
+
+def authored_connections(binary, directory, storage, records, checks):
+ get = 'on get { let o = store.read(request.key); reply(o, o.body); }'
+ put = 'on put { let s = store.write(request.key, request.revision, request.body); reply(s); }'
+
+ def author(name, source):
+ path = directory / name
+ path.write_text(source)
+ return path
+
+ def explain(path):
+ return json.loads(subprocess.check_output([str(binary), '--check-program', str(path)], text=True))
+
+ with serving(binary, storage) as writer:
+ assert rpc(writer, 'PUT', 'short_parent', bytes(range(48)), 0)[0] == 200
+ assert rpc(writer, 'PUT', 'short_unused', bytes(range(80)), 0)[0] == 200
+ records.append(writer.stats)
+ excerpt = ROOT / 'examples/excerpt.pure'
+ prepared = {'excerpt': explain(excerpt)}
+ assert prepared['excerpt']['read'] == {
+ 'to_end': False, 'offset': 32, 'length': 16, 'minimum_source_bytes': 80}
+ with serving(binary, storage, budget=16, program=excerpt) as selected:
+ status, headers, body = rpc(selected, 'GET', 'large')
+ assert status == 200 and body == bytes(range(32, 48)) and headers['ETag'] == '"3"'
+ # Final [32,48) fits, but the authored parent [16,80) does not.
+ assert rpc(selected, 'GET', 'short_parent')[0] == 413
+ assert rpc(selected, 'GET', 'missing')[0] == 404
+ assert selected.stats['peak_retained_payload_bytes'] == 16
+ records.append(selected.stats)
+ checks.append('authored nested read maps only final demand while preserving parent bounds and revision')
+
+ unused = author('unused.pure', 'on get { let o = store.read(request.key); '
+ 'let unused = range(o.body, 0, 96); let body = range(o.body, 32, 16); reply(o, body); } ' + put)
+ with serving(binary, storage, budget=16, program=unused) as guarded:
+ assert rpc(guarded, 'GET', 'short_unused')[0] == 413
+ assert rpc(guarded, 'GET', 'large')[2] == bytes(range(32, 48))
+ records.append(guarded.stats)
+ checks.append('unused checked view still fails even when response range would be valid')
+
+ select_write = author('write.pure', get + ' on put { let a = range(request.body, 2, 10); '
+ 'let b = range(a, 3, 4); let alias = b; '
+ 'let saved = store.write(request.key, request.revision, alias); reply(saved, b); }')
+ prepared['write'] = explain(select_write)
+ with serving(binary, storage, program=select_write) as writer:
+ status, headers, body = rpc(writer, 'PUT', 'selected', b'0123456789AB', 0)
+ assert status == 200 and body == b'5678' and headers['ETag'] == '"1"'
+ assert rpc(writer, 'GET', 'selected')[2] == b'5678'
+ assert rpc(writer, 'PUT', 'selected', b'012345678', 1)[0] == 413
+ status, headers, body = rpc(writer, 'GET', 'selected')
+ assert status == 200 and body == b'5678' and headers['ETag'] == '"1"'
+ assert rpc(writer, 'PUT', 'selected', b'0123456789AB', 0)[0] == 412
+ records.append(writer.stats)
+ checks.append('authored write and reply share selected input; invalid parent prevents the storage effect')
+
+ metadata = author('metadata.pure', 'on get { let o = store.read(request.key); reply(o); } ' + put)
+ with serving(binary, storage, budget=1, program=metadata) as meta:
+ status, headers, body = rpc(meta, 'GET', 'large')
+ assert status == 200 and headers['ETag'] == '"3"' and body == b''
+ assert rpc(meta, 'GET', 'absent')[0] == 404
+ assert rpc(meta, 'GET', 'broken')[0] == 500
+ assert meta.stats['peak_retained_payload_bytes'] == 0
+ records.append(meta.stats)
+ checks.append('body-free response preserves read existence and malformed-object errors')
+
+ echo = author('echo.pure', get + ' on put { let body = request.body; '
+ 'let saved = store.write(request.key, request.revision, body); reply(saved, body); }')
+ payload = bytes(range(256)) * 4096
+ with serving(binary, storage, budget=len(payload), program=echo) as echoed:
+ with socket.create_connection(('127.0.0.1', echoed.port), timeout=8) as sock:
+ sock.sendall(header('PUT', 'echo', len(payload), b'If-None-Match: *\r\n') + payload)
+ response = http.client.HTTPResponse(sock)
+ response.begin()
+ assert response.status == 200 and response.read(1) == payload[:1]
+ assert rpc(echoed, 'GET', 'binary')[0] == 503
+ assert response.read() == payload[1:]
+ response.close()
+ assert rpc(echoed, 'GET', 'binary')[2] == b'new'
+ with socket.create_connection(('127.0.0.1', echoed.port), timeout=8) as sock:
+ sock.sendall(header('PUT', 'echo_abort', len(payload), b'If-None-Match: *\r\n') + payload)
+ assert sock.recv(1)
+ assert rpc(echoed, 'GET', 'binary')[0] == 503
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
+ deadline = time.monotonic() + 3
+ while rpc(echoed, 'GET', 'binary')[0] == 503:
+ assert time.monotonic() < deadline
+ time.sleep(0.01)
+ assert rpc(echoed, 'GET', 'echo_abort')[2] == payload
+ records.append(echoed.stats)
+ checks.append('input-backed response survives partial send and releases on finish or abort without undoing commit')
+
+ bad = author('invalid.pure', get + get + put)
+ untouched = directory / 'must_not_exist'
+ rejected = subprocess.run([str(binary), '--program', str(bad), '--store', str(untouched)],
+ capture_output=True, text=True, timeout=10)
+ assert rejected.returncode == 2 and 'duplicate handler' in rejected.stderr and not untouched.exists()
+ checks.append('invalid authored program fails preparation before creating storage or accepting requests')
+ return prepared
+
+
+def field_connections(binary, directory, storage, records, checks):
+ program = ROOT / 'examples/selection.pure'
+ plans = {'selection': json.loads(subprocess.check_output(
+ [str(binary), '--check-program', str(program)], text=True))}
+ assert plans['selection']['runtime_view_steps'] == 1
+ assert plans['selection']['steps'][0] == {
+ 'source_step': 0, 'source': {'offset': 8, 'length': 0, 'to_end': True},
+ 'offset': {'value': 0, 'from_u32le': True}, 'length': {'value': 4, 'from_u32le': True}}
+ document = '처음🙂 Pure는 필드를 연결한다.\n끝'
+ document_file = directory / 'document.txt'
+ document_file.write_bytes(document.encode('utf-8'))
+ with serving(binary, storage, program=program) as selected:
+ command = [sys.executable, str(ROOT / 'examples/select-text.py'), str(document_file),
+ '--key', 'text_selection', '--start', '2', '--end', '12', '--url', f'http://127.0.0.1:{selected.port}']
+ result = subprocess.run(command, capture_output=True, text=True, timeout=15)
+ assert result.returncode == 0, (result.stdout, result.stderr)
+ expected = document[2:12].encode('utf-8')
+ assert json.loads(result.stdout) == {'revision': '1', 'selected': document[2:12], 'stored_bytes': len(expected)}
+ assert rpc(selected, 'GET', 'text_selection')[2] == expected
+ checks.append('text client uses character selection; named numeric fields select and persist the matching UTF-8 bytes')
+
+ # Validation precedes the write: even a stale header cannot expose or
+ # commit partial input, and prior content/revision survive all failures.
+ invalid = [b'\0' * n for n in range(8)] + [
+ struct.pack('<II', 0xffffffff, 0) + b'abc',
+ struct.pack('<II', 0, 0xffffffff) + b'abc',
+ struct.pack('<II', 2, 2) + b'abc',
+ struct.pack('<II', 4, 0) + b'abc']
+ for payload in invalid:
+ assert rpc(selected, 'PUT', 'text_selection', payload, 1)[0] == 413
+ status, headers, body = rpc(selected, 'GET', 'text_selection')
+ assert status == 200 and headers['ETag'] == '"1"' and body == expected
+ for key, payload in [('selection_empty', struct.pack('<II', 0, 0)),
+ ('selection_end', struct.pack('<II', 3, 0) + b'abc')]:
+ assert rpc(selected, 'PUT', key, payload, 0)[0] == 200
+ assert rpc(selected, 'GET', key)[2] == b''
+ assert rpc(selected, 'PUT', 'text_selection', struct.pack('<II', 0, 3) + b'abc', 0)[0] == 412
+ checks.append('truncated layouts and invalid data-dependent ranges never change storage; empty and end selections remain valid')
+ records.append(selected.stats)
+
+ declaration = 'layout E { tag: bytes[3]; count: u32le; start: u32le; document: bytes; } '
+ get = 'on get { let o = store.read(request.key); reply(o, o.body); } '
+ put = 'on put { let s = store.write(request.key, request.revision, request.body); reply(s); } '
+ reordered = directory / 'reordered.pure'
+ reordered.write_text(declaration + get + 'on put { let e = view(E, request.body); let alias = e; '
+ 'let part = range(alias.document, alias.start, alias.count); let again = part; '
+ 'let s = store.write(request.key, request.revision, again); reply(s, part); }')
+ plans['reordered'] = json.loads(subprocess.check_output([str(binary), '--check-program', str(reordered)], text=True))
+ assert plans['reordered']['runtime_view_steps'] == 1
+ with serving(binary, storage, program=reordered) as moved:
+ status, headers, body = rpc(moved, 'PUT', 'reordered', b'tag' + struct.pack('<II', 4, 2) + b'abcdefgh', 0)
+ assert status == 200 and body == b'cdef' and headers['ETag'] == '"1"'
+ assert rpc(moved, 'GET', 'reordered')[2] == b'cdef'
+ records.append(moved.stats)
+ checks.append('changed declaration order and unaligned numeric fields determine access; aliases add no dynamic steps')
+
+ unused = directory / 'unused-dynamic.pure'
+ unused.write_text(declaration + get + 'on put { let e = view(E, request.body); '
+ 'let unused = range(e.document, e.start, e.count); '
+ 'let s = store.write(request.key, request.revision, e.document); reply(s); }')
+ with serving(binary, storage, program=unused) as guarded:
+ assert rpc(guarded, 'PUT', 'unused_dynamic', b'tag' + struct.pack('<II', 4, 2) + b'abc', 0)[0] == 413
+ assert rpc(guarded, 'GET', 'unused_dynamic')[0] == 404
+ assert rpc(guarded, 'PUT', 'unused_dynamic', b'tag' + struct.pack('<II', 1, 1) + b'abc', 0)[0] == 200
+ assert rpc(guarded, 'GET', 'unused_dynamic')[2] == b'abc'
+ records.append(guarded.stats)
+ checks.append('unused dynamic field selection retains its validation before the write effect')
+
+ field_get = directory / 'field-get.pure'
+ field_get.write_text(declaration + 'on get { let o = store.read(request.key); '
+ 'let e = view(E, o.body); reply(o, e.document); } ' + put)
+ plans['field_get'] = json.loads(subprocess.check_output([str(binary), '--check-program', str(field_get)], text=True))
+ tail = '다른 길이의 문서'.encode('utf-8')
+ with serving(binary, storage, program=field_get) as writer:
+ assert rpc(writer, 'PUT', 'tail', b'tag' + struct.pack('<II', 0, 0) + tail, 0)[0] == 200
+ assert rpc(writer, 'PUT', 'bad_layout', b'short', 0)[0] == 200
+ assert rpc(writer, 'PUT', 'empty_tail', b'tag' + struct.pack('<II', 0, 0), 0)[0] == 200
+ records.append(writer.stats)
+ with serving(binary, storage, budget=len(tail), program=field_get) as reader:
+ assert rpc(reader, 'GET', 'tail')[2] == tail
+ assert rpc(reader, 'GET', 'empty_tail')[2] == b''
+ assert rpc(reader, 'GET', 'bad_layout')[0] == 413
+ assert reader.stats['peak_retained_payload_bytes'] == len(tail)
+ records.append(reader.stats)
+ checks.append('named variable tail reads use the same file version and charge only the selected suffix')
+
+ document_bytes = bytes(range(256)) * 4096
+ payload = struct.pack('<II', 16, len(document_bytes) - 32) + document_bytes
+ with serving(binary, storage, budget=len(payload), program=program) as slow:
+ with socket.create_connection(('127.0.0.1', slow.port), timeout=8) as sock:
+ sock.sendall(header('PUT', 'dynamic_slow', len(payload), b'If-None-Match: *\r\n') + payload)
+ response = http.client.HTTPResponse(sock)
+ response.begin()
+ assert response.status == 200 and response.read(1) == document_bytes[16:17]
+ assert rpc(slow, 'GET', 'binary')[0] == 503
+ assert response.read() == document_bytes[17:-16]
+ response.close()
+ assert rpc(slow, 'GET', 'binary')[2] == b'new'
+ assert rpc(slow, 'GET', 'dynamic_slow')[2] == document_bytes[16:-16]
+ assert slow.stats['peak_retained_payload_bytes'] == len(payload)
+ records.append(slow.stats)
+ checks.append('data-dependent response keeps and charges the original input through partial transmission')
+ return plans
+
+
+def rpc_bytes(path):
+ # CLI export is pretty JSON; wire export is compact JSON with the same model.
+ return json.dumps(json.loads(path.read_text()), ensure_ascii=False, separators=(',', ':')).encode()
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--server', type=Path, default=ROOT / 'build/pure-connections')
+ parser.add_argument('--output', type=Path)
+ parser.add_argument('--runtime-test', type=Path)
+ parser.add_argument('--splice-test', type=Path)
+ parser.add_argument('--editor', type=Path)
+ args = parser.parse_args()
+ if args.output and args.output.exists():
+ parser.error('evidence file already exists')
+ binary = args.server.resolve()
+ with tempfile.TemporaryDirectory(prefix='pure-connections-check-') as temporary:
+ result = check(binary, Path(temporary), args.editor.resolve() if args.editor else None)
+ if args.runtime_test:
+ runtime_test = args.runtime_test.resolve()
+ tested = subprocess.run([str(runtime_test)], cwd=ROOT, capture_output=True, text=True, timeout=30)
+ assert tested.returncode == 0, (tested.stdout, tested.stderr)
+ result['execution_core'] = json.loads(tested.stdout)
+ result['execution_core_test_sha256'] = hashlib.sha256(runtime_test.read_bytes()).hexdigest()
+ if args.splice_test:
+ splice_test = args.splice_test.resolve()
+ tested = subprocess.run([str(splice_test)], cwd=ROOT, capture_output=True, text=True, timeout=30)
+ assert tested.returncode == 0, (tested.stdout, tested.stderr)
+ result['document_edit_units'] = json.loads(tested.stdout)
+ result['document_edit_test_sha256'] = hashlib.sha256(splice_test.read_bytes()).hexdigest()
+ if args.editor:
+ result['editor_sha256'] = hashlib.sha256(args.editor.resolve().read_bytes()).hexdigest()
+ result['binary_sha256'] = hashlib.sha256(binary.read_bytes()).hexdigest()
+ 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 [*(ROOT / name for name in ('flow.c', 'flow.h', 'store.c', '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',
+ 'core-layout.c', 'check_core.py', 'core-budget.json', 'examples/editor.pure',
+ 'examples/storage.pure', 'examples/excerpt.pure', 'examples/selection.pure', 'examples/select-text.py')),
+ *(WORKBENCH / name for name in ('remote.mjs', 'cli.mjs', 'web/core.wasm', 'web/runtime.mjs',
+ 'web/compiler.mjs', 'web/project.mjs', 'examples/direct.pure'))]}
+ output = json.dumps(result, ensure_ascii=False, indent=2) + '\n'
+ if args.output:
+ args.output.parent.mkdir(parents=True, exist_ok=True)
+ with args.output.open('x') as destination:
+ destination.write(output)
+ print(output, end='')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/check_core.py b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/check_core.py
new file mode 100644
index 0000000..321896e
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/check_core.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+"""Fail when the selected execution core grows past its reviewed cost boundary.
+
+This is a release-build structural check using GNU-compatible ar/nm/size. Run it
+separately from correctness/sanitizer tests; instrumented objects have other costs.
+"""
+import argparse
+import hashlib
+import json
+from pathlib import Path
+import platform
+import subprocess
+
+ROOT = Path(__file__).resolve().parent
+
+
+def run(*args):
+ return subprocess.check_output([str(arg) for arg in args], text=True)
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--archive', type=Path, required=True)
+ parser.add_argument('--layout', type=Path, required=True)
+ parser.add_argument('--budget', type=Path, default=ROOT / 'core-budget.json')
+ parser.add_argument('--output', type=Path)
+ args = parser.parse_args()
+ if args.output and args.output.exists():
+ parser.error('evidence file already exists')
+ budget = json.loads(args.budget.read_text())
+ archive = args.archive.resolve()
+ members = run('ar', 't', archive).splitlines()
+ layout = json.loads(run(args.layout.resolve()))
+ size_output = run('size', archive)
+ rows = [line.split() for line in size_output.splitlines() if line.split() and line.split()[0].isdigit()]
+ if len(rows) != len(members):
+ parser.error('unsupported size output; no footprint claim was made')
+ sizes = {name: sum(int(row[i]) for row in rows) for i, name in enumerate(('text', 'data', 'bss'))}
+ defined = {line.split()[-1] for line in run('nm', '-g', '--defined-only', archive).splitlines()
+ if len(line.split()) >= 3}
+ undefined = {line.split()[-1] for line in run('nm', '-u', archive).splitlines()
+ if len(line.split()) == 2 and line.split()[0] == 'U'}
+ external = sorted(undefined - defined)
+ failures = []
+ if sorted(members) != sorted(budget['archive_members']):
+ failures.append('unexpected archive members')
+ for name, value in sizes.items():
+ if value > budget[f'max_{name}_bytes']:
+ failures.append(f'{name}: {value} > {budget[f"max_{name}_bytes"]}')
+ for name, maximum in budget['layout_max_bytes'].items():
+ if layout[name] > maximum:
+ failures.append(f'{name}: {layout[name]} > {maximum}')
+ extra = set(external) - set(budget['external_symbols_allowed'])
+ if extra:
+ failures.append(f'unexpected dependencies: {sorted(extra)}')
+ result = {'passed': not failures, 'failures': failures, 'budget': budget,
+ 'layout': layout, 'sections': sizes, 'members': members,
+ 'external_symbols': external, 'size_output': size_output,
+ 'archive_sha256': hashlib.sha256(archive.read_bytes()).hexdigest(),
+ 'layout_binary_sha256': hashlib.sha256(args.layout.resolve().read_bytes()).hexdigest(),
+ 'budget_sha256': hashlib.sha256(args.budget.read_bytes()).hexdigest(),
+ 'platform': platform.platform(), 'size_tool': run('size', '--version').splitlines()[0]}
+ output = json.dumps(result, indent=2) + '\n'
+ if args.output:
+ args.output.parent.mkdir(parents=True, exist_ok=True)
+ with args.output.open('x') as destination:
+ destination.write(output)
+ print(output, end='')
+ if failures:
+ raise SystemExit(1)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/check_edits.py b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/check_edits.py
new file mode 100644
index 0000000..1a6dc53
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/check_edits.py
@@ -0,0 +1,108 @@
+"""Real native automation and HTTP clients editing the same authored document."""
+from concurrent.futures import ThreadPoolExecutor
+import json
+import socket
+import struct
+import subprocess
+
+
+def check_edits(editor, binary, root, directory, serving, rpc, header, records, checks):
+ storage = directory / 'edited-objects'
+ program = root / 'examples/editor.pure'
+ file = directory / 'insertion.bin'
+
+ def local(*args, body=None, code=0, source=program, budget=None):
+ if body is not None:
+ file.write_bytes(body)
+ args = (*args, str(file))
+ command = [str(editor), '--program', str(source), '--store', str(storage)]
+ if budget is not None:
+ command += ['--budget', str(budget)]
+ result = subprocess.run(command + [str(arg) for arg in args], capture_output=True, timeout=20)
+ assert result.returncode == code, (command, args, result.stdout, result.stderr)
+ return result
+
+ initial = 'Pure에서 안녕 🌏\n'.encode()
+ created = local('edit', 'note', 0, 0, 0, body=initial)
+ assert json.loads(created.stdout)['revision'] == '1'
+ start = initial.index('안녕'.encode())
+ inserted = '반가워'.encode()
+ expected = initial[:start] + inserted + initial[start + len('안녕'.encode()):]
+ local('edit', 'note', 1, start, len('안녕'.encode()), body=inserted)
+ shown = local('show', 'note')
+ assert shown.stdout == expected and json.loads(shown.stderr)['revision'] == '2'
+ checks.append('native authored byte edit and fresh native process restore UTF-8 content')
+ stale = local('edit', 'note', 1, 0, 0, body=b'bad', code=3)
+ assert json.loads(stale.stderr) == {'error': 'conflict', 'revision': '2'}
+ local('edit', 'note', 2, 0xffffffff, 0, body=b'bad', code=2)
+ assert local('show', 'note').stdout == expected
+ checks.append('native stale revision and invalid byte position preserve the committed document')
+
+ reordered = directory / 'edit-reordered.pure'
+ reordered.write_text('layout E { tag: bytes[1]; remove: u32le; start: u32le; body: bytes; } '
+ 'on get { let o = store.read(request.key); reply(o, o.body); } '
+ 'on put { let e = view(E, request.body); '
+ 'let s = store.splice(request.key, request.revision, e.start, e.remove, e.body); reply(s, e.body); }')
+ local('edit', 'note', 2, len(expected), 0, body=b'!', source=reordered)
+ expected += b'!'
+ assert local('show', 'note', source=reordered).stdout == expected
+ checks.append('native convenience editor derives unaligned reordered field positions from the authored program')
+
+ custom = directory / 'edit-custom.pure'
+ custom.write_text('on get { let o = store.read(request.key); reply(o, o.body); } '
+ 'on put { let s = store.splice(request.key, request.revision, 0, 0, request.body); reply(s); }')
+ local('edit', 'custom', 0, 0, 0, body=b'ignored', source=custom, code=2)
+ applied = local('apply', 'custom', 0, body=b'custom input', source=custom)
+ assert json.loads(applied.stdout) == {'revision': '1', 'reply_bytes': 0}
+ assert local('show', 'custom', source=custom).stdout == b'custom input'
+ checks.append('raw native apply runs another authored input contract without changing the executor')
+
+ with serving(binary, storage, program=program) as server:
+ assert rpc(server, 'GET', 'note')[2] == expected
+ status, headers, body = rpc(server, 'PUT', 'note', struct.pack('<II', len(expected), 0) + b'?', 3)
+ assert status == 200 and headers['ETag'] == '"4"' and body == b'?'
+ expected += b'?'
+ assert local('show', 'note').stdout == expected
+ local('edit', 'note', 4, 0, 4, body=b'PURE')
+ expected = b'PURE' + expected[4:]
+ assert rpc(server, 'PUT', 'note', struct.pack('<II', 0, 0) + b'stale', 4)[0] == 412
+ assert rpc(server, 'GET', 'note')[2] == expected
+ checks.append('native CLI and external HTTP share revisions and the same authored storage effect in both directions')
+ with socket.create_connection(('127.0.0.1', server.port), timeout=8) as sock:
+ sock.sendall(header('PUT', 'note', 12, b'If-Match: "5"\r\n') + b'partial')
+ sock.shutdown(socket.SHUT_WR)
+ assert sock.recv(1) == b''
+ assert rpc(server, 'PUT', 'note', b'short', 5)[0] == 413
+ assert rpc(server, 'PUT', 'note', struct.pack('<II', 0xffffffff, 0), 5)[0] == 413
+ assert rpc(server, 'GET', 'note')[2] == expected
+ checks.append('partial or invalid edit input never modifies the stored document')
+ with serving(binary, storage, program=program) as other:
+ with ThreadPoolExecutor(max_workers=2) as pool:
+ tasks = [pool.submit(rpc, target, 'PUT', 'note', struct.pack('<II', 0, 0) + value, 5)
+ for target, value in ((server, b'A'), (other, b'B'))]
+ statuses = [task.result()[0] for task in tasks]
+ assert statuses.count(200) == 1 and all(status in (200, 412, 503) for status in statuses)
+ status, headers, body = rpc(server, 'GET', 'note')
+ assert status == 200 and headers['ETag'] == '"6"'
+ assert body == (b'A' if statuses[0] == 200 else b'B') + expected
+ records.append(other.stats)
+ checks.append('two processes cannot both splice the same expected document revision')
+ records.append(server.stats)
+
+ # This tests retained input size for a real large edit, not throughput.
+ large = bytes(range(256)) * 4096
+ local('edit', 'large', 0, 0, 0, body=large)
+ local('edit', 'large', 1, 524287, 3, body=b'XYZ', budget=11)
+ expected_large = large[:524287] + b'XYZ' + large[524290:]
+ assert local('show', 'large').stdout == expected_large
+ with serving(binary, storage, program=program, budget=11) as bounded:
+ status, headers, body = rpc(bounded, 'PUT', 'large', struct.pack('<II', 524287, 3) + b'abc', 2)
+ assert status == 200 and headers['ETag'] == '"3"' and body == b'abc'
+ assert rpc(bounded, 'PUT', 'large', struct.pack('<II', 0, 0) + b'abcd', 3)[0] == 503
+ assert bounded.stats['peak_retained_payload_bytes'] == 11
+ records.append(bounded.stats)
+ assert local('show', 'large').stdout == large[:524287] + b'abc' + large[524290:]
+ checks.append('1 MiB document changes with 11 input credits; larger input is rejected before an effect')
+ return {'large_document_bytes': len(large), 'small_edit_input_bytes': 11,
+ 'storage_rewrites_full_extent': True, 'storage_scratch_bytes': 4096,
+ 'kind': 'correctness-and-admission-not-total-memory-or-performance'}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/core-budget.json b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/core-budget.json
new file mode 100644
index 0000000..82d830b
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/core-budget.json
@@ -0,0 +1,15 @@
+{
+ "profile": "current-storage-execution-core",
+ "max_text_bytes": 6144,
+ "max_data_bytes": 0,
+ "max_bss_bytes": 0,
+ "layout_max_bytes": {
+ "domain_bytes": 200,
+ "work_slot_bytes": 224,
+ "ticket_bytes": 24,
+ "prepared_program_bytes": 680
+ },
+ "archive_members": ["runtime.o", "evaluate.o"],
+ "external_symbols_allowed": ["memcpy", "memmove", "memset", "strlen"],
+ "scope": "Release object sections and C bookkeeping, validated with GNU tools on Linux AArch64. Not total RAM, process RSS, stack, linked libraries, parser, storage, network or UI. 6 KiB is a regression ceiling for this profile, not a universal runtime size promise."
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/core-layout.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/core-layout.c
new file mode 100644
index 0000000..6687be7
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/core-layout.c
@@ -0,0 +1,11 @@
+#include "runtime.h"
+#include <stdio.h>
+
+/* Host-side measurement tool; never linked into libpure-execution.a. */
+int main(void) {
+ printf("{\"domain_bytes\":%zu,\"work_slot_bytes\":%zu,\"ticket_bytes\":%zu,"
+ "\"prepared_program_bytes\":%zu,\"pointer_bytes\":%zu}\n",
+ sizeof(PureRuntime), sizeof(PureWork), sizeof(PureTicket),
+ sizeof(PureProgram), sizeof(void *));
+ return 0;
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/edit.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/edit.c
new file mode 100644
index 0000000..4daad14
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/edit.c
@@ -0,0 +1,153 @@
+#define _POSIX_C_SOURCE 200809L
+#include "runtime.h"
+#include "store-port.h"
+#include "store.h"
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Native automation entry for the same prepared document program as the
+ * network adapter. No socket or body serialization in the local execution. */
+static bool number(const char *text, uint64_t limit, uint64_t *out) {
+ if (!*text) return false;
+ uint64_t value = 0;
+ for (; *text; ++text) {
+ if (*text < '0' || *text > '9') return false;
+ unsigned digit = (unsigned)(*text - '0');
+ if (digit > limit || value > (limit - digit) / 10) return false;
+ value = value * 10 + digit;
+ }
+ *out = value;
+ return true;
+}
+
+static const char *message(PureResult status) {
+ switch (status) {
+ case PURE_OK: return "ok";
+ case PURE_NOT_FOUND: return "not_found";
+ case PURE_CONFLICT: return "conflict";
+ case PURE_BUSY: return "busy";
+ case PURE_BUDGET: return "payload_budget";
+ case PURE_LIMIT: return "limit";
+ case PURE_UNCERTAIN: return "durability_unknown";
+ case PURE_DENIED: return "denied";
+ case PURE_ALLOCATION: return "allocation";
+ case PURE_INVALID: return "invalid";
+ default: return "failed";
+ }
+}
+
+static void put32(unsigned char *to, uint32_t value) {
+ for (unsigned i = 0; i < 4; ++i) to[i] = (unsigned char)(value >> (8 * i));
+}
+
+/* The convenience command fills the program's two numeric splice arguments
+ * and its trailing insertion bytes. A more general input uses apply. */
+static bool edit_layout(const PureProgram *p, size_t *prefix) {
+ if (!p->splice || !p->write.to_end || p->write_step || p->input_steps ||
+ !p->splice_offset.from_u32le || !p->splice_remove.from_u32le) return false;
+ size_t start = p->splice_offset.value, remove = p->splice_remove.value;
+ *prefix = p->write.offset;
+ if (*prefix > PURE_OBJECT_LIMIT || p->input_required > *prefix || start > *prefix ||
+ remove > *prefix || *prefix - start < 4 || *prefix - remove < 4) return false;
+ return start < remove ? remove - start >= 4 : start - remove >= 4;
+}
+
+int main(int argc, char **argv) {
+ const char *program_path = NULL, *store_path = NULL;
+ size_t budget = 4u * 1024u * 1024u;
+ int at = 1;
+ for (; at + 1 < argc && !strncmp(argv[at], "--", 2); at += 2) {
+ uint64_t value;
+ if (!strcmp(argv[at], "--program")) program_path = argv[at + 1];
+ else if (!strcmp(argv[at], "--store")) store_path = argv[at + 1];
+ else if (!strcmp(argv[at], "--budget") && number(argv[at + 1], SIZE_MAX, &value)) budget = (size_t)value;
+ else goto usage;
+ }
+ if (!program_path || !store_path || at >= argc) goto usage;
+ bool show = !strcmp(argv[at], "show"), edit = !strcmp(argv[at], "edit");
+ if ((!show && !edit && strcmp(argv[at], "apply")) ||
+ argc - at != (show ? 2 : edit ? 6 : 4)) goto usage;
+ uint64_t expected = 0, offset = 0, remove = 0;
+ if (!show && !number(argv[at + 2], INT64_MAX, &expected)) goto usage;
+ if (edit && (!number(argv[at + 3], UINT32_MAX, &offset) || !number(argv[at + 4], UINT32_MAX, &remove))) goto usage;
+ PureProgram program;
+ char error[160];
+ if (!pure_program_load(program_path, &program, error, sizeof(error))) {
+ fprintf(stderr, "Program: %s\n", error); return 2;
+ }
+ size_t prefix = 0;
+ if (edit && !edit_layout(&program, &prefix)) {
+ fputs("edit requires two distinct u32le splice fields and trailing insertion bytes; use apply for a custom input\n", stderr);
+ return 2;
+ }
+ FILE *file = NULL;
+ size_t length = 0;
+ if (!show) {
+ file = fopen(argv[at + (edit ? 5 : 3)], "rb");
+ if (!file) { perror("input"); return 2; }
+ long bytes;
+ if (fseek(file, 0, SEEK_END) || (bytes = ftell(file)) < 0 ||
+ (uintmax_t)bytes > PURE_OBJECT_LIMIT - prefix || fseek(file, 0, SEEK_SET)) {
+ fputs("input must be a seekable file within the request size limit\n", stderr);
+ fclose(file); return 2;
+ }
+ length = (size_t)bytes;
+ }
+ if (pure_store_init(store_path) != PURE_OK) {
+ if (file) fclose(file);
+ fputs("cannot initialize store\n", stderr); return 2;
+ }
+ PureRuntime runtime;
+ PureWork work[1];
+ if (!pure_runtime_init(&runtime, work, 1, &program, pure_store_host(store_path), budget)) {
+ if (file) fclose(file);
+ return 2;
+ }
+ PureTicket ticket;
+ PureResult admitted = pure_runtime_accept(&runtime, show ? PURE_INPUT_READ : PURE_INPUT_WRITE,
+ argv[at + 1], (int64_t)expected, prefix + length, &ticket);
+ if (admitted != PURE_OK) {
+ if (file) fclose(file);
+ fprintf(stderr, "%s\n", message(admitted)); return 2;
+ }
+ if (!show) {
+ unsigned char *input = pure_runtime_ingress(ticket, NULL);
+ if (prefix) memset(input, 0, prefix);
+ if (edit) {
+ put32(input + program.splice_offset.value, (uint32_t)offset);
+ put32(input + program.splice_remove.value, (uint32_t)remove);
+ }
+ bool valid = !length || fread(input + prefix, 1, length, file) == length;
+ if (fgetc(file) != EOF || ferror(file)) valid = false;
+ if (fclose(file)) valid = false;
+ if (!valid) {
+ pure_runtime_release(ticket);
+ fputs("input changed or could not be read; nothing was applied\n", stderr); return 2;
+ }
+ if (!pure_runtime_ready(ticket)) { pure_runtime_release(ticket); return 2; }
+ }
+ PureOutcome outcome;
+ while (!pure_runtime_result(ticket, &outcome)) {
+ if (!pure_runtime_step(&runtime)) { pure_runtime_release(ticket); return 2; }
+ }
+ int status = 0;
+ if (outcome.status != PURE_OK) {
+ fprintf(stderr, "{\"error\":\"%s\",\"revision\":\"%" PRId64 "\"}\n", message(outcome.status), outcome.revision);
+ status = outcome.status == PURE_CONFLICT ? 3 : 2;
+ } else if (show) {
+ if (outcome.body.size && fwrite(outcome.body.data, 1, outcome.body.size, stdout) != outcome.body.size) status = 2;
+ fprintf(stderr, "{\"revision\":\"%" PRId64 "\",\"bytes\":%zu}\n", outcome.revision, outcome.body.size);
+ } else {
+ if (printf("{\"revision\":\"%" PRId64 "\",\"reply_bytes\":%zu}\n", outcome.revision, outcome.body.size) < 0) status = 2;
+ }
+ if (fflush(stdout)) status = 2;
+ pure_runtime_release(ticket);
+ return status;
+usage:
+ fputs("pure-edit --program FILE --store DIRECTORY [--budget BYTES] show KEY\n"
+ "pure-edit --program FILE --store DIRECTORY [--budget BYTES] edit KEY REVISION BYTE_OFFSET REMOVE_BYTES INSERT_FILE\n"
+ "pure-edit --program FILE --store DIRECTORY [--budget BYTES] apply KEY REVISION INPUT_FILE\n"
+ "edit uses the prepared program's field locations; apply accepts its raw input bytes.\n", stderr);
+ return 2;
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/evaluate.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/evaluate.c
new file mode 100644
index 0000000..88ffae7
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/evaluate.c
@@ -0,0 +1,53 @@
+#include "program.h"
+#include <stdint.h>
+
+bool pure_region_span(PureRegion region, PureSpan source, PureSpan *out) {
+ *out = (PureSpan){0};
+ if (region.offset > source.size) return false;
+ size_t length = region.to_end ? source.size - region.offset : region.length;
+ if (length > source.size - region.offset) return false;
+ *out = (PureSpan){length ? source.data + region.offset : NULL, length};
+ return true;
+}
+
+static bool index_read(PureIndex index, PureSpan source, size_t *out) {
+ if (!index.from_u32le) { *out = index.value; return true; }
+ if (index.value > source.size || 4 > source.size - index.value) return false;
+ const unsigned char *bytes = source.data + index.value;
+ *out = (size_t)bytes[0] | (size_t)bytes[1] << 8 | (size_t)bytes[2] << 16 | (size_t)bytes[3] << 24;
+ return true;
+}
+
+bool pure_program_splice(const PureProgram *p, PureSpan source, size_t *offset, size_t *remove) {
+ return p->splice && index_read(p->splice_offset, source, offset) &&
+ index_read(p->splice_remove, source, remove);
+}
+
+static bool resolve(PureRegion region, size_t step, PureSpan source,
+ const PureSpan *values, size_t count, PureSpan *out) {
+ if (!step) return pure_region_span(region, source, out);
+ if (step > count) return false;
+ *out = values[step - 1];
+ return true;
+}
+
+bool pure_program_input(const PureProgram *p, PureSpan source, PureSpan *write, PureSpan *reply) {
+ *write = (PureSpan){0};
+ *reply = (PureSpan){0};
+ if (source.size < p->input_required || p->input_steps > PURE_DYNAMIC_LIMIT) return false;
+ PureSpan values[PURE_DYNAMIC_LIMIT];
+ for (size_t i = 0; i < p->input_steps; ++i) {
+ const PureRangeStep *step = &p->steps[i];
+ PureSpan parent;
+ size_t offset, length;
+ if (!resolve(step->source, step->source_step, source, values, i, &parent) ||
+ !index_read(step->offset, source, &offset) || !index_read(step->length, source, &length) ||
+ !pure_region_span((PureRegion){.offset = offset, .length = length}, parent, &values[i])) return false;
+ }
+ PureSpan stored, returned = {0};
+ if (!resolve(p->write, p->write_step, source, values, p->input_steps, &stored) ||
+ (p->reply_input && !resolve(p->reply, p->reply_step, source, values, p->input_steps, &returned))) return false;
+ *write = stored;
+ *reply = returned;
+ return true;
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/editor.pure b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/editor.pure
new file mode 100644
index 0000000..4de78bc
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/editor.pure
@@ -0,0 +1,19 @@
+// A revision-checked byte edit. The input carries only the replacement.
+// UTF-8 cursor/grapheme positions are translated to byte ranges by the UI.
+layout Edit {
+ start: u32le;
+ remove: u32le;
+ insert: bytes;
+}
+
+on get {
+ let document = store.read(request.key);
+ reply(document, document.body);
+}
+
+on put {
+ let edit = view(Edit, request.body);
+ let saved = store.splice(request.key, request.revision,
+ edit.start, edit.remove, edit.insert);
+ reply(saved, edit.insert);
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/excerpt.pure b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/excerpt.pure
new file mode 100644
index 0000000..622f9bb
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/excerpt.pure
@@ -0,0 +1,13 @@
+// Read bytes 32..47 of an object that must contain the complete 64-byte window.
+// Preparation keeps the size check for 16..79, and maps only 32..47 for reply.
+on get {
+ let object = store.read(request.key);
+ let window = range(object.body, 16, 64);
+ let excerpt = range(window, 16, 16);
+ reply(object, excerpt);
+}
+
+on put {
+ let saved = store.write(request.key, request.revision, request.body);
+ reply(saved);
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/select-text.py b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/select-text.py
new file mode 100644
index 0000000..ffaf80b
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/select-text.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+"""Save a UTF-8 document selection through selection.pure (character indices)."""
+import argparse
+import http.client
+import json
+from pathlib import Path
+import re
+import struct
+from urllib.parse import urlsplit
+
+LIMIT = (2 * 6 + 32) * 32768 + 8192
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('file', type=Path)
+ parser.add_argument('--key', required=True)
+ parser.add_argument('--start', type=int, required=True, help='first Unicode code point, starting at 0')
+ parser.add_argument('--end', type=int, required=True, help='exclusive Unicode code point boundary')
+ parser.add_argument('--revision', type=int, default=0, help='0 creates; otherwise expected stored revision')
+ parser.add_argument('--url', default='http://127.0.0.1:8767')
+ args = parser.parse_args()
+ url = urlsplit(args.url)
+ try:
+ port = url.port or 80
+ except ValueError as error:
+ parser.error(str(error))
+ if (url.scheme != 'http' or url.hostname not in ['localhost', '127.0.0.1'] or
+ url.username is not None or url.password is not None or url.path not in ['', '/'] or
+ url.query or url.fragment):
+ parser.error('use a local HTTP server origin')
+ if not re.fullmatch(r'[A-Za-z0-9_-]{1,64}', args.key) or not 0 <= args.revision <= 2**63 - 1:
+ parser.error('invalid object key or revision')
+ try:
+ with args.file.open('rb') as source:
+ document = source.read(LIMIT - 8 + 1)
+ if len(document) > LIMIT - 8:
+ parser.error('document exceeds the prototype request limit')
+ text = document.decode('utf-8')
+ except (OSError, UnicodeError) as error:
+ parser.error(str(error))
+ if not 0 <= args.start <= args.end <= len(text):
+ parser.error('selection is outside the document')
+ start = len(text[:args.start].encode('utf-8'))
+ selected = text[args.start:args.end].encode('utf-8')
+ # The boundary layout is explicit; storage receives only selected bytes.
+ payload = struct.pack('<II', start, len(selected)) + document
+ headers = {'Content-Type': 'application/octet-stream'}
+ headers['If-None-Match' if args.revision == 0 else 'If-Match'] = (
+ '*' if args.revision == 0 else f'"{args.revision}"')
+ connection = http.client.HTTPConnection(url.hostname, port, timeout=12)
+ try:
+ connection.request('PUT', '/objects/' + args.key, payload, headers)
+ response = connection.getresponse()
+ body = response.read(LIMIT + 1)
+ if response.status != 200:
+ parser.error(f'storage response {response.status}: {response.getheader("X-Pure-Error")}')
+ if body != selected:
+ parser.error('response differs from the selection; check the installed program (write may have occurred)')
+ revision = response.getheader('ETag', '')
+ if not re.fullmatch(r'"[1-9][0-9]*"', revision) or int(revision[1:-1]) > 2**63 - 1:
+ parser.error('response has no valid stored revision (write may have occurred)')
+ except (OSError, http.client.HTTPException) as error:
+ parser.error(f'{error}; storage outcome is unknown if the request was sent')
+ finally:
+ connection.close()
+ print(json.dumps({'revision': revision[1:-1], 'selected': selected.decode('utf-8'),
+ 'stored_bytes': len(selected)}, ensure_ascii=False))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/selection.pure b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/selection.pure
new file mode 100644
index 0000000..7d9d4ec
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/selection.pure
@@ -0,0 +1,19 @@
+// This is an input boundary layout, not a required storage or RAM model.
+// The client sends two little-endian u32 values followed by document bytes.
+layout Selection {
+ start: u32le;
+ count: u32le;
+ document: bytes;
+}
+
+on get {
+ let saved = store.read(request.key);
+ reply(saved, saved.body);
+}
+
+on put {
+ let input = view(Selection, request.body);
+ let selected = range(input.document, input.start, input.count);
+ let saved = store.write(request.key, request.revision, selected);
+ reply(saved, selected);
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/storage.pure b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/storage.pure
new file mode 100644
index 0000000..ff54ea3
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/examples/storage.pure
@@ -0,0 +1,11 @@
+// The host supplies request bytes, an object name, and the expected revision.
+// Failed storage results propagate to the host's response without executing reply.
+on get {
+ let object = store.read(request.key);
+ reply(object, object.body);
+}
+
+on put {
+ let saved = store.write(request.key, request.revision, request.body);
+ reply(saved);
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/flow.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/flow.c
new file mode 100644
index 0000000..1070c70
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/flow.c
@@ -0,0 +1,41 @@
+#include "flow.h"
+#include <assert.h>
+
+void pure_transfer_abort(PureTransfer *t) {
+ if (!t->active) return;
+ PureRelease release = t->release;
+ void *owner = t->owner;
+ *t = (PureTransfer){0};
+ if (release) release(owner);
+}
+
+static void advance(PureTransfer *t) {
+ while (t->active && t->part < 2 && t->offset == t->spans[t->part].size) {
+ t->part++;
+ t->offset = 0;
+ }
+ if (t->active && t->part == 2) pure_transfer_abort(t);
+}
+
+void pure_transfer_init(PureTransfer *t, PureSpan header, PureSpan body,
+ void *owner, PureRelease release) {
+ assert(!t->active);
+ assert((!header.size || header.data) && (!body.size || body.data));
+ *t = (PureTransfer){.spans = {header, body}, .owner = owner,
+ .release = release, .active = true};
+ advance(t);
+}
+
+PureSpan pure_transfer_next(const PureTransfer *t, size_t limit) {
+ if (!t->active) return (PureSpan){0};
+ PureSpan span = t->spans[t->part];
+ size_t remaining = span.size - t->offset;
+ return (PureSpan){span.data + t->offset, remaining < limit ? remaining : limit};
+}
+
+bool pure_transfer_consume(PureTransfer *t, size_t bytes) {
+ if (!t->active || bytes > t->spans[t->part].size - t->offset) return false;
+ t->offset += bytes;
+ advance(t);
+ return true;
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/flow.h b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/flow.h
new file mode 100644
index 0000000..6e27c58
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/flow.h
@@ -0,0 +1,25 @@
+#ifndef PURE_FLOW_H
+#define PURE_FLOW_H
+#include <stdbool.h>
+#include <stddef.h>
+
+typedef struct { const unsigned char *data; size_t size; } PureSpan;
+typedef void (*PureRelease)(void *owner);
+
+/* A borrowed body stays alive until every byte is consumed or the transfer is
+ * aborted. A successful send() consumes bytes; peer receipt is a separate fact.
+ * Single owner thread; callbacks must not reenter or reuse this transfer. */
+typedef struct {
+ PureSpan spans[2];
+ size_t part, offset;
+ void *owner;
+ PureRelease release;
+ bool active;
+} PureTransfer;
+
+void pure_transfer_init(PureTransfer *, PureSpan header, PureSpan body,
+ void *owner, PureRelease);
+PureSpan pure_transfer_next(const PureTransfer *, size_t limit);
+bool pure_transfer_consume(PureTransfer *, size_t bytes);
+void pure_transfer_abort(PureTransfer *);
+#endif
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/program.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/program.c
new file mode 100644
index 0000000..8680782
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/program.c
@@ -0,0 +1,366 @@
+#include "program.h"
+#include "store.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+enum { NAME = 256, NUMBER, SYMBOLS = 32, LAYOUTS = 4, FIELDS = 16 };
+typedef enum { BYTE_VALUE, RESULT_VALUE, LAYOUT_VALUE, INDEX_VALUE } ValueKind;
+typedef struct {
+ char name[32];
+ ValueKind kind;
+ PureRegion region;
+ size_t step, layout;
+ PureIndex index;
+} Symbol;
+typedef struct {
+ char name[32];
+ size_t offset, length;
+ bool number, tail;
+} Field;
+typedef struct {
+ char name[32];
+ Field fields[FIELDS];
+ size_t count, prefix;
+ bool tail;
+} Layout;
+typedef struct {
+ const char *source;
+ size_t length, at, line, token_line;
+ int token;
+ char name[32];
+ size_t number;
+ char *error;
+ size_t error_size;
+ bool failed, put, effect;
+ Symbol symbols[SYMBOLS];
+ size_t count, layout_count;
+ Layout layouts[LAYOUTS];
+ PureProgram program;
+} Parser;
+
+static bool reject(Parser *p, const char *message) {
+ if (!p->failed && p->error_size) snprintf(p->error, p->error_size, "line %zu: %s", p->token_line, message);
+ p->failed = true;
+ return false;
+}
+
+static bool letter(char c) {
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
+}
+
+static bool next(Parser *p) {
+ while (p->at < p->length) {
+ char c = p->source[p->at];
+ if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ if (c == '\n') ++p->line;
+ ++p->at;
+ } else if (c == '/' && p->at + 1 < p->length && p->source[p->at + 1] == '/') {
+ while (p->at < p->length && p->source[p->at] != '\n') ++p->at;
+ } else break;
+ }
+ p->token_line = p->line;
+ p->name[0] = 0;
+ p->token = 0;
+ if (p->at == p->length) return true;
+ char c = p->source[p->at++];
+ if (letter(c)) {
+ size_t start = p->at - 1;
+ while (p->at < p->length && (letter(p->source[p->at]) ||
+ (p->source[p->at] >= '0' && p->source[p->at] <= '9'))) ++p->at;
+ size_t size = p->at - start;
+ if (size >= sizeof(p->name)) return reject(p, "name exceeds 31 bytes");
+ memcpy(p->name, p->source + start, size);
+ p->name[size] = 0;
+ p->token = NAME;
+ } else if (c >= '0' && c <= '9') {
+ size_t value = (size_t)(c - '0');
+ while (p->at < p->length && p->source[p->at] >= '0' && p->source[p->at] <= '9') {
+ unsigned digit = (unsigned)(p->source[p->at++] - '0');
+ if (value > (SIZE_MAX - digit) / 10) return reject(p, "integer overflow");
+ value = value * 10 + digit;
+ }
+ p->number = value;
+ p->token = NUMBER;
+ } else if (c && strchr("{}().,=;:[]", c)) p->token = (unsigned char)c;
+ else return reject(p, "unexpected character");
+ return true;
+}
+
+static bool is_word(Parser *p, const char *word) {
+ return p->token == NAME && !strcmp(p->name, word);
+}
+
+static bool word(Parser *p, const char *expected) {
+ return is_word(p, expected) ? next(p) : reject(p, expected);
+}
+
+static bool token(Parser *p, int expected) {
+ return p->token == expected ? next(p) : reject(p, "unexpected token");
+}
+
+static Symbol *find(Parser *p, const char *name) {
+ for (size_t i = 0; i < p->count; ++i)
+ if (!strcmp(name, p->symbols[i].name)) return &p->symbols[i];
+ return NULL;
+}
+
+static bool field(Parser *p, const char *object, const char *name) {
+ return word(p, object) && token(p, '.') && word(p, name);
+}
+
+static bool require_bytes(Parser *p, const Symbol *value) {
+ return value->kind == BYTE_VALUE || reject(p, "expected bytes; select a byte field");
+}
+
+static void require_length(Parser *p, size_t required) {
+ size_t *minimum = p->put ? &p->program.input_required : &p->program.read_required;
+ if (required > *minimum) *minimum = required;
+}
+
+static Layout *find_layout(Parser *p, const char *name) {
+ for (size_t i = 0; i < p->layout_count; ++i)
+ if (!strcmp(name, p->layouts[i].name)) return &p->layouts[i];
+ return NULL;
+}
+
+static bool layout_definition(Parser *p) {
+ if (p->layout_count == LAYOUTS) return reject(p, "program exceeds 4 layouts");
+ if (!next(p)) return false;
+ if (p->token != NAME || find_layout(p, p->name)) return reject(p, "expected a unique layout name");
+ Layout *layout = &p->layouts[p->layout_count];
+ strcpy(layout->name, p->name);
+ if (!next(p) || !token(p, '{')) return false;
+ while (p->token != '}') {
+ if (layout->count == FIELDS) return reject(p, "layout exceeds 16 fields");
+ if (layout->tail) return reject(p, "variable bytes must be the last field");
+ if (p->token != NAME) return reject(p, "expected a field name");
+ for (size_t i = 0; i < layout->count; ++i)
+ if (!strcmp(layout->fields[i].name, p->name)) return reject(p, "duplicate field");
+ Field *f = &layout->fields[layout->count];
+ strcpy(f->name, p->name);
+ f->offset = layout->prefix;
+ if (!next(p) || !token(p, ':')) return false;
+ if (is_word(p, "u32le")) {
+ f->number = true;
+ f->length = 4;
+ if (!next(p)) return false;
+ } else if (is_word(p, "bytes")) {
+ if (!next(p)) return false;
+ if (p->token == '[') {
+ if (!next(p)) return false;
+ if (p->token != NUMBER) return reject(p, "fixed bytes requires a constant size");
+ f->length = p->number;
+ if (!next(p) || !token(p, ']')) return false;
+ } else { f->tail = true; layout->tail = true; }
+ } else return reject(p, "supported field types: u32le, bytes[N], bytes");
+ if (f->length > PURE_OBJECT_LIMIT - layout->prefix) return reject(p, "layout exceeds object bound");
+ layout->prefix += f->length;
+ ++layout->count;
+ if (!token(p, ';')) return false;
+ }
+ if (!layout->count) return reject(p, "empty layout");
+ ++p->layout_count;
+ return token(p, '}');
+}
+
+static bool reference(Parser *p, Symbol *out) {
+ if (is_word(p, "request")) {
+ if (!p->put) return reject(p, "request.body is only available in on put");
+ *out = (Symbol){.kind = BYTE_VALUE, .region = {.to_end = true}};
+ return field(p, "request", "body");
+ }
+ Symbol *symbol = p->token == NAME ? find(p, p->name) : NULL;
+ if (!symbol) return reject(p, "unknown value");
+ *out = *symbol;
+ if (!next(p)) return false;
+ if (p->token != '.') return true;
+ if (!next(p)) return false;
+ if (symbol->kind == RESULT_VALUE) {
+ if (p->put) return reject(p, "write result has no body; use the input value");
+ *out = (Symbol){.kind = BYTE_VALUE, .region = {.to_end = true}};
+ return word(p, "body");
+ }
+ if (symbol->kind != LAYOUT_VALUE || p->token != NAME) return reject(p, "expected a layout field");
+ Layout *layout = &p->layouts[symbol->layout];
+ Field *f = NULL;
+ for (size_t i = 0; i < layout->count; ++i)
+ if (!strcmp(p->name, layout->fields[i].name)) f = &layout->fields[i];
+ if (!f) return reject(p, "unknown layout field");
+ size_t offset = symbol->region.offset + f->offset;
+ *out = (Symbol){.kind = f->number ? INDEX_VALUE : BYTE_VALUE};
+ if (f->number) out->index = (PureIndex){.value = offset, .from_u32le = true};
+ else out->region = (PureRegion){.offset = offset,
+ .length = f->tail ? (symbol->region.to_end ? 0 : symbol->region.length - f->offset) : f->length,
+ .to_end = f->tail && symbol->region.to_end};
+ return next(p);
+}
+
+static bool byte_reference(Parser *p, Symbol *out) {
+ return reference(p, out) && require_bytes(p, out);
+}
+
+static bool index_value(Parser *p, PureIndex *out) {
+ if (p->token == NUMBER) {
+ *out = (PureIndex){.value = p->number};
+ return next(p);
+ }
+ Symbol value;
+ if (!reference(p, &value)) return false;
+ if (value.kind != INDEX_VALUE) return reject(p, "range requires an integer or u32le field");
+ *out = value.index;
+ return true;
+}
+
+static bool layout_view(Parser *p, Symbol *out) {
+ if (!next(p) || !token(p, '(')) return false;
+ Layout *layout = p->token == NAME ? find_layout(p, p->name) : NULL;
+ if (!layout) return reject(p, "unknown layout");
+ if (!next(p) || !token(p, ',')) return false;
+ Symbol source;
+ if (!byte_reference(p, &source) || !token(p, ')')) return false;
+ if (source.step) return reject(p, "layout view requires a statically located source");
+ size_t bound = source.region.to_end ? PURE_OBJECT_LIMIT - source.region.offset : source.region.length;
+ if (layout->prefix > bound) return reject(p, "layout exceeds source bound");
+ require_length(p, source.region.offset + layout->prefix);
+ *out = (Symbol){.kind = LAYOUT_VALUE, .region = source.region, .layout = (size_t)(layout - p->layouts)};
+ if (!layout->tail) { out->region.length = layout->prefix; out->region.to_end = false; }
+ return true;
+}
+
+static bool view(Parser *p, Symbol *out) {
+ if (is_word(p, "view")) return layout_view(p, out);
+ if (!is_word(p, "range")) return reference(p, out);
+ Symbol parent;
+ PureIndex offset, length;
+ if (!next(p) || !token(p, '(') || !byte_reference(p, &parent) || !token(p, ',') ||
+ !index_value(p, &offset) || !token(p, ',') || !index_value(p, &length) || !token(p, ')')) return false;
+ bool dynamic = parent.step || offset.from_u32le || length.from_u32le;
+ *out = (Symbol){.kind = BYTE_VALUE};
+ if (dynamic) {
+ if (!p->put) return reject(p, "data-dependent ranges currently require PUT input");
+ if (p->program.input_steps == PURE_DYNAMIC_LIMIT) return reject(p, "input exceeds 8 dynamic ranges");
+ if ((!offset.from_u32le && offset.value > PURE_OBJECT_LIMIT) ||
+ (!length.from_u32le && length.value > PURE_OBJECT_LIMIT)) return reject(p, "range exceeds object bound");
+ PureRangeStep *step = &p->program.steps[p->program.input_steps++];
+ *step = (PureRangeStep){.source = parent.region, .source_step = parent.step,
+ .offset = offset, .length = length};
+ out->step = p->program.input_steps;
+ } else {
+ size_t bound = parent.region.to_end ? PURE_OBJECT_LIMIT - parent.region.offset : parent.region.length;
+ if (offset.value > bound || length.value > bound - offset.value) return reject(p, "range exceeds its source bound");
+ out->region = (PureRegion){.offset = parent.region.offset + offset.value, .length = length.value};
+ require_length(p, out->region.offset + out->region.length);
+ }
+ ++p->program.range_definitions;
+ return true;
+}
+
+static bool effect(Parser *p, Symbol *out) {
+ if (p->effect) return reject(p, "only one storage effect is supported per handler");
+ if (!word(p, "store") || !token(p, '.')) return false;
+ bool splice = p->put && is_word(p, "splice");
+ if (!word(p, p->put ? (splice ? "splice" : "write") : "read") ||
+ !token(p, '(') || !field(p, "request", "key")) return false;
+ if (p->put) {
+ Symbol value;
+ if (!token(p, ',') || !field(p, "request", "revision") || !token(p, ',')) return false;
+ if (splice) {
+ if (!index_value(p, &p->program.splice_offset) || !token(p, ',') ||
+ !index_value(p, &p->program.splice_remove) || !token(p, ',')) return false;
+ if ((!p->program.splice_offset.from_u32le && p->program.splice_offset.value > PURE_OBJECT_LIMIT) ||
+ (!p->program.splice_remove.from_u32le && p->program.splice_remove.value > PURE_OBJECT_LIMIT))
+ return reject(p, "splice exceeds object bound");
+ p->program.splice = true;
+ }
+ if (!byte_reference(p, &value)) return false;
+ p->program.write = value.region;
+ p->program.write_step = value.step;
+ }
+ if (!token(p, ')')) return false;
+ out->kind = RESULT_VALUE;
+ p->effect = true;
+ return true;
+}
+
+static bool handler(Parser *p) {
+ p->count = 0;
+ p->effect = false;
+ if (!token(p, '{')) return false;
+ while (is_word(p, "let")) {
+ if (p->put && p->effect) return reject(p, "all views must precede the storage effect; reply must follow it");
+ if (p->count == SYMBOLS) return reject(p, "handler exceeds 32 definitions");
+ if (!next(p)) return false;
+ if (p->token != NAME || is_word(p, "request") || is_word(p, "store") ||
+ is_word(p, "range") || is_word(p, "view")) return reject(p, "expected a non-reserved definition name");
+ if (find(p, p->name)) return reject(p, "duplicate definition");
+ char name[32];
+ strcpy(name, p->name);
+ Symbol symbol = {0};
+ if (!next(p) || !token(p, '=')) return false;
+ if (is_word(p, "store")) {
+ if (!effect(p, &symbol)) return false;
+ } else {
+ if (!view(p, &symbol)) return false;
+ ++p->program.view_definitions;
+ }
+ if (!token(p, ';')) return false;
+ strcpy(symbol.name, name);
+ p->symbols[p->count++] = symbol;
+ }
+ if (!p->effect) return reject(p, "handler requires its storage effect");
+ if (!word(p, "reply") || !token(p, '(')) return false;
+ Symbol *result = p->token == NAME ? find(p, p->name) : NULL;
+ if (!result || result->kind != RESULT_VALUE) return reject(p, "reply requires this handler's storage result");
+ if (!next(p)) return false;
+ Symbol body = {0};
+ bool has_body = p->token == ',';
+ if (has_body && (!next(p) || !byte_reference(p, &body))) return false;
+ if (!token(p, ')') || !token(p, ';') || !token(p, '}')) return false;
+ if (p->put) {
+ p->program.reply = body.region;
+ p->program.reply_step = body.step;
+ p->program.reply_input = has_body;
+ } else p->program.read = body.region;
+ return true;
+}
+
+bool pure_program_parse(const char *source, size_t length, PureProgram *out,
+ char *error, size_t error_size) {
+ Parser p = {.source = source, .length = length, .line = 1, .token_line = 1,
+ .error = error, .error_size = error_size};
+ if (error_size) error[0] = 0;
+ if (length > PURE_PROGRAM_LIMIT) return reject(&p, "program exceeds 16 KiB");
+ if (!next(&p)) return false;
+ while (is_word(&p, "layout")) if (!layout_definition(&p)) return false;
+ unsigned handlers = 0;
+ while (p.token) {
+ if (!word(&p, "on")) return false;
+ if (!is_word(&p, "get") && !is_word(&p, "put")) return reject(&p, "expected get or put handler");
+ p.put = is_word(&p, "put");
+ unsigned bit = p.put ? 2 : 1;
+ if (handlers & bit) return reject(&p, "duplicate handler");
+ handlers |= bit;
+ if (!next(&p) || !handler(&p)) return false;
+ }
+ if (handlers != 3) return reject(&p, "both get and put handlers are required");
+ *out = p.program; /* Invalid preparation never changes the installed plan. */
+ return true;
+}
+
+bool pure_program_load(const char *path, PureProgram *out, char *error, size_t error_size) {
+ FILE *file = fopen(path, "rb");
+ if (!file) {
+ if (error_size) snprintf(error, error_size, "cannot open program");
+ return false;
+ }
+ char source[PURE_PROGRAM_LIMIT + 1];
+ size_t length = fread(source, 1, sizeof(source), file);
+ bool bad = ferror(file) != 0;
+ if (fclose(file)) bad = true;
+ if (bad) {
+ if (error_size) snprintf(error, error_size, "cannot read program");
+ return false;
+ }
+ return pure_program_parse(source, length, out, error, error_size);
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/program.h b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/program.h
new file mode 100644
index 0000000..c102eb1
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/program.h
@@ -0,0 +1,44 @@
+#ifndef PURE_PROGRAM_H
+#define PURE_PROGRAM_H
+#include "flow.h"
+
+#define PURE_PROGRAM_LIMIT 16384u
+#define PURE_DYNAMIC_LIMIT 8u
+typedef struct {
+ size_t offset, length;
+ bool to_end;
+} PureRegion;
+
+typedef struct { size_t value; bool from_u32le; } PureIndex;
+typedef struct {
+ PureRegion source;
+ size_t source_step; /* 0: source region; otherwise a preceding step + 1. */
+ PureIndex offset, length;
+} PureRangeStep;
+
+/* Prepared connections, not an instruction stream. All view definitions are
+ * checked at preparation; their root-length requirements survive elimination.
+ * Input views are evaluated before the write effect. A read still opens and
+ * validates the object even if its response has no body. */
+typedef struct {
+ PureRegion read, write, reply;
+ size_t read_required, input_required;
+ size_t view_definitions, range_definitions;
+ size_t write_step, reply_step, input_steps;
+ PureRangeStep steps[PURE_DYNAMIC_LIMIT];
+ bool reply_input;
+ bool splice;
+ PureIndex splice_offset, splice_remove;
+} PureProgram;
+
+bool pure_program_parse(const char *source, size_t length, PureProgram *out,
+ char *error, size_t error_size);
+bool pure_program_load(const char *path, PureProgram *out, char *error, size_t error_size);
+bool pure_region_span(PureRegion region, PureSpan source, PureSpan *out);
+/* Validates all input views, including unused dynamic views, before any effect.
+ * Returns borrowed selections; their lifetime remains that of source. */
+bool pure_program_input(const PureProgram *, PureSpan source, PureSpan *write, PureSpan *reply);
+/* Byte positions in the stored value. Bounds against the current version are
+ * checked by the conditional storage effect under the writer lock. */
+bool pure_program_splice(const PureProgram *, PureSpan source, size_t *offset, size_t *remove);
+#endif
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/result.h b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/result.h
new file mode 100644
index 0000000..8abb0f2
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/result.h
@@ -0,0 +1,8 @@
+#ifndef PURE_RESULT_H
+#define PURE_RESULT_H
+typedef enum {
+ PURE_OK, PURE_NOT_FOUND, PURE_CONFLICT, PURE_BUSY, PURE_BUDGET,
+ PURE_LIMIT, PURE_STORE_ERROR, PURE_UNCERTAIN,
+ PURE_INVALID, PURE_DENIED, PURE_CLOSED, PURE_CANCELLED, PURE_ALLOCATION
+} PureResult;
+#endif
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/runtime.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/runtime.c
new file mode 100644
index 0000000..aa4ed05
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/runtime.c
@@ -0,0 +1,273 @@
+#include "runtime.h"
+#include <string.h>
+
+#define NONE SIZE_MAX
+enum { FREE, RECEIVING, READY, RUNNING, DONE };
+
+static PureWork *lookup(PureTicket ticket, bool require_held) {
+ PureRuntime *r = ticket.runtime;
+ if (!r || ticket.slot >= r->capacity || !ticket.generation) return NULL;
+ PureWork *w = &r->work[ticket.slot];
+ if (w->state == FREE || w->generation != ticket.generation ||
+ (require_held && !w->held)) return NULL;
+ return w;
+}
+
+static bool valid_key(const char *key) {
+ if (!key || !*key) return false;
+ size_t n = 0;
+ for (; n <= 64 && key[n]; ++n) {
+ unsigned char c = (unsigned char)key[n];
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') || c == '-' || c == '_')) return false;
+ }
+ return n <= 64;
+}
+
+static void dispose(PureResource *resource) {
+ PureResource old = *resource;
+ *resource = (PureResource){0};
+ if (old.release) old.release(old.allocation, old.allocation_size);
+}
+
+static void payload_release(PureRuntime *r, PureWork *w);
+
+/* Iteratively retire a chain of forwarded values. An arbitrarily long chain
+ * must not turn completion into recursive stack growth. */
+static void retire(PureRuntime *r, PureWork *w) {
+ while (w && !w->held && !w->pins) {
+ PureTicket parent = w->parent;
+ bool owned = w->charged || w->resource.release || parent.runtime;
+ dispose(&w->resource);
+ r->retained -= w->charged;
+ if (owned) ++r->releases;
+ size_t slot = (size_t)(w - r->work);
+ *w = (PureWork){.next = r->free_head};
+ r->free_head = slot;
+ --r->active;
+ if (!parent.runtime) break;
+ r = parent.runtime;
+ w = lookup(parent, false);
+ /* Pins can only be created and removed by the owner-thread core. */
+ if (!w || !w->pins) break;
+ --w->pins;
+ }
+}
+
+static void payload_release(PureRuntime *r, PureWork *w) {
+ PureTicket parent = w->parent;
+ bool owned = w->charged || w->resource.release || parent.runtime;
+ dispose(&w->resource);
+ r->retained -= w->charged;
+ w->charged = 0;
+ w->parent = (PureTicket){0};
+ if (owned) ++r->releases;
+ if (parent.runtime) {
+ PureWork *source = lookup(parent, false);
+ if (source && source->pins) { --source->pins; retire(parent.runtime, source); }
+ }
+}
+
+bool pure_runtime_init(PureRuntime *r, PureWork *work, size_t capacity,
+ const PureProgram *program, PureHost host, size_t budget) {
+ if (!r || !work || !capacity || !program) return false;
+ *r = (PureRuntime){.program = program, .host = host, .work = work,
+ .capacity = capacity, .free_head = 0, .ready_head = NONE, .ready_tail = NONE,
+ .budget = budget, .accepting = true};
+ for (size_t i = 0; i < capacity; ++i)
+ work[i] = (PureWork){.next = i + 1 < capacity ? i + 1 : NONE};
+ return true;
+}
+
+bool pure_runtime_restart(PureRuntime *r, const PureProgram *p, PureHost host, size_t budget) {
+ if (!r || !p || r->running || r->active) return false;
+ r->program = p;
+ r->host = host;
+ r->budget = budget;
+ r->accepting = true;
+ return true;
+}
+
+void pure_runtime_stop(PureRuntime *r) { if (r && !r->running) r->accepting = false; }
+
+static PureResult admission(PureRuntime *r, PureInput input, const char *key,
+ int64_t expected, size_t bytes) {
+ if (!r || r->running || !valid_key(key) ||
+ (input != PURE_INPUT_READ && input != PURE_INPUT_WRITE) ||
+ (input == PURE_INPUT_READ ? bytes != 0 : expected < 0)) return PURE_INVALID;
+ if (!r->accepting) return PURE_CLOSED;
+ if (input == PURE_INPUT_READ ? !r->host.read :
+ (r->program->splice ? !r->host.splice : !r->host.write)) return PURE_DENIED;
+ if (r->free_head == NONE) return PURE_BUSY;
+ if (r->serial == UINT64_MAX) return PURE_LIMIT;
+ if (bytes > r->budget - r->retained) { ++r->budget_rejections; return PURE_BUDGET; }
+ return PURE_OK;
+}
+
+static PureTicket occupy(PureRuntime *r, PureInput input, const char *key,
+ int64_t expected, size_t bytes, PureResource resource) {
+ size_t slot = r->free_head;
+ PureWork *w = &r->work[slot];
+ r->free_head = w->next;
+ *w = (PureWork){.generation = ++r->serial, .next = NONE, .charged = bytes,
+ .state = RECEIVING, .held = true, .input = input, .expected = expected,
+ .resource = resource};
+ memcpy(w->key, key, strlen(key) + 1);
+ ++r->active;
+ ++r->accepted;
+ r->retained += bytes;
+ if (r->active > r->peak_active) r->peak_active = r->active;
+ if (r->retained > r->peak_retained) r->peak_retained = r->retained;
+ return (PureTicket){r, slot, w->generation};
+}
+
+bool pure_runtime_ready(PureTicket ticket) {
+ PureWork *w = lookup(ticket, true);
+ if (!w || ticket.runtime->running || w->state != RECEIVING) return false;
+ PureRuntime *r = ticket.runtime;
+ w->state = READY;
+ if (r->ready_tail == NONE) r->ready_head = ticket.slot;
+ else r->work[r->ready_tail].next = ticket.slot;
+ r->ready_tail = ticket.slot;
+ return true;
+}
+
+PureResult pure_runtime_accept(PureRuntime *r, PureInput input, const char *key,
+ int64_t expected, size_t size, PureTicket *out) {
+ if (!out) return PURE_INVALID;
+ PureResult status = admission(r, input, key, expected, size);
+ if (status != PURE_OK) return status;
+ PureResource resource = {0};
+ if (size) {
+ if (!r->host.allocate) return PURE_ALLOCATION;
+ r->running = true;
+ bool ok = r->host.allocate(r->host.context, size, &resource);
+ r->running = false;
+ if (!ok || !resource.body.data || resource.body.size != size || !resource.release) {
+ dispose(&resource);
+ return PURE_ALLOCATION;
+ }
+ }
+ *out = occupy(r, input, key, expected, size, resource);
+ if (input == PURE_INPUT_READ) pure_runtime_ready(*out);
+ return PURE_OK;
+}
+
+unsigned char *pure_runtime_ingress(PureTicket ticket, size_t *size) {
+ PureWork *w = lookup(ticket, true);
+ if (size) *size = 0;
+ if (!w || ticket.runtime->running || w->state != RECEIVING ||
+ w->input != PURE_INPUT_WRITE || w->parent.runtime) return NULL;
+ if (size) *size = w->resource.body.size;
+ return (unsigned char *)w->resource.body.data;
+}
+
+bool pure_runtime_step(PureRuntime *r) {
+ if (!r || r->running || r->ready_head == NONE) return false;
+ size_t slot = r->ready_head;
+ PureWork *w = &r->work[slot];
+ r->ready_head = w->next;
+ if (r->ready_head == NONE) r->ready_tail = NONE;
+ w->next = NONE;
+ w->state = RUNNING;
+ r->running = true;
+ PureOutcome outcome = {0};
+ if (w->input == PURE_INPUT_WRITE) {
+ PureSpan value;
+ size_t offset = 0, remove = 0;
+ if (!pure_program_input(r->program, w->resource.body, &value, &outcome.body))
+ outcome.status = PURE_LIMIT;
+ else if (r->program->splice) {
+ if (!pure_program_splice(r->program, w->resource.body, &offset, &remove))
+ outcome.status = PURE_LIMIT;
+ else outcome.status = r->host.splice(r->host.context, w->key, w->expected,
+ offset, remove, value, &outcome.revision);
+ }
+ else outcome.status = r->host.write(r->host.context, w->key, w->expected,
+ value, &outcome.revision);
+ if (outcome.status == PURE_OK) ++r->commits;
+ else if (outcome.status == PURE_CONFLICT) ++r->conflicts;
+ } else {
+ outcome.status = r->host.read(r->host.context, w->key, r->program->read,
+ r->program->read_required, r->budget - r->retained, &w->resource, &outcome.revision);
+ if (outcome.status == PURE_OK) {
+ if (w->resource.body.size > r->budget - r->retained) outcome.status = PURE_BUDGET;
+ else if (w->resource.body.size && (!w->resource.body.data || !w->resource.release))
+ outcome.status = PURE_STORE_ERROR;
+ else {
+ w->charged = w->resource.body.size;
+ r->retained += w->charged;
+ if (r->retained > r->peak_retained) r->peak_retained = r->retained;
+ outcome.body = w->resource.body;
+ ++r->gets;
+ }
+ }
+ if (outcome.status == PURE_BUDGET) ++r->budget_rejections;
+ }
+ if (outcome.status != PURE_OK || !outcome.body.size) {
+ outcome.body = (PureSpan){0};
+ payload_release(r, w);
+ }
+ r->borrowed_output_bytes += outcome.body.size;
+ w->outcome = outcome;
+ w->state = DONE;
+ r->running = false;
+ return true;
+}
+
+bool pure_runtime_result(PureTicket ticket, PureOutcome *out) {
+ PureWork *w = lookup(ticket, true);
+ if (!out || !w || ticket.runtime->running || w->state != DONE) return false;
+ *out = w->outcome;
+ return true;
+}
+
+PureResult pure_runtime_forward(PureTicket source, PureRuntime *r,
+ const char *key, int64_t expected, PureTicket *out) {
+ PureWork *parent = lookup(source, true);
+ if (!out || !parent || source.runtime->running || parent->state != DONE ||
+ parent->outcome.status != PURE_OK) return PURE_INVALID;
+ PureResult status = admission(r, PURE_INPUT_WRITE, key, expected, parent->outcome.body.size);
+ if (status != PURE_OK) return status;
+ if (parent->pins == SIZE_MAX) return PURE_LIMIT;
+ PureTicket ticket = occupy(r, PURE_INPUT_WRITE, key, expected, parent->outcome.body.size,
+ (PureResource){.body = parent->outcome.body});
+ ++parent->pins;
+ r->work[ticket.slot].parent = source;
+ pure_runtime_ready(ticket);
+ *out = ticket;
+ return PURE_OK;
+}
+
+static void unlink_ready(PureRuntime *r, size_t slot) {
+ size_t previous = NONE;
+ for (size_t at = r->ready_head; at != NONE; at = r->work[at].next) {
+ if (at == slot) {
+ if (previous == NONE) r->ready_head = r->work[at].next;
+ else r->work[previous].next = r->work[at].next;
+ if (r->ready_tail == at) r->ready_tail = previous;
+ r->work[at].next = NONE;
+ return;
+ }
+ previous = at;
+ }
+}
+
+bool pure_runtime_cancel(PureTicket ticket) {
+ PureWork *w = lookup(ticket, true);
+ if (!w || ticket.runtime->running || (w->state != RECEIVING && w->state != READY)) return false;
+ if (w->state == READY) unlink_ready(ticket.runtime, ticket.slot);
+ payload_release(ticket.runtime, w);
+ w->outcome = (PureOutcome){.status = PURE_CANCELLED};
+ w->state = DONE;
+ return true;
+}
+
+bool pure_runtime_release(PureTicket ticket) {
+ PureWork *w = lookup(ticket, true);
+ if (!w || ticket.runtime->running) return false;
+ if (w->state == READY) unlink_ready(ticket.runtime, ticket.slot);
+ w->held = false;
+ retire(ticket.runtime, w);
+ return true;
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/runtime.h b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/runtime.h
new file mode 100644
index 0000000..1bff082
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/runtime.h
@@ -0,0 +1,88 @@
+#ifndef PURE_RUNTIME_H
+#define PURE_RUNTIME_H
+#include "program.h"
+#include "result.h"
+#include <stdint.h>
+
+/* First execution profile: authored selection -> read/conditional write ->
+ * reply. No socket, file descriptor, allocator, parser or OS type in the core.
+ * All control calls and connected domains share one owner thread. Host effects
+ * are synchronous in this profile and must not reenter the runtime. */
+typedef struct PureRuntime PureRuntime;
+typedef struct PureWork PureWork;
+typedef struct { PureRuntime *runtime; size_t slot; uint64_t generation; } PureTicket;
+typedef enum { PURE_INPUT_READ, PURE_INPUT_WRITE } PureInput;
+
+/* The host owns this resource until it successfully returns it to the core.
+ * release must end all access and free/unmap allocation exactly once. */
+typedef struct {
+ PureSpan body;
+ void *allocation;
+ size_t allocation_size;
+ void (*release)(void *allocation, size_t size);
+} PureResource;
+typedef struct {
+ void *context;
+ bool (*allocate)(void *, size_t, PureResource *);
+ PureResult (*read)(void *, const char *, PureRegion, size_t minimum,
+ size_t available, PureResource *, int64_t *revision);
+ PureResult (*write)(void *, const char *, int64_t expected,
+ PureSpan, int64_t *revision);
+ PureResult (*splice)(void *, const char *, int64_t expected, size_t offset,
+ size_t remove, PureSpan insert, int64_t *revision);
+} PureHost;
+typedef struct { PureResult status; int64_t revision; PureSpan body; } PureOutcome;
+
+/* Caller-provided work slots: no background thread or per-domain heap. These
+ * records are implementation storage, not an ABI or a wire representation. */
+struct PureWork {
+ uint64_t generation;
+ size_t next, charged, pins;
+ unsigned state;
+ bool held;
+ PureInput input;
+ int64_t expected;
+ char key[65];
+ PureResource resource;
+ PureTicket parent;
+ PureOutcome outcome;
+};
+struct PureRuntime {
+ const PureProgram *program;
+ PureHost host;
+ PureWork *work;
+ size_t capacity, free_head, ready_head, ready_tail;
+ size_t budget, retained, peak_retained, active, peak_active;
+ uint64_t serial, accepted, commits, gets, conflicts, budget_rejections;
+ uint64_t releases, borrowed_output_bytes;
+ bool accepting, running;
+};
+
+/* Initialize fresh storage once. Use restart, not init, to reuse a domain;
+ * the monotonic ticket sequence then survives restart. program is immutable
+ * and remains alive until all work has drained. */
+bool pure_runtime_init(PureRuntime *, PureWork *, size_t capacity,
+ const PureProgram *, PureHost, size_t budget);
+bool pure_runtime_restart(PureRuntime *, const PureProgram *, PureHost, size_t budget);
+void pure_runtime_stop(PureRuntime *); /* stop admission, allow queued work to drain */
+
+/* READ queues immediately. WRITE reserves its slot, budget and host allocation
+ * before returning. Fill ingress then publish once with ready. A partial input
+ * released without ready never executes. On error, out is unchanged. */
+PureResult pure_runtime_accept(PureRuntime *, PureInput, const char *key,
+ int64_t expected, size_t input_size, PureTicket *out);
+unsigned char *pure_runtime_ingress(PureTicket, size_t *size);
+bool pure_runtime_ready(PureTicket);
+bool pure_runtime_step(PureRuntime *); /* execute at most one ready job */
+bool pure_runtime_result(PureTicket, PureOutcome *out);
+
+/* Pin a completed reply and queue it as another domain's WRITE input, with no
+ * allocation, serialization or payload copy. Source may be released as soon
+ * as this succeeds; the core retains its backing until the consumer ends.
+ * Each domain charges its own retained input bytes as admission credits.
+ * Credits across domains are NOT distinct physical memory and must not be summed. */
+PureResult pure_runtime_forward(PureTicket source, PureRuntime *destination,
+ const char *key, int64_t expected, PureTicket *out);
+bool pure_runtime_cancel(PureTicket); /* only before execution; keeps a completion */
+bool pure_runtime_release(PureTicket); /* invalidates caller's ticket, preserves pins */
+#endif
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/server.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/server.c
new file mode 100644
index 0000000..50480c0
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/server.c
@@ -0,0 +1,372 @@
+#define _POSIX_C_SOURCE 200809L
+#include "store.h"
+#include "program.h"
+#include "store-port.h"
+#include <arpa/inet.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <unistd.h>
+
+enum { SLOTS = 8, HEADER_LIMIT = 4096, CHUNK = 65536 };
+typedef enum { READING_HEADER, READING_BODY, WRITING } Phase;
+typedef struct Server Server;
+typedef struct {
+ int fd;
+ Phase phase;
+ uint64_t deadline;
+ char request[HEADER_LIMIT + 1], response[512], key[65];
+ size_t header_size, body_size, received;
+ unsigned char *body;
+ bool put;
+ int64_t expected;
+ PureTicket ticket;
+ PureTransfer transfer;
+ Server *server;
+} Connection;
+struct Server {
+ const char *path;
+ PureProgram program;
+ PureRuntime runtime;
+ PureWork work[SLOTS];
+ size_t budget, active, peak_active;
+ uint64_t accepted, expired, prefix_copy_bytes;
+ uint64_t timeout_ms;
+ int send_buffer;
+ Connection connections[SLOTS];
+};
+static volatile sig_atomic_t stopping;
+static void stop_server(int sig) { (void)sig; stopping = 1; }
+
+static uint64_t now_ms(void) {
+ struct timespec t;
+ if (clock_gettime(CLOCK_MONOTONIC, &t)) abort();
+ return (uint64_t)t.tv_sec * 1000 + (uint64_t)t.tv_nsec / 1000000;
+}
+
+static bool number(const char *text, uint64_t maximum, uint64_t *value) {
+ if (!*text) return false;
+ uint64_t n = 0;
+ for (; *text; ++text) {
+ if (*text < '0' || *text > '9') return false;
+ unsigned digit = (unsigned)(*text - '0');
+ if (digit > maximum || n > (maximum - digit) / 10) return false;
+ n = n * 10 + digit;
+ }
+ *value = n;
+ return true;
+}
+
+static void release_payload(void *owner) {
+ Connection *c = owner;
+ if (c->ticket.runtime) {
+ bool released = pure_runtime_release(c->ticket);
+ assert(released);
+ (void)released;
+ }
+ c->ticket = (PureTicket){0};
+ c->body = NULL;
+}
+
+static void close_connection(Connection *c) {
+ if (c->fd < 0) return;
+ if (c->transfer.active) pure_transfer_abort(&c->transfer);
+ else release_payload(c);
+ close(c->fd);
+ --c->server->active;
+ *c = (Connection){.fd = -1};
+}
+
+static void respond(Connection *c, int status, const char *reason, const char *error,
+ int64_t revision, PureSpan body) {
+ char tag[80] = "";
+ if (revision > 0) snprintf(tag, sizeof(tag), "ETag: \"%" PRId64 "\"\r\n", revision);
+ int length = snprintf(c->response, sizeof(c->response),
+ "HTTP/1.1 %d %s\r\nContent-Length: %zu\r\nConnection: close\r\n"
+ "Content-Type: application/octet-stream\r\nCache-Control: no-store\r\n"
+ "X-Pure-Error: %s\r\n%s\r\n", status, reason, body.size, error, tag);
+ assert(length > 0 && (size_t)length < sizeof(c->response));
+ c->phase = WRITING;
+ pure_transfer_init(&c->transfer,
+ (PureSpan){(const unsigned char *)c->response, (size_t)length}, body, c, release_payload);
+}
+
+static void fail(Connection *c, int status, const char *reason, const char *error) {
+ /* No outstanding backend access on the owner thread at this point. */
+ release_payload(c);
+ respond(c, status, reason, error, 0, (PureSpan){0});
+}
+
+static void answer(Connection *c, PureOutcome result) {
+ switch (result.status) {
+ case PURE_OK: respond(c, 200, "OK", "none", result.revision, result.body); break;
+ case PURE_NOT_FOUND: fail(c, 404, "Not Found", "not_found"); break;
+ case PURE_CONFLICT:
+ respond(c, 412, "Precondition Failed", "conflict", result.revision, (PureSpan){0}); break;
+ case PURE_BUSY: fail(c, 503, "Service Unavailable", "store_busy"); break;
+ case PURE_BUDGET: fail(c, 503, "Service Unavailable", "payload_budget"); break;
+ case PURE_ALLOCATION: fail(c, 503, "Service Unavailable", "allocation"); break;
+ case PURE_CLOSED: fail(c, 503, "Service Unavailable", "stopped"); break;
+ case PURE_DENIED: fail(c, 403, "Forbidden", "denied"); break;
+ case PURE_LIMIT: fail(c, 413, "Content Too Large", "limit"); break;
+ case PURE_UNCERTAIN: fail(c, 500, "Internal Server Error", "durability_unknown"); break;
+ default: fail(c, 500, "Internal Server Error", "storage"); break;
+ }
+}
+
+static void run_request(Connection *c) {
+ if (c->put && !pure_runtime_ready(c->ticket)) abort();
+ PureOutcome result;
+ while (!pure_runtime_result(c->ticket, &result))
+ if (!pure_runtime_step(&c->server->runtime)) abort();
+ c->body = NULL; /* Core now owns input until all consumers release it. */
+ answer(c, result);
+}
+
+/* Deliberately bounded HTTP/1.1 subset: one GET/PUT, Content-Length, close.
+ * No transfer coding, pipelining, trailers, Expect, URL decoding, or proxying. */
+static bool parse_header(Connection *c, size_t end) {
+ for (size_t i = 0; i < end; ++i) {
+ unsigned char b = (unsigned char)c->request[i];
+ if ((b < 32 && b != '\r' && b != '\n' && b != '\t') || b == 127) return false;
+ }
+ char *line = c->request, *next = strstr(line, "\r\n");
+ if (!next) return false;
+ *next = 0;
+ char *path = strchr(line, ' ');
+ if (!path) return false;
+ *path++ = 0;
+ if (strcmp(line, "PUT") == 0) c->put = true;
+ else if (strcmp(line, "GET") != 0) return false;
+ char *version = strchr(path, ' ');
+ if (!version) return false;
+ *version++ = 0;
+ if (strcmp(version, "HTTP/1.1") || strncmp(path, "/objects/", 9)) return false;
+ const char *key = path + 9;
+ size_t key_size = strlen(key);
+ if (!key_size || key_size > 64) return false;
+ for (size_t i = 0; i < key_size; ++i) {
+ char b = key[i];
+ if (!((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') ||
+ (b >= '0' && b <= '9') || b == '-' || b == '_')) return false;
+ }
+ memcpy(c->key, key, key_size + 1);
+ bool length_seen = false, condition_seen = false, host_seen = false;
+ line = next + 2;
+ while (*line != '\r') {
+ next = strstr(line, "\r\n");
+ if (!next) return false;
+ *next = 0;
+ char *value = strchr(line, ':');
+ if (!value || value == line) return false;
+ *value++ = 0;
+ for (char *p = line; *p; ++p)
+ if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') ||
+ (*p >= '0' && *p <= '9') || *p == '-')) return false;
+ while (*value == ' ' || *value == '\t') ++value;
+ char *tail = value + strlen(value);
+ while (tail > value && (tail[-1] == ' ' || tail[-1] == '\t')) *--tail = 0;
+ if (strchr(value, '\r') || strchr(value, '\n')) return false;
+ uint64_t n;
+ if (!strcasecmp(line, "Content-Length")) {
+ if (length_seen || !number(value, SIZE_MAX, &n)) return false;
+ length_seen = true;
+ c->body_size = (size_t)n;
+ } else if (!strcasecmp(line, "Host")) {
+ if (host_seen || !*value) return false;
+ host_seen = true;
+ } else if (!strcasecmp(line, "If-Match")) {
+ if (condition_seen || tail - value < 3 || *value != '"' || tail[-1] != '"') return false;
+ tail[-1] = 0;
+ if (!number(value + 1, INT64_MAX, &n) || !n) return false;
+ c->expected = (int64_t)n;
+ condition_seen = true;
+ } else if (!strcasecmp(line, "If-None-Match")) {
+ if (condition_seen || strcmp(value, "*")) return false;
+ c->expected = 0;
+ condition_seen = true;
+ } else if (!strcasecmp(line, "Transfer-Encoding") || !strcasecmp(line, "Expect")) return false;
+ line = next + 2;
+ }
+ return host_seen && (c->put ? length_seen && condition_seen : !condition_seen && c->body_size == 0);
+}
+
+static void read_connection(Connection *c) {
+ if (c->phase == READING_HEADER) {
+ ssize_t n = recv(c->fd, c->request + c->header_size, HEADER_LIMIT - c->header_size, 0);
+ if (n < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) close_connection(c); return; }
+ if (!n) { close_connection(c); return; }
+ c->header_size += (size_t)n;
+ c->request[c->header_size] = 0;
+ /* Scan by byte count, so embedded NUL cannot hide a terminator. */
+ size_t end = 0;
+ for (size_t i = 3; i < c->header_size; ++i)
+ if (!memcmp(c->request + i - 3, "\r\n\r\n", 4)) { end = i + 1; break; }
+ if (!end) {
+ if (c->header_size == HEADER_LIMIT) fail(c, 431, "Request Header Fields Too Large", "headers");
+ return;
+ }
+ size_t prefix = c->header_size - end;
+ if (!parse_header(c, end)) { fail(c, 400, "Bad Request", "request"); return; }
+ if (c->body_size > PURE_OBJECT_LIMIT) { fail(c, 413, "Content Too Large", "limit"); return; }
+ if (prefix > c->body_size) { fail(c, 400, "Bad Request", "extra_body"); return; }
+ PureResult admitted = pure_runtime_accept(&c->server->runtime,
+ c->put ? PURE_INPUT_WRITE : PURE_INPUT_READ, c->key, c->expected, c->body_size, &c->ticket);
+ if (admitted != PURE_OK) { answer(c, (PureOutcome){.status = admitted}); return; }
+ if (!c->put) { run_request(c); return; }
+ c->body = pure_runtime_ingress(c->ticket, NULL);
+ if (prefix) memcpy(c->body, c->request + end, prefix);
+ c->server->prefix_copy_bytes += prefix;
+ c->received = prefix;
+ c->phase = READING_BODY;
+ if (c->received == c->body_size) run_request(c);
+ } else {
+ size_t remaining = c->body_size - c->received;
+ ssize_t n = recv(c->fd, c->body + c->received, remaining < CHUNK ? remaining : CHUNK, 0);
+ if (n < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) close_connection(c); return; }
+ if (!n) { close_connection(c); return; }
+ c->received += (size_t)n;
+ if (c->received == c->body_size) run_request(c);
+ }
+}
+
+static void write_connection(Connection *c) {
+ PureSpan span = pure_transfer_next(&c->transfer, CHUNK);
+ ssize_t n = send(c->fd, span.data, span.size, 0);
+ if (n < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) close_connection(c); return; }
+ if (!n) { close_connection(c); return; }
+ if (!pure_transfer_consume(&c->transfer, (size_t)n)) abort();
+ if (!c->transfer.active) close_connection(c);
+}
+
+static bool nonblocking(int fd) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ return flags >= 0 && fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0;
+}
+
+int main(int argc, char **argv) {
+ Server server = {.budget = 4u * 1024u * 1024u, .timeout_ms = 10000};
+ unsigned port = 8767;
+ const char *program_path = NULL;
+ bool explain = argc == 3 && !strcmp(argv[1], "--check-program");
+ char program_error[160];
+ if (explain) program_path = argv[2];
+ for (int i = 1; !explain && i < argc; i += 2) {
+ if (i + 1 == argc) goto usage;
+ uint64_t value;
+ if (!strcmp(argv[i], "--store")) server.path = argv[i + 1];
+ else if (!strcmp(argv[i], "--program")) program_path = argv[i + 1];
+ else if (!strcmp(argv[i], "--port") && number(argv[i + 1], 65535, &value)) port = (unsigned)value;
+ else if (!strcmp(argv[i], "--budget") && number(argv[i + 1], SIZE_MAX, &value) && value) server.budget = (size_t)value;
+ else if (!strcmp(argv[i], "--timeout-ms") && number(argv[i + 1], 3600000, &value) && value) server.timeout_ms = value;
+ else if (!strcmp(argv[i], "--send-buffer") && number(argv[i + 1], INT32_MAX, &value)) server.send_buffer = (int)value;
+ else goto usage;
+ }
+ if (!program_path || (!explain && !server.path)) goto usage;
+ if (!pure_program_load(program_path, &server.program, program_error, sizeof(program_error))) {
+ fprintf(stderr, "Program: %s\n", program_error); return 2;
+ }
+ if (explain) {
+ PureProgram *p = &server.program;
+ printf("{\"read\":{\"to_end\":%s,\"offset\":%zu,\"length\":%zu,\"minimum_source_bytes\":%zu},"
+ "\"write\":{\"to_end\":%s,\"offset\":%zu,\"length\":%zu,\"minimum_source_bytes\":%zu},"
+ "\"reply_input\":%s,\"view_definitions\":%zu,\"range_definitions\":%zu,"
+ "\"runtime_view_steps\":%zu,\"write_step\":%zu,\"reply_step\":%zu,\"prepared_program_bytes\":%zu,\"steps\":[",
+ p->read.to_end ? "true" : "false", p->read.offset, p->read.length, p->read_required,
+ p->write.to_end ? "true" : "false", p->write.offset, p->write.length, p->input_required,
+ p->reply_input ? "true" : "false", p->view_definitions, p->range_definitions,
+ p->input_steps, p->write_step, p->reply_step, sizeof(*p));
+ for (size_t i = 0; i < p->input_steps; ++i) {
+ const PureRangeStep *step = &p->steps[i];
+ printf("%s{\"source_step\":%zu,\"source\":{\"offset\":%zu,\"length\":%zu,\"to_end\":%s},"
+ "\"offset\":{\"value\":%zu,\"from_u32le\":%s},\"length\":{\"value\":%zu,\"from_u32le\":%s}}",
+ i ? "," : "", step->source_step, step->source.offset, step->source.length,
+ step->source.to_end ? "true" : "false", step->offset.value, step->offset.from_u32le ? "true" : "false",
+ step->length.value, step->length.from_u32le ? "true" : "false");
+ }
+ printf("],\"write_effect\":\"%s\",\"splice_offset\":{\"value\":%zu,\"from_u32le\":%s},"
+ "\"splice_remove\":{\"value\":%zu,\"from_u32le\":%s}}\n",
+ p->splice ? "splice" : "write", p->splice_offset.value,
+ p->splice_offset.from_u32le ? "true" : "false", p->splice_remove.value,
+ p->splice_remove.from_u32le ? "true" : "false");
+ return 0;
+ }
+ if (pure_store_init(server.path) != PURE_OK) { fputs("Cannot initialize byte store directory\n", stderr); return 1; }
+ if (!pure_runtime_init(&server.runtime, server.work, SLOTS, &server.program,
+ pure_store_host(server.path), server.budget)) return 1;
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGINT, stop_server);
+ signal(SIGTERM, stop_server);
+ int listener = socket(AF_INET, SOCK_STREAM, 0);
+ if (listener < 0) { perror("socket"); return 1; }
+ int one = 1;
+ setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+ struct sockaddr_in address = {.sin_family = AF_INET, .sin_port = htons((uint16_t)port),
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK)};
+ if (bind(listener, (struct sockaddr *)&address, sizeof(address)) || listen(listener, SLOTS) || !nonblocking(listener)) {
+ perror("listen"); close(listener); return 1;
+ }
+ socklen_t address_size = sizeof(address);
+ if (getsockname(listener, (struct sockaddr *)&address, &address_size)) { close(listener); return 1; }
+ for (size_t i = 0; i < SLOTS; ++i) server.connections[i].fd = -1;
+ printf("{\"port\":%u,\"storage\":\"immutable-byte-extents-v1\"}\n", ntohs(address.sin_port));
+ fflush(stdout);
+ while (!stopping) {
+ struct pollfd polls[SLOTS + 1] = {{.fd = server.active < SLOTS ? listener : -1, .events = POLLIN}};
+ for (size_t i = 0; i < SLOTS; ++i) {
+ Connection *c = &server.connections[i];
+ polls[i + 1] = (struct pollfd){.fd = c->fd, .events = c->phase == WRITING ? POLLOUT : POLLIN};
+ }
+ int ready = poll(polls, SLOTS + 1, 50);
+ if (ready < 0 && errno != EINTR) { perror("poll"); stopping = 1; }
+ uint64_t now = now_ms();
+ for (size_t i = 0; i < SLOTS; ++i) {
+ Connection *c = &server.connections[i];
+ if (c->fd < 0) continue;
+ if (now >= c->deadline) { ++server.expired; close_connection(c); continue; }
+ short events = polls[i + 1].revents;
+ if (events & (POLLERR | POLLNVAL)) { close_connection(c); continue; }
+ if (events & (POLLIN | POLLOUT | POLLHUP)) {
+ if (c->phase == WRITING) write_connection(c); else read_connection(c);
+ }
+ }
+ if (!stopping && (polls[0].revents & POLLIN)) {
+ int fd = accept(listener, NULL, NULL);
+ if (fd < 0) continue;
+ if (!nonblocking(fd)) { close(fd); continue; }
+ if (server.send_buffer) setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &server.send_buffer, sizeof(server.send_buffer));
+ for (size_t i = 0; i < SLOTS; ++i) if (server.connections[i].fd < 0) {
+ server.connections[i] = (Connection){.fd = fd, .server = &server, .deadline = now_ms() + server.timeout_ms};
+ ++server.active;
+ ++server.accepted;
+ if (server.active > server.peak_active) server.peak_active = server.active;
+ break;
+ }
+ }
+ }
+ close(listener);
+ pure_runtime_stop(&server.runtime);
+ for (size_t i = 0; i < SLOTS; ++i) close_connection(&server.connections[i]);
+ fprintf(stderr, "{\"active\":%zu,\"retained_payload_bytes\":%zu,\"peak_retained_payload_bytes\":%zu,"
+ "\"payload_budget\":%zu,\"peak_connections\":%zu,\"accepted\":%" PRIu64 ",\"commits\":%" PRIu64 ","
+ "\"gets\":%" PRIu64 ",\"conflicts\":%" PRIu64 ",\"budget_rejections\":%" PRIu64 ","
+ "\"expired\":%" PRIu64 ",\"releases\":%" PRIu64 ",\"ingress_prefix_copy_bytes\":%" PRIu64 ","
+ "\"borrowed_output_bytes\":%" PRIu64 ",\"server_structure_bytes\":%zu}\n",
+ server.active, server.runtime.retained, server.runtime.peak_retained, server.budget, server.peak_active,
+ server.accepted, server.runtime.commits, server.runtime.gets, server.runtime.conflicts, server.runtime.budget_rejections,
+ server.expired, server.runtime.releases, server.prefix_copy_bytes, server.runtime.borrowed_output_bytes, sizeof(server));
+ return 0;
+usage:
+ fputs("pure-connections --program FILE --store DIRECTORY [--port 8767] [--budget BYTES] [--timeout-ms 10000] [--send-buffer BYTES]\n"
+ "pure-connections --check-program FILE\n", stderr);
+ return 2;
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store-port.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store-port.c
new file mode 100644
index 0000000..9860308
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store-port.c
@@ -0,0 +1,44 @@
+#include "store-port.h"
+#include "store.h"
+#include <stdlib.h>
+#include <sys/mman.h>
+
+static void free_memory(void *data, size_t size) { (void)size; free(data); }
+static void unmap_memory(void *data, size_t size) { if (size) munmap(data, size); }
+
+static bool allocate(void *context, size_t size, PureResource *out) {
+ (void)context;
+ void *data = malloc(size);
+ if (!data) return false;
+ *out = (PureResource){.body = {data, size}, .allocation = data,
+ .allocation_size = size, .release = free_memory};
+ return true;
+}
+
+static PureResult read_value(void *context, const char *key, PureRegion region,
+ size_t minimum, size_t available, PureResource *out, int64_t *revision) {
+ PureStoredView view = {0};
+ PureResult result = pure_store_select(context, key, region.offset, region.length,
+ region.to_end, minimum, available, &view);
+ if (result == PURE_OK) {
+ *out = (PureResource){.body = view.body, .allocation = view.mapping,
+ .allocation_size = view.mapped_size, .release = view.mapped_size ? unmap_memory : NULL};
+ *revision = view.revision;
+ }
+ return result;
+}
+
+static PureResult write_value(void *context, const char *key, int64_t expected,
+ PureSpan body, int64_t *revision) {
+ return pure_store_put(context, key, expected, body, revision);
+}
+
+static PureResult splice_value(void *context, const char *key, int64_t expected,
+ size_t offset, size_t remove, PureSpan insert, int64_t *revision) {
+ return pure_store_splice(context, key, expected, offset, remove, insert, revision);
+}
+
+PureHost pure_store_host(const char *path) {
+ return (PureHost){.context = (void *)path, .allocate = allocate,
+ .read = read_value, .write = write_value, .splice = splice_value};
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store-port.h b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store-port.h
new file mode 100644
index 0000000..4c0d49d
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store-port.h
@@ -0,0 +1,6 @@
+#ifndef PURE_STORE_PORT_H
+#define PURE_STORE_PORT_H
+#include "runtime.h"
+/* The path remains alive for the domain's complete lifetime, including pins. */
+PureHost pure_store_host(const char *path);
+#endif
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store.c
new file mode 100644
index 0000000..4c8bdc4
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store.c
@@ -0,0 +1,258 @@
+#define _POSIX_C_SOURCE 200809L
+#include "store.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/* Immutable extent envelope: marker, little-endian u64 revision and payload
+ * length, then unchanged caller bytes. Single-threaded control API; cooperating
+ * processes serialize publication using .writer.lock. */
+enum { HEADER_BYTES = 24 };
+static const unsigned char magic[8] = {'P','U','R','E','B','0','0','1'};
+static uint64_t temporary_sequence;
+
+static bool fault(PureStoreStage stage) {
+#ifdef PURE_STORE_TEST
+ if (pure_store_test_fault(stage)) { errno = EIO; return true; }
+#else
+ (void)stage;
+#endif
+ return false;
+}
+
+static bool file_name(const char *key, char name[72]) {
+ if (!key) return false;
+ size_t length = strlen(key);
+ if (!length || length > 64) return false;
+ for (size_t i = 0; i < length; ++i) {
+ char b = key[i];
+ if (!((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') ||
+ (b >= '0' && b <= '9') || b == '-' || b == '_')) return false;
+ }
+ snprintf(name, 72, "obj-%s", key);
+ return true;
+}
+
+static uint64_t decode64(const unsigned char *bytes) {
+ uint64_t value = 0;
+ for (unsigned i = 0; i < 8; ++i) value |= (uint64_t)bytes[i] << (8 * i);
+ return value;
+}
+
+static void encode64(unsigned char *bytes, uint64_t value) {
+ for (unsigned i = 0; i < 8; ++i) bytes[i] = (unsigned char)(value >> (8 * i));
+}
+
+static bool sync_fd(int fd) {
+ int rc;
+ do { rc = fsync(fd); } while (rc && errno == EINTR);
+ return rc == 0;
+}
+
+static bool write_bytes(int fd, const unsigned char *bytes, size_t length) {
+ while (length) {
+ ssize_t n = write(fd, bytes, length);
+ if (n < 0 && errno == EINTR) continue;
+ if (n <= 0) return false;
+ bytes += (size_t)n;
+ length -= (size_t)n;
+ }
+ return true;
+}
+
+static bool read_header(int fd, int64_t *revision, size_t *length) {
+ struct stat info;
+ if (fstat(fd, &info) || !S_ISREG(info.st_mode)) return false;
+ unsigned char header[HEADER_BYTES];
+ size_t used = 0;
+ while (used < sizeof(header)) {
+ ssize_t n = pread(fd, header + used, sizeof(header) - used, (off_t)used);
+ if (n < 0 && errno == EINTR) continue;
+ if (n <= 0) return false;
+ used += (size_t)n;
+ }
+ uint64_t version = decode64(header + 8), size = decode64(header + 16);
+ if (memcmp(header, magic, sizeof(magic)) || !version || version > INT64_MAX ||
+ size > PURE_OBJECT_LIMIT || info.st_size != (off_t)(HEADER_BYTES + size)) return false;
+ *revision = (int64_t)version;
+ *length = (size_t)size;
+ return true;
+}
+
+PureResult pure_store_init(const char *path) {
+ if (!path || !*path) return PURE_STORE_ERROR;
+ bool created = mkdir(path, 0700) == 0;
+ if (!created && errno != EEXIST) return PURE_STORE_ERROR;
+ int directory = open(path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+ if (directory < 0) return PURE_STORE_ERROR; /* Never reinterpret an old DB file. */
+ int lock = openat(directory, ".writer.lock", O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC, 0600);
+ struct stat info;
+ bool ok = lock >= 0 && fstat(lock, &info) == 0 && S_ISREG(info.st_mode) && sync_fd(lock);
+ if (lock >= 0) close(lock);
+ if (ok) ok = sync_fd(directory);
+ close(directory);
+ if (!ok) return PURE_STORE_ERROR;
+ if (created) {
+ char *parent = strdup(path);
+ if (!parent) return PURE_STORE_ERROR;
+ size_t length = strlen(parent);
+ while (length > 1 && parent[length - 1] == '/') parent[--length] = 0;
+ char *slash = strrchr(parent, '/');
+ if (!slash) strcpy(parent, ".");
+ else if (slash == parent) parent[1] = 0;
+ else *slash = 0;
+ int fd = open(parent, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+ free(parent);
+ ok = fd >= 0 && sync_fd(fd);
+ if (fd >= 0) close(fd);
+ }
+ return ok ? PURE_OK : PURE_STORE_ERROR;
+}
+
+void pure_store_release(PureStoredView *view) {
+ if (view->mapped_size) munmap(view->mapping, view->mapped_size);
+ *view = (PureStoredView){0};
+}
+
+PureResult pure_store_select(const char *path, const char *key, size_t offset,
+ size_t length, bool whole, size_t minimum,
+ size_t available, PureStoredView *out) {
+ *out = (PureStoredView){0};
+ char name[72];
+ if (!file_name(key, name)) return PURE_STORE_ERROR;
+ int directory = open(path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+ if (directory < 0) return PURE_STORE_ERROR;
+ int fd = openat(directory, name, O_RDONLY | O_NOFOLLOW | O_NONBLOCK | O_CLOEXEC);
+ int cause = errno;
+ close(directory);
+ if (fd < 0) return cause == ENOENT ? PURE_NOT_FOUND : PURE_STORE_ERROR;
+ int64_t revision;
+ size_t size;
+ PureResult result = PURE_STORE_ERROR;
+ if (!read_header(fd, &revision, &size)) goto finish;
+ if (size < minimum) { result = PURE_LIMIT; goto finish; }
+ if (offset > size) { result = PURE_LIMIT; goto finish; }
+ if (whole) length = size - offset;
+ if (offset > size || length > size - offset) { result = PURE_LIMIT; goto finish; }
+ if (length > available) { result = PURE_BUDGET; goto finish; }
+ if (length) {
+ long page = sysconf(_SC_PAGESIZE);
+ if (page <= 0) goto finish;
+ size_t start = HEADER_BYTES + offset;
+ size_t aligned = start - start % (size_t)page;
+ size_t prefix = start - aligned;
+ size_t mapped_size = prefix + length;
+ void *mapping = mmap(NULL, mapped_size, PROT_READ, MAP_PRIVATE, fd, (off_t)aligned);
+ if (mapping == MAP_FAILED) goto finish;
+ out->mapping = mapping;
+ out->mapped_size = mapped_size;
+ out->body = (PureSpan){(const unsigned char *)mapping + prefix, length};
+ }
+ out->revision = revision;
+ out->object_size = size;
+ result = PURE_OK;
+finish:
+ close(fd); /* The mapping retains this immutable file version after rename. */
+ return result;
+}
+
+PureResult pure_store_get(const char *path, const char *key, size_t available, PureStoredView *out) {
+ return pure_store_select(path, key, 0, 0, true, 0, available, out);
+}
+
+PureResult pure_store_get_range(const char *path, const char *key, size_t offset,
+ size_t length, size_t available, PureStoredView *out) {
+ return pure_store_select(path, key, offset, length, false, 0, available, out);
+}
+
+static bool copy_extent(int source, int destination, size_t offset, size_t length) {
+ unsigned char scratch[4096];
+ while (length) {
+ size_t wanted = length < sizeof(scratch) ? length : sizeof(scratch);
+ ssize_t n = pread(source, scratch, wanted, (off_t)(HEADER_BYTES + offset));
+ if (n < 0 && errno == EINTR) continue;
+ if (n <= 0 || !write_bytes(destination, scratch, (size_t)n)) return false;
+ offset += (size_t)n;
+ length -= (size_t)n;
+ }
+ return true;
+}
+
+static PureResult mutate(const char *path, const char *key, int64_t expected,
+ PureSpan body, bool splice, size_t offset, size_t remove, int64_t *revision) {
+ *revision = 0;
+ char name[72], temporary[96] = "";
+ if (!file_name(key, name) || (body.size && !body.data)) return PURE_STORE_ERROR;
+ if (body.size > PURE_OBJECT_LIMIT || expected < 0) return PURE_LIMIT;
+ int directory = open(path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+ if (directory < 0) return PURE_STORE_ERROR;
+ int lock = openat(directory, ".writer.lock", O_RDWR | O_NOFOLLOW | O_CLOEXEC);
+ int fd = -1, source = -1;
+ size_t old_size = 0, result_size = body.size;
+ PureResult result = PURE_STORE_ERROR;
+ struct stat info;
+ if (lock < 0 || fstat(lock, &info) || !S_ISREG(info.st_mode)) goto finish;
+ struct flock hold = {.l_type = F_WRLCK, .l_whence = SEEK_SET, .l_start = 0, .l_len = 0};
+ if (fcntl(lock, F_SETLK, &hold)) {
+ if (errno == EACCES || errno == EAGAIN) result = PURE_BUSY;
+ goto finish;
+ }
+ source = openat(directory, name, O_RDONLY | O_NOFOLLOW | O_NONBLOCK | O_CLOEXEC);
+ if (source >= 0) {
+ if (!read_header(source, revision, &old_size)) goto finish;
+ } else if (errno != ENOENT) goto finish;
+ if (*revision != expected) { result = PURE_CONFLICT; goto finish; }
+ if (*revision == INT64_MAX) { result = PURE_LIMIT; goto finish; }
+ if (splice) {
+ if (offset > old_size || remove > old_size - offset ||
+ body.size > PURE_OBJECT_LIMIT - (old_size - remove)) { result = PURE_LIMIT; goto finish; }
+ result_size = old_size - remove + body.size;
+ }
+ for (unsigned attempt = 0; attempt < 64; ++attempt) {
+ if (temporary_sequence == UINT64_MAX) goto finish;
+ snprintf(temporary, sizeof(temporary), ".pending-%ld-%" PRIu64, (long)getpid(), ++temporary_sequence);
+ fd = openat(directory, temporary, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC, 0600);
+ if (fd >= 0) break;
+ temporary[0] = 0; /* Never remove an existing file on a name collision. */
+ if (errno != EEXIST) goto finish;
+ }
+ if (fd < 0) goto finish;
+ unsigned char header[HEADER_BYTES];
+ memcpy(header, magic, sizeof(magic));
+ encode64(header + 8, (uint64_t)*revision + 1);
+ encode64(header + 16, result_size);
+ if (!write_bytes(fd, header, sizeof(header)) || fault(PURE_AFTER_HEADER)) goto finish;
+ if (splice && !copy_extent(source, fd, 0, offset)) goto finish;
+ if (!write_bytes(fd, body.data, body.size)) goto finish;
+ if (splice && !copy_extent(source, fd, offset + remove, old_size - offset - remove)) goto finish;
+ if (fault(PURE_BEFORE_FILE_SYNC) || !sync_fd(fd)) goto finish;
+ int close_result = close(fd);
+ fd = -1;
+ if (close_result || fault(PURE_BEFORE_RENAME) || renameat(directory, temporary, directory, name)) goto finish;
+ temporary[0] = 0; /* Published: a later sync failure does not roll it back. */
+ ++*revision;
+ result = fault(PURE_BEFORE_DIR_SYNC) || !sync_fd(directory) ? PURE_UNCERTAIN : PURE_OK;
+finish:
+ if (fd >= 0) close(fd);
+ if (source >= 0) close(source);
+ if (*temporary) unlinkat(directory, temporary, 0);
+ if (lock >= 0) close(lock);
+ close(directory);
+ return result;
+}
+
+PureResult pure_store_put(const char *path, const char *key, int64_t expected,
+ PureSpan body, int64_t *revision) {
+ return mutate(path, key, expected, body, false, 0, 0, revision);
+}
+
+PureResult pure_store_splice(const char *path, const char *key, int64_t expected,
+ size_t offset, size_t remove, PureSpan insert, int64_t *revision) {
+ return mutate(path, key, expected, insert, true, offset, remove, revision);
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store.h b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store.h
new file mode 100644
index 0000000..99a3ef5
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/store.h
@@ -0,0 +1,44 @@
+#ifndef PURE_STORE_H
+#define PURE_STORE_H
+#include "flow.h"
+#include "result.h"
+#include <stdint.h>
+
+#define PURE_OBJECT_LIMIT ((2u * 6u + 32u) * 32768u + 8192u)
+typedef struct {
+ void *mapping;
+ size_t mapped_size, object_size;
+ PureSpan body;
+ int64_t revision;
+} PureStoredView;
+
+PureResult pure_store_init(const char *path);
+PureResult pure_store_get(const char *path, const char *key, size_t available,
+ PureStoredView *out);
+PureResult pure_store_get_range(const char *path, const char *key, size_t offset,
+ size_t length, size_t available, PureStoredView *out);
+/* Inspect once: guards and mapping refer to the same immutable file version.
+ * minimum preserves bounds checks from eliminated intermediate views.
+ * whole selects the suffix starting at offset; otherwise length is exact. */
+PureResult pure_store_select(const char *path, const char *key, size_t offset,
+ size_t length, bool whole, size_t minimum,
+ size_t available, PureStoredView *out);
+void pure_store_release(PureStoredView *);
+PureResult pure_store_put(const char *path, const char *key, int64_t expected,
+ PureSpan body, int64_t *revision);
+/* Atomic byte replacement: retain [0,offset), insert bytes, retain suffix after
+ * remove bytes. Check the expected revision and bounds under the same writer
+ * lock. expected=0 permits creating an empty base (offset=remove=0).
+ * Streams retained bytes through bounded scratch space; never assembles a
+ * whole new object in application memory. Still rewrites the immutable file. */
+PureResult pure_store_splice(const char *path, const char *key, int64_t expected,
+ size_t offset, size_t remove, PureSpan insert, int64_t *revision);
+
+/* Fault hooks exist only in the separately built unit-test binary. */
+typedef enum {
+ PURE_AFTER_HEADER, PURE_BEFORE_FILE_SYNC, PURE_BEFORE_RENAME, PURE_BEFORE_DIR_SYNC
+} PureStoreStage;
+#ifdef PURE_STORE_TEST
+int pure_store_test_fault(PureStoreStage stage);
+#endif
+#endif
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-fields.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-fields.c
new file mode 100644
index 0000000..63dfc3e
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-fields.c
@@ -0,0 +1,153 @@
+#include "program.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define CHECK(expr) do { if (!(expr)) { fprintf(stderr, "line %d: %s\n", __LINE__, #expr); exit(1); } } while (0)
+static const char get[] = "on get { let o = store.read(request.key); reply(o, o.body); }";
+static const char put[] = "on put { let s = store.write(request.key, request.revision, request.body); reply(s); }";
+static const char layout[] = "layout Envelope { marker: bytes[1]; start: u32le; count: u32le; text: bytes; }";
+static PureProgram parse(const char *source) {
+ PureProgram p;
+ char error[160];
+ if (!pure_program_parse(source, strlen(source), &p, error, sizeof(error))) {
+ fprintf(stderr, "%s\n", error); exit(1);
+ }
+ return p;
+}
+static void invalid(const char *source) {
+ PureProgram p;
+ memset(&p, 0x5a, sizeof(p));
+ unsigned char before[sizeof(p)];
+ memcpy(before, &p, sizeof(p));
+ char error[160];
+ CHECK(!pure_program_parse(source, strlen(source), &p, error, sizeof(error)));
+ CHECK(*error && !memcmp(before, &p, sizeof(p)));
+}
+static void encode(unsigned char *at, uint32_t value) {
+ for (unsigned i = 0; i < 4; ++i) at[i] = (unsigned char)(value >> (8 * i));
+}
+int main(void) {
+ char source[8000];
+ snprintf(source, sizeof(source), "%s %s on put { let input = view(Envelope, request.body); "
+ "let alias = input; let start = alias.start; let text = alias.text; "
+ "let selected = range(text, start, alias.count); let result = selected; "
+ "let saved = store.write(request.key, request.revision, result); reply(saved, selected); }", layout, get);
+ PureProgram p = parse(source);
+ CHECK(p.input_steps == 1 && p.input_required == 9 && p.write_step == 1 && p.reply_step == 1);
+ CHECK(p.steps[0].source.offset == 9 && p.steps[0].source.to_end);
+ CHECK(p.steps[0].offset.value == 1 && p.steps[0].offset.from_u32le);
+ CHECK(p.steps[0].length.value == 5 && p.steps[0].length.from_u32le);
+ unsigned char bytes[609];
+ for (size_t i = 0; i < sizeof(bytes); ++i) bytes[i] = (unsigned char)(i * 13);
+ PureSpan stored, returned;
+ for (size_t n = 0; n < 9; ++n) {
+ CHECK(!pure_program_input(&p, (PureSpan){bytes, n}, &stored, &returned));
+ CHECK(!stored.size && !returned.size);
+ }
+ const uint32_t offsets[] = {0, 1, 255, 257, 599, 600, 601, UINT32_MAX};
+ const uint32_t counts[] = {0, 1, 2, 260, 600, UINT32_MAX};
+ size_t comparisons = 0;
+ for (size_t i = 0; i < sizeof(offsets) / sizeof(*offsets); ++i)
+ for (size_t j = 0; j < sizeof(counts) / sizeof(*counts); ++j) {
+ uint32_t start = offsets[i], count = counts[j];
+ encode(bytes + 1, start);
+ encode(bytes + 5, count);
+ bool expected = start <= 600 && count <= 600 - start;
+ CHECK(pure_program_input(&p, (PureSpan){bytes, sizeof(bytes)}, &stored, &returned) == expected);
+ if (expected) {
+ CHECK(stored.size == count && returned.size == count && stored.data == returned.data);
+ CHECK(!count || stored.data == bytes + 9 + start);
+ } else CHECK(!stored.size && !returned.size);
+ ++comparisons;
+ }
+ snprintf(source, sizeof(source), "%s %s on put { let input = view(Envelope, request.body); "
+ "let first = range(input.text, input.start, input.count); let second = range(first, 1, 2); "
+ "let saved = store.write(request.key, request.revision, second); reply(saved, second); }", layout, get);
+ p = parse(source);
+ CHECK(p.input_steps == 2 && p.steps[1].source_step == 1);
+ encode(bytes + 1, 3); encode(bytes + 5, 4);
+ CHECK(pure_program_input(&p, (PureSpan){bytes, sizeof(bytes)}, &stored, &returned));
+ CHECK(stored.size == 2 && stored.data == bytes + 13);
+ encode(bytes + 5, 2);
+ CHECK(!pure_program_input(&p, (PureSpan){bytes, sizeof(bytes)}, &stored, &returned));
+ snprintf(source, sizeof(source), "%s %s on put { let input = view(Envelope, request.body); "
+ "let unused = range(input.text, input.start, input.count); "
+ "let saved = store.write(request.key, request.revision, input.text); reply(saved); }", layout, get);
+ p = parse(source);
+ encode(bytes + 1, UINT32_MAX);
+ CHECK(!pure_program_input(&p, (PureSpan){bytes, sizeof(bytes)}, &stored, &returned));
+
+ snprintf(source, sizeof(source), "%s on get { let o = store.read(request.key); "
+ "let input = view(Envelope, o.body); reply(o, input.text); } %s", layout, put);
+ p = parse(source);
+ CHECK(p.read.to_end && p.read.offset == 9 && p.read_required == 9 && !p.input_steps);
+ snprintf(source, sizeof(source), "%s %s on put { let input = view(Envelope, request.body); "
+ "let selection = range(input.text, 2, 3); let saved = store.write(request.key, request.revision, selection); reply(saved); }", layout, get);
+ p = parse(source);
+ CHECK(!p.input_steps && p.write.offset == 11 && p.write.length == 3 && p.input_required == 14);
+ snprintf(source, sizeof(source), "layout Empty { body: bytes; } %s on put { let input = view(Empty, request.body); "
+ "let saved = store.write(request.key, request.revision, input.body); reply(saved, input.body); }", get);
+ p = parse(source);
+ CHECK(pure_program_input(&p, (PureSpan){0}, &stored, &returned) && !stored.size && !returned.size);
+
+ const char *bad_layout[] = {
+ "layout E {}", "layout E { x: bytes; y: u32le; }", "layout E { x: u32le; x: bytes; }",
+ "layout E { x: bytes[1449985]; }", "layout E { x: bytes[1449984]; y: u32le; }",
+ "layout E { x: bytes[184467440737095516160]; }", "layout E { x: u64le; }",
+ "layout E { x: u32le; } layout E { y: bytes; }"
+ };
+ for (size_t i = 0; i < sizeof(bad_layout) / sizeof(*bad_layout); ++i) {
+ snprintf(source, sizeof(source), "%s %s %s", bad_layout[i], get, put); invalid(source);
+ }
+ const char *bad_input[] = {
+ "let input = view(Missing, request.body);",
+ "let input = view(Envelope, request.body); let x = input.missing;",
+ "let input = view(Envelope, request.body); let x = range(input.text, input.text, 1);",
+ "let short = range(request.body, 0, 8); let input = view(Envelope, short);",
+ "let input = view(Envelope, request.body); let x = range(input.text, input.start, 20); let y = view(Envelope, x);"
+ };
+ for (size_t i = 0; i < sizeof(bad_input) / sizeof(*bad_input); ++i) {
+ snprintf(source, sizeof(source), "%s %s on put { %s let saved = store.write(request.key, request.revision, request.body); reply(saved); }", layout, get, bad_input[i]);
+ invalid(source);
+ }
+ snprintf(source, sizeof(source), "%s %s on put { let input = view(Envelope, request.body); "
+ "let saved = store.write(request.key, request.revision, input.start); reply(saved); }", layout, get);
+ invalid(source);
+ snprintf(source, sizeof(source), "%s on get { let o = store.read(request.key); let input = view(Envelope, o.body); "
+ "let x = range(input.text, input.start, input.count); reply(o, x); } %s", layout, put);
+ invalid(source);
+ for (size_t count = 8; count <= 9; ++count) {
+ snprintf(source, sizeof(source), "%s %s on put { let input = view(Envelope, request.body); ", layout, get);
+ for (size_t i = 0; i < count; ++i) {
+ size_t used = strlen(source);
+ snprintf(source + used, sizeof(source) - used, "let v%zu = range(input.text, input.start, input.count); ", i);
+ }
+ size_t used = strlen(source);
+ snprintf(source + used, sizeof(source) - used, "let saved = store.write(request.key, request.revision, input.text); reply(saved); }");
+ if (count == 8) CHECK(parse(source).input_steps == 8); else invalid(source);
+ }
+ for (size_t count = 4; count <= 5; ++count) {
+ source[0] = 0;
+ for (size_t i = 0; i < count; ++i) {
+ size_t used = strlen(source);
+ snprintf(source + used, sizeof(source) - used, "layout L%zu { body: bytes; } ", i);
+ }
+ size_t used = strlen(source);
+ snprintf(source + used, sizeof(source) - used, "%s %s", get, put);
+ if (count == 4) (void)parse(source); else invalid(source);
+ }
+ for (size_t count = 16; count <= 17; ++count) {
+ strcpy(source, "layout L { ");
+ for (size_t i = 0; i < count; ++i) {
+ size_t used = strlen(source);
+ snprintf(source + used, sizeof(source) - used, "f%zu: u32le; ", i);
+ }
+ size_t used = strlen(source);
+ snprintf(source + used, sizeof(source) - used, "} %s %s", get, put);
+ if (count == 16) (void)parse(source); else invalid(source);
+ }
+ printf("{\"fields\":\"named-layouts-unaligned-u32le-tail-dynamic-ranges-aliases-failures-limits\","
+ "\"data_boundary_cases\":%zu}\n", comparisons);
+ return 0;
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-flow.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-flow.c
new file mode 100644
index 0000000..5ff028d
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-flow.c
@@ -0,0 +1,183 @@
+#define _POSIX_C_SOURCE 200809L
+#include "store.h"
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define CHECK(expr) do { if (!(expr)) { fprintf(stderr, "line %d: %s\n", __LINE__, #expr); exit(1); } } while (0)
+static int failed_stage = -1;
+static bool crash_at_stage;
+int pure_store_test_fault(PureStoreStage stage) {
+ if ((int)stage != failed_stage) return 0;
+ if (crash_at_stage) _exit(77);
+ return 1;
+}
+typedef struct { unsigned char *bytes; unsigned releases; } Owner;
+static void release(void *raw) {
+ Owner *owner = raw;
+ free(owner->bytes);
+ owner->bytes = NULL;
+ ++owner->releases;
+}
+
+static void transfers(void) {
+ Owner owner = {.bytes = malloc(5)};
+ CHECK(owner.bytes);
+ memcpy(owner.bytes, "a\0bcd", 5);
+ PureTransfer transfer = {0};
+ pure_transfer_init(&transfer, (PureSpan){(const unsigned char *)"head", 4},
+ (PureSpan){owner.bytes, 5}, &owner, release);
+ CHECK(!pure_transfer_consume(&transfer, 5));
+ CHECK(transfer.active && !owner.releases);
+ CHECK(pure_transfer_consume(&transfer, 0));
+ unsigned char received[9];
+ size_t used = 0;
+ while (transfer.active) {
+ PureSpan span = pure_transfer_next(&transfer, 2);
+ CHECK(span.size && span.size <= 2);
+ memcpy(received + used, span.data, span.size);
+ used += span.size;
+ CHECK(pure_transfer_consume(&transfer, span.size));
+ CHECK((used == 9) == (owner.releases == 1));
+ }
+ CHECK(used == 9 && !memcmp(received, "heada\0bcd", 9));
+ pure_transfer_abort(&transfer);
+ CHECK(owner.releases == 1 && !pure_transfer_consume(&transfer, 0));
+ owner.bytes = malloc(3);
+ CHECK(owner.bytes);
+ pure_transfer_init(&transfer, (PureSpan){0}, (PureSpan){owner.bytes, 3}, &owner, release);
+ CHECK(pure_transfer_consume(&transfer, 1));
+ pure_transfer_abort(&transfer);
+ pure_transfer_abort(&transfer);
+ CHECK(owner.releases == 2 && !transfer.active);
+ pure_transfer_init(&transfer, (PureSpan){0}, (PureSpan){0}, &owner, release);
+ CHECK(owner.releases == 3 && !transfer.active);
+}
+
+static void storage(const char *path) {
+ CHECK(pure_store_init(path) == PURE_OK);
+ PureStoredView first, second;
+ CHECK(pure_store_get(path, "missing", 100, &first) == PURE_NOT_FOUND);
+ CHECK(!first.mapping && !first.mapped_size);
+ static const unsigned char original[] = {0, 1, 2, 255, 17};
+ static const unsigned char updated[] = {9, 8, 7};
+ int64_t revision;
+ CHECK(pure_store_put(path, "work", 0, (PureSpan){original, sizeof(original)}, &revision) == PURE_OK);
+ CHECK(revision == 1);
+ CHECK(pure_store_get(path, "work", sizeof(original) - 1, &first) == PURE_BUDGET);
+ CHECK(!first.mapping && !first.mapped_size);
+ CHECK(pure_store_get_range(path, "work", 1, 3, 3, &first) == PURE_OK);
+ CHECK(first.object_size == sizeof(original) && first.body.size == 3 && !memcmp(first.body.data, original + 1, 3));
+ pure_store_release(&first);
+ CHECK(pure_store_get_range(path, "work", SIZE_MAX, 1, 10, &first) == PURE_LIMIT);
+ CHECK(pure_store_get_range(path, "work", 1, SIZE_MAX, 10, &first) == PURE_LIMIT);
+ CHECK(pure_store_get_range(path, "work", 1, 3, 2, &first) == PURE_BUDGET);
+ CHECK(pure_store_get_range(path, "work", sizeof(original), 0, 0, &first) == PURE_OK);
+ CHECK(!first.mapped_size && !first.body.size);
+ pure_store_release(&first);
+ CHECK(pure_store_get(path, "work", sizeof(original), &first) == PURE_OK);
+ CHECK(first.body.size == sizeof(original) && first.revision == 1);
+ CHECK(pure_store_put(path, "work", 1, (PureSpan){updated, sizeof(updated)}, &revision) == PURE_OK);
+ CHECK(revision == 2);
+ CHECK(!memcmp(first.body.data, original, sizeof(original)));
+ CHECK(pure_store_get(path, "work", 100, &second) == PURE_OK);
+ CHECK(second.revision == 2 && second.body.size == sizeof(updated));
+ CHECK(!memcmp(second.body.data, updated, sizeof(updated)));
+ pure_store_release(&first);
+ pure_store_release(&first);
+ pure_store_release(&second);
+ CHECK(pure_store_put(path, "work", 1, (PureSpan){original, sizeof(original)}, &revision) == PURE_CONFLICT);
+ CHECK(revision == 2);
+
+ for (failed_stage = PURE_AFTER_HEADER; failed_stage <= PURE_BEFORE_RENAME; ++failed_stage) {
+ CHECK(pure_store_put(path, "work", 2, (PureSpan){original, sizeof(original)}, &revision) == PURE_STORE_ERROR);
+ CHECK(pure_store_get(path, "work", 100, &first) == PURE_OK);
+ CHECK(first.revision == 2 && !memcmp(first.body.data, updated, sizeof(updated)));
+ pure_store_release(&first);
+ }
+ failed_stage = PURE_BEFORE_DIR_SYNC;
+ CHECK(pure_store_put(path, "work", 2, (PureSpan){original, sizeof(original)}, &revision) == PURE_UNCERTAIN);
+ CHECK(revision == 3);
+ failed_stage = -1;
+ CHECK(pure_store_get(path, "work", 100, &first) == PURE_OK);
+ CHECK(first.revision == 3 && !memcmp(first.body.data, original, sizeof(original)));
+ pure_store_release(&first);
+ CHECK(pure_store_put(path, "work", 2, (PureSpan){updated, sizeof(updated)}, &revision) == PURE_CONFLICT);
+
+ /* A crashed unpublished writer leaves only a private file. A new publisher
+ * must still use the previous committed version, never an incomplete body. */
+ pid_t child = fork();
+ CHECK(child >= 0);
+ if (!child) {
+ failed_stage = PURE_AFTER_HEADER;
+ crash_at_stage = true;
+ pure_store_put(path, "work", 3, (PureSpan){updated, sizeof(updated)}, &revision);
+ _exit(78);
+ }
+ int status;
+ CHECK(waitpid(child, &status, 0) == child && WIFEXITED(status) && WEXITSTATUS(status) == 77);
+ CHECK(pure_store_init(path) == PURE_OK);
+ CHECK(pure_store_get(path, "work", 100, &first) == PURE_OK);
+ CHECK(first.revision == 3 && !memcmp(first.body.data, original, sizeof(original)));
+ pure_store_release(&first);
+ CHECK(pure_store_put(path, "work", 3, (PureSpan){updated, sizeof(updated)}, &revision) == PURE_OK);
+ CHECK(revision == 4);
+
+ char file[320];
+ snprintf(file, sizeof(file), "%s/obj-work", path);
+ int fd = open(file, O_WRONLY);
+ CHECK(fd >= 0);
+ const unsigned char maximum[] = {255,255,255,255,255,255,255,127};
+ CHECK(pwrite(fd, maximum, 8, 8) == 8 && close(fd) == 0);
+ CHECK(pure_store_put(path, "work", INT64_MAX, (PureSpan){original, sizeof(original)}, &revision) == PURE_LIMIT);
+ CHECK(pure_store_put(path, "empty", 0, (PureSpan){0}, &revision) == PURE_OK);
+ CHECK(pure_store_get(path, "empty", 0, &first) == PURE_OK && first.body.size == 0);
+ pure_store_release(&first);
+
+ /* Range mapping crosses page boundaries without copying a whole object. */
+ long page = sysconf(_SC_PAGESIZE);
+ CHECK(page >= 128 && (size_t)page <= PURE_OBJECT_LIMIT / 3);
+ size_t size = (size_t)page * 3, offset = (size_t)page + 13, length = (size_t)page + 105;
+ unsigned char *bytes = malloc(size);
+ CHECK(bytes);
+ for (size_t i = 0; i < size; ++i) bytes[i] = (unsigned char)((i * 17u) ^ (i >> 8) ^ (i >> 16));
+ CHECK(pure_store_put(path, "range", 0, (PureSpan){bytes, size}, &revision) == PURE_OK);
+ CHECK(pure_store_get_range(path, "range", offset, length, length, &first) == PURE_OK);
+ CHECK(first.body.size == length && !memcmp(first.body.data, bytes + offset, length));
+ pure_store_release(&first);
+ free(bytes);
+ snprintf(file, sizeof(file), "%s/obj-broken", path);
+ fd = open(file, O_CREAT | O_WRONLY | O_EXCL, 0600);
+ CHECK(fd >= 0 && write(fd, "incomplete", 10) == 10 && close(fd) == 0);
+ CHECK(pure_store_get(path, "broken", 100, &first) == PURE_STORE_ERROR && !first.mapped_size);
+ CHECK(pure_store_put(path, "broken", 0, (PureSpan){updated, sizeof(updated)}, &revision) == PURE_STORE_ERROR);
+ CHECK(pure_store_init(file) == PURE_STORE_ERROR);
+ struct stat info;
+ CHECK(stat(file, &info) == 0 && info.st_size == 10);
+}
+
+int main(void) {
+ transfers();
+ char directory[] = "/tmp/pure-connection-unit-XXXXXX";
+ CHECK(mkdtemp(directory));
+ char path[256];
+ snprintf(path, sizeof(path), "%s/store", directory);
+ storage(path);
+ DIR *entries = opendir(path);
+ CHECK(entries);
+ struct dirent *entry;
+ while ((entry = readdir(entries))) {
+ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue;
+ CHECK(unlinkat(dirfd(entries), entry->d_name, 0) == 0);
+ }
+ CHECK(closedir(entries) == 0 && rmdir(path) == 0);
+ CHECK(rmdir(directory) == 0);
+ puts("{\"transfer\":\"partial-consumption-and-single-release\","
+ "\"storage\":\"mapped-ranges-snapshot-budget-conflict-failure-uncertain-crash-overflow-empty\"}");
+ return 0;
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-program.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-program.c
new file mode 100644
index 0000000..6a4a19d
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-program.c
@@ -0,0 +1,111 @@
+#include "program.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define CHECK(expr) do { if (!(expr)) { fprintf(stderr, "line %d: %s\n", __LINE__, #expr); exit(1); } } while (0)
+static const char get[] = "on get { let o = store.read(request.key); reply(o, o.body); }";
+static const char put[] = "on put { let s = store.write(request.key, request.revision, request.body); reply(s); }";
+static PureProgram parse(const char *source) {
+ PureProgram program;
+ char error[160];
+ if (!pure_program_parse(source, strlen(source), &program, error, sizeof(error))) {
+ fprintf(stderr, "%s\n", error); exit(1);
+ }
+ return program;
+}
+static void invalid(const char *source) {
+ PureProgram program;
+ memset(&program, 0x5a, sizeof(program));
+ unsigned char original[sizeof(program)];
+ memcpy(original, &program, sizeof(program));
+ char error[160];
+ CHECK(!pure_program_parse(source, strlen(source), &program, error, sizeof(error)));
+ CHECK(*error && !memcmp(original, &program, sizeof(program)));
+}
+int main(void) {
+ char source[4096];
+ snprintf(source, sizeof(source), "%s %s", get, put);
+ PureProgram plan = parse(source);
+ CHECK(plan.read.to_end && plan.write.to_end && !plan.reply_input);
+ CHECK(!plan.view_definitions && !plan.read_required && !plan.input_required);
+ snprintf(source, sizeof(source), "%s on put { let a = range(request.body, 2, 10); "
+ "let b = range(a, 3, 4); let alias = b; "
+ "let saved = store.write(request.key, request.revision, alias); reply(saved, b); }", get);
+ plan = parse(source);
+ CHECK(plan.write.offset == 5 && plan.write.length == 4 && !plan.write.to_end);
+ CHECK(plan.reply.offset == 5 && plan.reply.length == 4 && plan.reply_input);
+ CHECK(plan.input_required == 12 && plan.range_definitions == 2 && plan.view_definitions == 3);
+ /* Ordered reference views keep even unused bounds failures observable. */
+ unsigned char bytes[160];
+ for (size_t i = 0; i < sizeof(bytes); ++i) bytes[i] = (unsigned char)(i * 7);
+ size_t comparisons = 0;
+ for (size_t a = 0; a < 4; ++a) for (size_t b = 0; b < 6; ++b)
+ for (size_t c = 0; c <= b; ++c) for (size_t d = 0; d <= b - c; ++d) {
+ size_t unused_end = (a + b + c) % 12;
+ snprintf(source, sizeof(source), "on get { let o = store.read(request.key); "
+ "let unused = range(o.body, %zu, 0); let first = range(o.body, %zu, %zu); "
+ "let second = range(first, %zu, %zu); reply(o, second); } %s",
+ unused_end, a, b, c, d, put);
+ plan = parse(source);
+ for (size_t n = 0; n < 16; ++n) {
+ bool reference_ok = unused_end <= n && a <= n && b <= n - a;
+ PureSpan selected;
+ bool prepared_ok = n >= plan.read_required &&
+ pure_region_span(plan.read, (PureSpan){bytes, n}, &selected);
+ CHECK(reference_ok == prepared_ok);
+ if (reference_ok) {
+ CHECK(selected.size == d);
+ CHECK(!d || !memcmp(selected.data, bytes + a + c, d));
+ }
+ ++comparisons;
+ }
+ }
+ snprintf(source, sizeof(source), "on get { let o = store.read(request.key); reply(o); } %s", put);
+ plan = parse(source);
+ CHECK(!plan.read.to_end && !plan.read.length);
+ const char *bad_get[] = {
+ "on get { let o = store.read(request.key); let x = range(o.body, 0, 2); let y = range(x, 2, 1); reply(o, y); }",
+ "on get { let o = store.read(request.key); let x = range(o.body, 184467440737095516160, 1); reply(o, x); }",
+ "on get { let o = store.read(request.key); let x = range(o.body, 1449984, 1); reply(o, x); }",
+ "on get { let o = store.read(request.key); let o = o.body; reply(o); }",
+ "on get { let o = store.read(request.key); let x = x; reply(o, x); }",
+ "on get { let o = store.read(request.key); let x = store.read(request.key); reply(x); }",
+ "on get { let o = store.read(request.key); reply(o, request.body); }",
+ "on get { let o = store.read(request.key); let x = o.body; reply(x); }",
+ "on get { let o = store.read(request.key); reply(o.body); }",
+ "on get { let o = store.read(request.key); reply(o); let x = o.body; }",
+ "on get { let o = store.read(request.key); reply(o);", "on get {}"
+ };
+ for (size_t i = 0; i < sizeof(bad_get) / sizeof(*bad_get); ++i) {
+ snprintf(source, sizeof(source), "%s %s", bad_get[i], put); invalid(source);
+ }
+ const char *bad_put[] = {
+ "on put { let s = store.write(request.key, request.revision, request.body); let b = range(request.body, 0, 1); reply(s, b); }",
+ "on put { let s = store.write(request.key, request.revision, request.body); reply(s, s.body); }",
+ "on put { let s = store.read(request.key); reply(s); }"
+ };
+ for (size_t i = 0; i < sizeof(bad_put) / sizeof(*bad_put); ++i) {
+ snprintf(source, sizeof(source), "%s %s", get, bad_put[i]); invalid(source);
+ }
+ invalid(get);
+ snprintf(source, sizeof(source), "%s %s %s", get, get, put); invalid(source);
+ snprintf(source, sizeof(source), "%s %s garbage", get, put); invalid(source);
+ snprintf(source, sizeof(source), "on get { let o = store.read(request.key); ");
+ for (size_t i = 0; i < 32; ++i) {
+ size_t used = strlen(source);
+ snprintf(source + used, sizeof(source) - used, "let x%zu = o.body; ", i);
+ }
+ size_t used = strlen(source);
+ snprintf(source + used, sizeof(source) - used, "reply(o); } %s", put); invalid(source);
+ char oversized[PURE_PROGRAM_LIMIT + 1];
+ memset(oversized, ' ', sizeof(oversized));
+ char error[160];
+ CHECK(!pure_program_parse(oversized, sizeof(oversized), &plan, error, sizeof(error)));
+ const char embedded[] = "on get\0{}";
+ CHECK(!pure_program_parse(embedded, sizeof(embedded) - 1, &plan, error, sizeof(error)));
+ PureSpan selected;
+ CHECK(pure_region_span((PureRegion){0}, (PureSpan){0}, &selected) && !selected.data && !selected.size);
+ printf("{\"program\":\"prepare-views-preserve-guards-types-effects-and-atomic-install\","
+ "\"boundary_semantic_comparisons\":%zu}\n", comparisons);
+ return 0;
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-runtime.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-runtime.c
new file mode 100644
index 0000000..0ff6a8b
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-runtime.c
@@ -0,0 +1,285 @@
+#define _POSIX_C_SOURCE 200809L
+#include "runtime.h"
+#include "store-port.h"
+#include "store.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static const PureProgram identity = {
+ .read = {.to_end = true}, .write = {.to_end = true},
+ .reply = {.to_end = true}, .reply_input = true
+};
+typedef struct {
+ size_t allocations, writes, frees, live;
+ bool allocation_failure, oversized_read, reenter;
+ PureRuntime *runtime;
+ unsigned char received[256];
+ size_t received_size;
+} Host;
+typedef struct { Host *host; unsigned char bytes[]; } Allocation;
+
+static void free_input(void *pointer, size_t size) {
+ Allocation *a = pointer;
+ assert(size > 0 && a->host->live > 0);
+ ++a->host->frees;
+ --a->host->live;
+ free(a);
+}
+
+static bool allocate(void *context, size_t size, PureResource *out) {
+ Host *host = context;
+ if (host->allocation_failure) return false;
+ Allocation *a = malloc(sizeof(*a) + size);
+ assert(a);
+ a->host = host;
+ ++host->allocations;
+ ++host->live;
+ *out = (PureResource){.body = {a->bytes, size}, .allocation = a,
+ .allocation_size = size, .release = free_input};
+ return true;
+}
+
+static PureResult write_value(void *context, const char *key, int64_t expected,
+ PureSpan body, int64_t *revision) {
+ Host *host = context;
+ (void)key;
+ if (host->reenter) {
+ PureTicket ignored;
+ assert(pure_runtime_accept(host->runtime, PURE_INPUT_WRITE, "reenter", 0, 0, &ignored) == PURE_INVALID);
+ assert(!pure_runtime_step(host->runtime));
+ }
+ if (expected == 99) { *revision = 1; return PURE_CONFLICT; }
+ ++host->writes;
+ assert(body.size <= sizeof(host->received));
+ if (body.size) memcpy(host->received, body.data, body.size);
+ host->received_size = body.size;
+ *revision = 1;
+ return PURE_OK;
+}
+
+static PureResult read_value(void *context, const char *key, PureRegion range,
+ size_t minimum, size_t available, PureResource *out, int64_t *revision) {
+ Host *host = context;
+ (void)key; (void)range; (void)minimum;
+ if (!host->oversized_read) return PURE_NOT_FOUND;
+ assert(available < 1000);
+ assert(allocate(host, available + 1, out));
+ *revision = 1;
+ return PURE_OK; /* Deliberately violates the available-credit contract. */
+}
+
+static PureHost port(Host *host) {
+ return (PureHost){.context = host, .allocate = allocate, .read = read_value, .write = write_value};
+}
+
+static PureTicket submit(PureRuntime *r, const char *key, const void *bytes, size_t length) {
+ PureTicket ticket;
+ assert(pure_runtime_accept(r, PURE_INPUT_WRITE, key, 0, length, &ticket) == PURE_OK);
+ size_t capacity;
+ unsigned char *input = pure_runtime_ingress(ticket, &capacity);
+ assert(capacity == length);
+ if (length) memcpy(input, bytes, length);
+ assert(pure_runtime_ready(ticket));
+ assert(!pure_runtime_ready(ticket));
+ return ticket;
+}
+
+static PureOutcome completed(PureRuntime *r, PureTicket ticket) {
+ PureOutcome result;
+ while (!pure_runtime_result(ticket, &result)) assert(pure_runtime_step(r));
+ return result;
+}
+
+static void admission_and_lifecycle(void) {
+ Host host = {0};
+ PureRuntime r;
+ PureWork work[3];
+ assert(pure_runtime_init(&r, work, 3, &identity, port(&host), 5));
+ host.runtime = &r;
+ PureTicket a, untouched = {0}, out = untouched;
+ assert(pure_runtime_accept(&r, PURE_INPUT_WRITE, "../bad", 0, 1, &out) == PURE_INVALID);
+ assert(!out.runtime && !host.allocations);
+ assert(pure_runtime_accept(&r, PURE_INPUT_WRITE, "a", 0, 4, &a) == PURE_OK);
+ assert(r.retained == 4 && !pure_runtime_step(&r) && !host.writes);
+ assert(pure_runtime_accept(&r, PURE_INPUT_WRITE, "b", 0, 2, &out) == PURE_BUDGET);
+ assert(!out.runtime && host.allocations == 1);
+ assert(pure_runtime_cancel(a));
+ PureOutcome cancelled;
+ assert(pure_runtime_result(a, &cancelled) && cancelled.status == PURE_CANCELLED);
+ assert(r.retained == 0 && host.frees == 1 && !pure_runtime_cancel(a));
+ assert(pure_runtime_release(a) && !pure_runtime_release(a));
+ assert(!pure_runtime_result(a, &cancelled));
+
+ PureTicket first = submit(&r, "first", "1", 1);
+ PureTicket middle = submit(&r, "middle", "2", 1);
+ PureTicket last = submit(&r, "last", "3", 1);
+ assert(pure_runtime_accept(&r, PURE_INPUT_WRITE, "full", 0, 0, &out) == PURE_BUSY);
+ assert(pure_runtime_cancel(middle));
+ assert(pure_runtime_release(middle));
+ pure_runtime_stop(&r);
+ assert(pure_runtime_accept(&r, PURE_INPUT_WRITE, "closed", 0, 0, &out) == PURE_CLOSED);
+ assert(!pure_runtime_restart(&r, &identity, port(&host), 5));
+ host.reenter = true;
+ assert(completed(&r, first).status == PURE_OK && host.received[0] == '1');
+ assert(completed(&r, last).status == PURE_OK && host.received[0] == '3');
+ assert(!pure_runtime_step(&r));
+ assert(pure_runtime_release(first) && pure_runtime_release(last));
+ assert(r.active == 0 && r.retained == 0 && host.live == 0);
+ assert(pure_runtime_restart(&r, &identity, port(&host), 5));
+ PureTicket next = submit(&r, "next", "4", 1);
+ assert(next.generation > last.generation && !pure_runtime_ready(a));
+ assert(!pure_runtime_release(last));
+ assert(pure_runtime_release(next)); /* queued input: no effect */
+ assert(host.writes == 2 && !pure_runtime_step(&r));
+
+ host.allocation_failure = true;
+ assert(pure_runtime_accept(&r, PURE_INPUT_WRITE, "no_memory", 0, 1, &out) == PURE_ALLOCATION);
+ assert(r.active == 0 && r.retained == 0);
+ host.allocation_failure = false;
+ PureHost denied = port(&host);
+ denied.write = NULL;
+ assert(pure_runtime_restart(&r, &identity, denied, 5));
+ assert(pure_runtime_accept(&r, PURE_INPUT_WRITE, "denied", 0, 1, &out) == PURE_DENIED);
+ assert(pure_runtime_restart(&r, &identity, port(&host), 5));
+ host.oversized_read = true;
+ assert(pure_runtime_accept(&r, PURE_INPUT_READ, "bad_host", 0, 0, &out) == PURE_OK);
+ assert(completed(&r, out).status == PURE_BUDGET && host.live == 0 && r.retained == 0);
+ assert(pure_runtime_release(out));
+ r.serial = UINT64_MAX;
+ assert(pure_runtime_accept(&r, PURE_INPUT_WRITE, "exhausted", 0, 0, &out) == PURE_LIMIT);
+}
+
+static void forwarding(void) {
+ Host a = {0}, b = {0}, c = {0};
+ PureRuntime source, left, right;
+ PureWork source_work[1], left_work[1], right_work[1];
+ assert(pure_runtime_init(&source, source_work, 1, &identity, port(&a), 8));
+ assert(pure_runtime_init(&left, left_work, 1, &identity, port(&b), 2));
+ assert(pure_runtime_init(&right, right_work, 1, &identity, port(&c), 8));
+ PureTicket original = submit(&source, "original", "value", 5), x = {0}, y;
+ PureOutcome result = completed(&source, original);
+ assert(result.status == PURE_OK);
+ const unsigned char *backing = result.body.data;
+ assert(pure_runtime_forward(original, &left, "left", 0, &x) == PURE_BUDGET);
+ assert(!x.runtime && source.work[0].pins == 0);
+ assert(pure_runtime_restart(&left, &identity, port(&b), 8));
+ assert(pure_runtime_forward(original, &left, "left", 0, &x) == PURE_OK);
+ assert(pure_runtime_forward(original, &right, "right", 0, &y) == PURE_OK);
+ assert(pure_runtime_release(original));
+ assert(!pure_runtime_result(original, &result));
+ pure_runtime_stop(&source);
+ assert(!pure_runtime_restart(&source, &identity, port(&a), 8));
+ assert(a.live == 1 && !b.allocations && !c.allocations);
+ assert(pure_runtime_cancel(x) && pure_runtime_release(x));
+ assert(a.live == 1 && !b.writes);
+ result = completed(&right, y);
+ assert(result.body.data == backing && result.body.size == 5 && !memcmp(result.body.data, "value", 5));
+ assert(c.writes == 1 && !c.allocations && source.retained == 5);
+ assert(!pure_runtime_cancel(y)); /* effects cannot be rolled back */
+ assert(pure_runtime_release(y));
+ assert(a.frees == 1 && !source.active && !source.retained && !right.active && !right.retained);
+ assert(pure_runtime_restart(&source, &identity, port(&a), 8));
+
+ /* A completed consumer does not retain its input when the program has no
+ * input-backed reply. The producing domain can then be reclaimed early. */
+ PureProgram no_reply = identity;
+ no_reply.reply_input = false;
+ assert(pure_runtime_restart(&right, &no_reply, port(&c), 8));
+ original = submit(&source, "again", "last", 4);
+ assert(completed(&source, original).status == PURE_OK);
+ assert(pure_runtime_forward(original, &right, "no_reply", 0, &y) == PURE_OK);
+ assert(pure_runtime_release(original));
+ assert(completed(&right, y).body.size == 0 && a.live == 0);
+ assert(source.active == 0 && right.active == 1 && right.retained == 0);
+ assert(pure_runtime_release(y));
+}
+
+static void long_chain(void) {
+ enum { COUNT = 1024 };
+ PureWork *work = calloc(COUNT, sizeof(*work));
+ assert(work);
+ Host host = {0};
+ PureRuntime r;
+ assert(pure_runtime_init(&r, work, COUNT, &identity, port(&host), COUNT));
+ PureTicket ticket = submit(&r, "chain", "x", 1);
+ for (size_t i = 1; i < COUNT; ++i) {
+ assert(completed(&r, ticket).status == PURE_OK);
+ PureTicket next;
+ assert(pure_runtime_forward(ticket, &r, "chain", 0, &next) == PURE_OK);
+ assert(pure_runtime_release(ticket));
+ ticket = next;
+ }
+ assert(completed(&r, ticket).status == PURE_OK);
+ assert(host.allocations == 1 && r.active == COUNT);
+ assert(pure_runtime_release(ticket));
+ assert(r.retained == 0 && r.active == 0 && host.frees == 1);
+ free(work);
+}
+
+static void actual_storage(void) {
+ char directory[] = "/tmp/pure-runtime-check-XXXXXX";
+ assert(mkdtemp(directory));
+ char source_path[128], target_path[128], name[160];
+ snprintf(source_path, sizeof(source_path), "%s/source", directory);
+ snprintf(target_path, sizeof(target_path), "%s/target", directory);
+ assert(pure_store_init(source_path) == PURE_OK && pure_store_init(target_path) == PURE_OK);
+ PureProgram selection;
+ char error[160];
+ assert(pure_program_load("examples/selection.pure", &selection, error, sizeof(error)));
+ PureRuntime source, target;
+ PureWork a[2], b[2];
+ assert(pure_runtime_init(&source, a, 2, &selection, pure_store_host(source_path), 128));
+ assert(pure_runtime_init(&target, b, 2, &identity, pure_store_host(target_path), 128));
+ const unsigned char bytes[] = {1,0,0,0, 3,0,0,0, 'a','b','c','d','e'};
+ PureTicket ticket = submit(&source, "excerpt", bytes, sizeof(bytes)), consumer;
+ PureOutcome result = completed(&source, ticket);
+ assert(result.status == PURE_OK && result.body.size == 3 && !memcmp(result.body.data, "bcd", 3));
+ assert(pure_runtime_forward(ticket, &target, "archive", 0, &consumer) == PURE_OK);
+ assert(pure_runtime_release(ticket));
+ assert(source.active == 1 && source.retained == sizeof(bytes));
+ assert(completed(&target, consumer).status == PURE_OK);
+ assert(pure_runtime_release(consumer) && source.active == 0);
+ PureStoredView stored = {0};
+ assert(pure_store_get(target_path, "archive", 128, &stored) == PURE_OK);
+ assert(stored.body.size == 3 && !memcmp(stored.body.data, "bcd", 3));
+ pure_store_release(&stored);
+
+ assert(pure_runtime_accept(&source, PURE_INPUT_READ, "excerpt", 0, 0, &ticket) == PURE_OK);
+ assert(completed(&source, ticket).status == PURE_OK);
+ assert(pure_runtime_forward(ticket, &target, "snapshot", 0, &consumer) == PURE_OK);
+ assert(pure_runtime_release(ticket));
+ int64_t revision;
+ assert(pure_store_put(source_path, "excerpt", 1, (PureSpan){(const unsigned char *)"new", 3}, &revision) == PURE_OK);
+ result = completed(&target, consumer);
+ assert(result.body.size == 3 && !memcmp(result.body.data, "bcd", 3));
+ assert(pure_runtime_release(consumer));
+
+ unsigned char invalid[] = {255,255,255,255, 1,0,0,0, 'x'};
+ ticket = submit(&source, "invalid", invalid, sizeof(invalid));
+ assert(completed(&source, ticket).status == PURE_LIMIT);
+ assert(pure_runtime_release(ticket));
+ assert(pure_store_get(source_path, "invalid", 128, &stored) == PURE_NOT_FOUND);
+ assert(source.active == 0 && target.active == 0 && source.retained == 0 && target.retained == 0);
+ const char *files[] = {"source/obj-excerpt", "source/.writer.lock", "target/obj-archive",
+ "target/obj-snapshot", "target/.writer.lock"};
+ for (size_t i = 0; i < sizeof(files) / sizeof(files[0]); ++i) {
+ snprintf(name, sizeof(name), "%s/%s", directory, files[i]);
+ assert(unlink(name) == 0);
+ }
+ assert(rmdir(source_path) == 0 && rmdir(target_path) == 0 && rmdir(directory) == 0);
+}
+
+int main(void) {
+ admission_and_lifecycle();
+ forwarding();
+ long_chain();
+ actual_storage();
+ printf("{\"runtime_tests\":\"passed\",\"domain_bytes\":%zu,\"work_slot_bytes\":%zu,"
+ "\"ticket_bytes\":%zu,\"prepared_program_bytes\":%zu,\"forwarding_chain\":1024,"
+ "\"native_storage_pipeline\":true}\n", sizeof(PureRuntime), sizeof(PureWork),
+ sizeof(PureTicket), sizeof(PureProgram));
+ return 0;
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-splice.c b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-splice.c
new file mode 100644
index 0000000..5b8232b
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/connections/test-splice.c
@@ -0,0 +1,172 @@
+#define _POSIX_C_SOURCE 200809L
+#include "runtime.h"
+#include "store-port.h"
+#include "store.h"
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define CHECK(x) do { if (!(x)) { fprintf(stderr, "line %d: %s\n", __LINE__, #x); exit(1); } } while (0)
+static int failed_stage = -1;
+int pure_store_test_fault(PureStoreStage stage) { return (int)stage == failed_stage; }
+
+static void expect(const char *path, const char *key, int64_t revision, PureSpan bytes) {
+ PureStoredView view;
+ CHECK(pure_store_get(path, key, PURE_OBJECT_LIMIT, &view) == PURE_OK);
+ CHECK(view.revision == revision && view.body.size == bytes.size);
+ CHECK(!bytes.size || !memcmp(view.body.data, bytes.data, bytes.size));
+ pure_store_release(&view);
+}
+
+static void parser(void) {
+ const char *get = "on get { let o = store.read(request.key); reply(o, o.body); }";
+ const char *layout = "layout E { marker: bytes[1]; remove: u32le; start: u32le; insert: bytes; }";
+ char source[2048], error[160];
+ PureProgram p;
+ snprintf(source, sizeof(source), "%s %s on put { let e = view(E, request.body); "
+ "let s = store.splice(request.key, request.revision, e.start, e.remove, e.insert); reply(s, e.insert); }", layout, get);
+ CHECK(pure_program_parse(source, strlen(source), &p, error, sizeof(error)));
+ CHECK(p.splice && p.input_required == 9 && p.splice_offset.value == 5 && p.splice_remove.value == 1);
+ unsigned char input[] = {0, 2,0,0,0, 3,0,0,0, 0,255};
+ PureSpan write, reply;
+ size_t offset, remove;
+ for (size_t n = 0; n < 9; ++n)
+ CHECK(!pure_program_input(&p, (PureSpan){input, n}, &write, &reply));
+ CHECK(pure_program_input(&p, (PureSpan){input, sizeof(input)}, &write, &reply));
+ CHECK(write.size == 2 && write.data == input + 9 && reply.data == write.data);
+ CHECK(pure_program_splice(&p, (PureSpan){input, sizeof(input)}, &offset, &remove));
+ CHECK(offset == 3 && remove == 2);
+
+ snprintf(source, sizeof(source), "%s on put { let s = store.splice(request.key, request.revision, 0, 0, request.body); reply(s); }", get);
+ CHECK(pure_program_parse(source, strlen(source), &p, error, sizeof(error)));
+ CHECK(pure_program_splice(&p, (PureSpan){0}, &offset, &remove) && offset == 0 && remove == 0);
+ const char *invalid[] = {
+ "let s = store.splice(request.key, request.revision, e.insert, 0, e.insert); reply(s);",
+ "let s = store.splice(request.key, request.revision, 0, 1449985, e.insert); reply(s);",
+ "let s = store.splice(request.key, request.revision, 0, 0, e.start); reply(s);",
+ "let s = store.splice(request.key, request.revision, 0, 0, e.insert); let t = store.write(request.key, request.revision, e.insert); reply(t);"
+ };
+ for (size_t i = 0; i < sizeof(invalid) / sizeof(*invalid); ++i) {
+ snprintf(source, sizeof(source), "%s %s on put { let e = view(E, request.body); %s }", layout, get, invalid[i]);
+ unsigned char before[sizeof(p)];
+ memcpy(before, &p, sizeof(p));
+ CHECK(!pure_program_parse(source, strlen(source), &p, error, sizeof(error)));
+ CHECK(*error && !memcmp(before, &p, sizeof(p)));
+ }
+}
+
+static void storage(const char *path) {
+ /* Reference whole-value assembly exists only in this test oracle. */
+ unsigned char oracle[65536], before[65536], insert[9000];
+ for (size_t i = 0; i < sizeof(insert); ++i) insert[i] = (unsigned char)(i * 19u);
+ size_t length = 49157;
+ for (size_t i = 0; i < length; ++i) oracle[i] = (unsigned char)((i * 17u) ^ (i >> 8));
+ int64_t revision;
+ CHECK(pure_store_splice(path, "work", 0, 0, 0, (PureSpan){oracle, length}, &revision) == PURE_OK);
+ CHECK(revision == 1);
+ /* Prefix/suffix copies cross both scratch and mapping page boundaries. */
+ const size_t edits[][3] = {{16381, 7, 9000}, {0, 0, 5}, {50000, 1, 0}, {4095, 4097, 3}, {0, 0, 0}};
+ for (size_t i = 0; i < sizeof(edits) / sizeof(*edits); ++i) {
+ size_t offset = edits[i][0], remove = edits[i][1], count = edits[i][2], previous = length;
+ memcpy(before, oracle, length);
+ PureStoredView old;
+ CHECK(pure_store_get(path, "work", PURE_OBJECT_LIMIT, &old) == PURE_OK);
+ int64_t expected = revision;
+ CHECK(pure_store_splice(path, "work", expected, offset, remove, (PureSpan){insert, count}, &revision) == PURE_OK);
+ CHECK(revision == expected + 1);
+ memmove(oracle + offset + count, oracle + offset + remove, length - offset - remove);
+ memcpy(oracle + offset, insert, count);
+ length = length - remove + count;
+ expect(path, "work", revision, (PureSpan){oracle, length});
+ CHECK(old.body.size == previous && !memcmp(old.body.data, before, previous));
+ pure_store_release(&old);
+ }
+ int64_t latest = revision;
+ CHECK(pure_store_splice(path, "work", latest - 1, 0, 0, (PureSpan){insert, 1}, &revision) == PURE_CONFLICT);
+ CHECK(revision == latest);
+ CHECK(pure_store_splice(path, "work", latest, SIZE_MAX, 0, (PureSpan){0}, &revision) == PURE_LIMIT);
+ CHECK(pure_store_splice(path, "work", latest, 0, SIZE_MAX, (PureSpan){0}, &revision) == PURE_LIMIT);
+ CHECK(pure_store_splice(path, "work", latest, length + 1, 0, (PureSpan){0}, &revision) == PURE_LIMIT);
+ /* Rejected before reading the intentionally undersized insertion pointer. */
+ CHECK(pure_store_splice(path, "work", latest, 0, 0, (PureSpan){insert, PURE_OBJECT_LIMIT}, &revision) == PURE_LIMIT);
+ expect(path, "work", latest, (PureSpan){oracle, length});
+ CHECK(pure_store_splice(path, "missing", 0, 1, 0, (PureSpan){0}, &revision) == PURE_LIMIT);
+ PureStoredView view;
+ CHECK(pure_store_get(path, "missing", 0, &view) == PURE_NOT_FOUND);
+ for (failed_stage = PURE_AFTER_HEADER; failed_stage <= PURE_BEFORE_RENAME; ++failed_stage) {
+ CHECK(pure_store_splice(path, "work", latest, 1, 3, (PureSpan){insert, 5}, &revision) == PURE_STORE_ERROR);
+ expect(path, "work", latest, (PureSpan){oracle, length});
+ }
+ failed_stage = PURE_BEFORE_DIR_SYNC;
+ CHECK(pure_store_splice(path, "work", latest, length, 0, (PureSpan){insert, 5}, &revision) == PURE_UNCERTAIN);
+ CHECK(revision == latest + 1);
+ failed_stage = -1;
+ memcpy(oracle + length, insert, 5); length += 5;
+ expect(path, "work", revision, (PureSpan){oracle, length});
+ CHECK(pure_store_splice(path, "work", revision, 0, length, (PureSpan){0}, &revision) == PURE_OK);
+ expect(path, "work", revision, (PureSpan){0});
+ char file[256];
+ snprintf(file, sizeof(file), "%s/obj-work", path);
+ int fd = open(file, O_WRONLY);
+ const unsigned char maximum[] = {255,255,255,255,255,255,255,127};
+ CHECK(fd >= 0 && pwrite(fd, maximum, 8, 8) == 8 && close(fd) == 0);
+ CHECK(pure_store_splice(path, "work", INT64_MAX, 0, 0, (PureSpan){0}, &revision) == PURE_LIMIT);
+}
+
+static void runtime(const char *path) {
+ PureProgram program;
+ char error[160];
+ CHECK(pure_program_load("examples/editor.pure", &program, error, sizeof(error)));
+ PureRuntime runtime;
+ PureWork slots[1];
+ PureHost denied = pure_store_host(path);
+ denied.splice = NULL; /* ordinary writes do not grant permission to splice */
+ CHECK(pure_runtime_init(&runtime, slots, 1, &program, denied, 32));
+ PureTicket ticket = {0};
+ CHECK(pure_runtime_accept(&runtime, PURE_INPUT_WRITE, "native", 0, 9, &ticket) == PURE_DENIED);
+ CHECK(!ticket.runtime && runtime.active == 0 && runtime.retained == 0);
+ CHECK(pure_runtime_restart(&runtime, &program, pure_store_host(path), 32));
+ CHECK(pure_runtime_accept(&runtime, PURE_INPUT_WRITE, "native", 0, 9, &ticket) == PURE_OK);
+ CHECK(pure_runtime_cancel(ticket) && pure_runtime_release(ticket));
+ CHECK(!pure_runtime_step(&runtime));
+ PureStoredView view;
+ CHECK(pure_store_get(path, "native", 32, &view) == PURE_NOT_FOUND);
+ CHECK(pure_runtime_accept(&runtime, PURE_INPUT_WRITE, "native", 0, 7, &ticket) == PURE_OK);
+ memset(pure_runtime_ingress(ticket, NULL), 0, 7);
+ CHECK(pure_runtime_ready(ticket) && pure_runtime_step(&runtime));
+ PureOutcome result;
+ CHECK(pure_runtime_result(ticket, &result) && result.status == PURE_LIMIT);
+ CHECK(pure_runtime_release(ticket) && runtime.commits == 0);
+ CHECK(pure_runtime_accept(&runtime, PURE_INPUT_WRITE, "native", 0, 9, &ticket) == PURE_OK);
+ unsigned char *input = pure_runtime_ingress(ticket, NULL);
+ memset(input, 0, 8); input[8] = 'x';
+ CHECK(pure_runtime_ready(ticket) && pure_runtime_step(&runtime));
+ CHECK(pure_runtime_result(ticket, &result) && result.status == PURE_OK && result.revision == 1);
+ CHECK(result.body.size == 1 && result.body.data == input + 8 && runtime.retained == 9);
+ expect(path, "native", 1, (PureSpan){(const unsigned char *)"x", 1});
+ CHECK(pure_runtime_release(ticket) && runtime.retained == 0 && runtime.active == 0);
+}
+
+int main(void) {
+ parser();
+ char path[] = "/tmp/pure-splice-check-XXXXXX";
+ CHECK(mkdtemp(path) && pure_store_init(path) == PURE_OK);
+ storage(path);
+ runtime(path);
+ DIR *entries = opendir(path);
+ CHECK(entries);
+ struct dirent *entry;
+ while ((entry = readdir(entries))) {
+ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue;
+ CHECK(strncmp(entry->d_name, ".pending-", 9));
+ CHECK(unlinkat(dirfd(entries), entry->d_name, 0) == 0);
+ }
+ CHECK(closedir(entries) == 0 && rmdir(path) == 0);
+ puts("{\"splice_tests\":\"passed\",\"checks\":[\"authored-fields-and-atomic-parse-failure\","
+ "\"binary-edit-oracle-and-old-snapshot\",\"bounds-conflict-size-overflow\","
+ "\"publication-failures-and-uncertain-durability\",\"cancel-admission-and-borrowed-reply\"]}");
+ return 0;
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/cli.mjs b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/cli.mjs
new file mode 100644
index 0000000..b67f4d3
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/cli.mjs
@@ -0,0 +1,127 @@
+#!/usr/bin/env node
+import { readFile, writeFile } from 'node:fs/promises';
+import { createInterface } from 'node:readline';
+import { createRuntime } from './web/runtime.mjs';
+import { parseProject } from './web/project.mjs';
+import { remoteTarget, pushProject, pullProject } from './remote.mjs';
+
+const help = `Pure authoring workbench · 같은 정의와 Zig 실행기
+ load PATH .pure 파일을 적용 (같은 이름의 상태 보존)
+ down NAME 정의한 입력 누르기
+ up NAME 정의한 입력 놓기
+ point NAME PHASE X Y 좌표 입력 (down / move / up / cancel)
+ point-target NAME VIEW PHASE X Y 그룹의 대상에 좌표 입력
+ change NAME VALUE 숫자 입력 전달
+ frame [1..600] 시간 진행, 1프레임 = 1/60초
+ show 상태와 도형 출력
+ limits C H W 표시 캐시(0..32)·변경 기록(0..8)·작업량(0..4294967295) 설정
+ forget [PART] 표시 기록 삭제: all, values, history (상태는 유지)
+ costs 마지막 표시 계산의 작업량·명령 수·캐시 적중 출력
+ reset 현재 정의의 초기 상태로
+ save PATH 적용한 정의를 저장
+ save-project PATH 적용 코드와 현재 배치를 JSON으로 저장
+ restore PATH 저장한 배치를 복원 (초안이 있으면 파일에 보존)
+ connect URL KEY 로컬 네이티브 저장 서버의 작업물에 연결
+ push [REVISION] 현재 배치를 저장 (첫 생성은 push 0, 충돌 시 기존 값 유지)
+ pull 원격 배치를 검증·복원하고 revision 기억
+ help / quit
+브라우저와 별도 인스턴스입니다. 임의 JavaScript는 실행하지 않습니다.`;
+
+async function main() {
+ const args = process.argv.slice(2);
+ if (args.includes('--help')) { console.log(help); return; }
+ if (args.length > 1) throw new Error('사용법: node cli.mjs [project.pure]');
+ const runtime = await createRuntime(await readFile(new URL('./web/core.wasm', import.meta.url)));
+ let savedDraft = null;
+ let remote = null, remoteRevision = null;
+ async function loadFile(path, restoreOnly = false) {
+ const content = await readFile(path, 'utf8');
+ if (restoreOnly || path.toLowerCase().endsWith('.json')) {
+ const project = parseProject(content);
+ if (project.version === 2) {
+ savedDraft = runtime.restoreDocument(project).draft;
+ return;
+ }
+ if (restoreOnly) throw new Error('현재 배치가 포함된 version 2 파일이 필요합니다.');
+ runtime.apply(project.source);
+ } else runtime.apply(content);
+ savedDraft = null;
+ }
+ if (args[0]) await loadFile(args[0]); else runtime.apply('');
+ const terminal = createInterface({ input: process.stdin, output: process.stdout, terminal: Boolean(process.stdin.isTTY) });
+ if (process.stdin.isTTY) console.log(help);
+ terminal.setPrompt('pure> ');
+ if (process.stdin.isTTY) terminal.prompt();
+ for await (const line of terminal) {
+ try {
+ const match = /^(\S+)(?:\s+(.+))?$/.exec(line.trim());
+ const name = match?.[1] || 'show';
+ const arg = match?.[2];
+ if (name === 'quit') { terminal.close(); break; }
+ if (name === 'help') console.log(help);
+ else if (name === 'costs' && !arg) console.log(JSON.stringify({ evaluation: runtime.evaluationStats() }));
+ else {
+ if (name === 'load' && arg) await loadFile(arg);
+ else if (name === 'restore' && arg) await loadFile(arg, true);
+ else if (name === 'connect' && arg) {
+ const parts = arg.split(/\s+/);
+ if (parts.length !== 2) throw new Error('connect URL KEY 형식을 사용하세요.');
+ remote = remoteTarget(parts[0], parts[1]);
+ remoteRevision = null;
+ console.log(JSON.stringify({ remote: remote.href }));
+ } else if (name === 'push') {
+ if (!remote) throw new Error('먼저 connect URL KEY로 연결하세요.');
+ const expected = arg ?? remoteRevision;
+ if (expected === null) throw new Error('먼저 pull로 버전을 읽거나 push 0으로 새 작업물을 만드세요.');
+ remoteRevision = await pushProject(remote, expected, runtime.exportDocument(savedDraft ?? undefined));
+ console.log(JSON.stringify({ remote: remote.href, revision: remoteRevision, stored: true }));
+ } else if (name === 'pull' && !arg) {
+ if (!remote) throw new Error('먼저 connect URL KEY로 연결하세요.');
+ const loaded = await pullProject(remote);
+ savedDraft = runtime.restoreDocument(loaded.project).draft;
+ remoteRevision = loaded.revision;
+ console.log(JSON.stringify({ remote: remote.href, revision: remoteRevision, restored: true }));
+ }
+ else if (name === 'save-project' && arg) await writeFile(arg, JSON.stringify(runtime.exportDocument(savedDraft ?? undefined), null, 2) + '\n', {flag:'wx'});
+ else if (name === 'save' && arg) await writeFile(arg, runtime.exportProject().source, { flag: 'wx' });
+ else if (name === 'down' && arg) runtime.down(arg, 'terminal');
+ else if (name === 'up' && arg) runtime.up(arg, 'terminal');
+ else if (name === 'point' && arg) {
+ const parts = arg.split(/\s+/);
+ if (parts.length !== 4) throw new Error('point NAME PHASE X Y 형식을 사용하세요.');
+ runtime.point(parts[0], parts[1], Number(parts[2]), Number(parts[3]), 'terminal');
+ } else if (name === 'point-target' && arg) {
+ const parts = arg.split(/\s+/);
+ if (parts.length !== 5) throw new Error('point-target NAME VIEW PHASE X Y 형식을 사용하세요.');
+ runtime.point(parts[0], parts[2], Number(parts[3]), Number(parts[4]), 'terminal', parts[1]);
+ } else if (name === 'change' && arg) {
+ const parts = arg.split(/\s+/);
+ if (parts.length !== 2) throw new Error('change NAME VALUE 형식을 사용하세요.');
+ runtime.change(parts[0], Number(parts[1]), 'terminal');
+ } else if (name === 'frame') {
+ if (arg !== undefined && !/^\d+$/.test(arg)) throw new Error('frame 1..600 정수를 입력하세요.');
+ const count = arg === undefined ? 1 : Number(arg);
+ if (count < 1 || count > 600) throw new Error('frame 1..600 정수를 입력하세요.');
+ runtime.frame(count);
+ } else if (name === 'reset' && !arg) runtime.reset();
+ else if (name === 'limits' && arg) {
+ const parts = arg.split(/\s+/);
+ if (parts.length !== 3 || parts.some(part => !/^\d+$/.test(part)))
+ throw new Error('limits C H W 정수 세 개를 입력하세요.');
+ const [cacheEntries, historyEntries, workLimit] = parts.map(Number);
+ runtime.configureEvaluation({ cacheEntries, historyEntries, workLimit });
+ } else if (name === 'forget') runtime.forgetEvaluation(arg || 'all');
+ else if (name !== 'show' || arg) throw new Error('명령 형식을 확인하세요. help로 안내를 볼 수 있습니다.');
+ const result = runtime.snapshot();
+ console.log(JSON.stringify(result));
+ if (result.lastError && !process.stdin.isTTY) process.exitCode = 1;
+ }
+ } catch (error) {
+ console.error(`${error.line ? `${error.line}:${error.column || 1} ` : ''}${error.message}`);
+ if (!process.stdin.isTTY) process.exitCode = 1;
+ }
+ if (process.stdin.isTTY) terminal.prompt();
+ }
+}
+
+main().catch((error) => { console.error(error.message); process.exitCode = 1; });
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/examples/direct.pure b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/examples/direct.pure
new file mode 100644
index 0000000..b29721c
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/examples/direct.pure
@@ -0,0 +1,47 @@
+# 도형을 잡은 위치를 유지해 이동합니다. 취소하면 잡기 전 위치로 돌아갑니다.
+state x = 80
+state y = 160
+state grab_x = 0
+state grab_y = 0
+state start_x = 80
+state start_y = 160
+state dragging = 0
+
+input drag = pointer(tile)
+input left = ArrowLeft
+input right = ArrowRight
+
+box left_area(20, 100, 280, 220, "#233a31")
+box right_area(340, 100, 280, 220, "#343b25")
+box tile(x, y, 56, 44, "#c9f08b")
+text horizontal(30, 45, x, "x: ")
+text vertical(180, 45, y, "y: ")
+text region(350, 70, x >= 320, "오른쪽 영역: ")
+text active(30, 75, dragging, "잡고 있음: ")
+
+on drag.down {
+ start_x = x
+ start_y = y
+ grab_x = event_x - x
+ grab_y = event_y - y
+ dragging = 1
+}
+on drag.move {
+ x = clamp(event_x - grab_x, 20, 564)
+ y = clamp(event_y - grab_y, 100, 276)
+}
+on drag.up {
+ # 놓기는 마지막으로 표시한 위치를 확정합니다.
+ dragging = 0
+}
+on drag.cancel {
+ x = start_x
+ y = start_y
+ dragging = 0
+}
+on left.down {
+ if dragging == 0 { x = max(20, x - 10) }
+}
+on right.down {
+ if dragging == 0 { x = min(564, x + 10) }
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/remote.mjs b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/remote.mjs
new file mode 100644
index 0000000..6ee6a59
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/remote.mjs
@@ -0,0 +1,89 @@
+import http from 'node:http';
+import { MAX_PROJECT_BYTES, parseProject } from './web/project.mjs';
+
+const maxRevision = 9223372036854775807n;
+function revisionText(value, allowZero = false) {
+ if (typeof value !== 'string' || !/^(0|[1-9]\d*)$/.test(value) ||
+ value.length > 19 || BigInt(value) > maxRevision || (!allowZero && value === '0'))
+ throw new Error('revision은 범위 안의 정수 문자열이어야 합니다.');
+ return value;
+}
+
+export function remoteTarget(base, key) {
+ const url = new URL(base);
+ if (url.protocol !== 'http:' || !['127.0.0.1', 'localhost'].includes(url.hostname) ||
+ url.username || url.password || url.pathname !== '/' || url.search || url.hash)
+ throw new Error('현재 연결 호스트는 로컬 http://127.0.0.1:PORT 형식을 사용합니다.');
+ if (!/^[A-Za-z0-9_-]{1,64}$/.test(key)) throw new Error('작업물 이름은 영문·숫자·_·- 1~64자입니다.');
+ url.hostname = '127.0.0.1';
+ url.pathname = `/objects/${key}`;
+ return url;
+}
+
+function request(url, method, body, headers = {}) {
+ return new Promise((resolve, reject) => {
+ let done = false;
+ const finish = (error, value) => {
+ if (done) return;
+ done = true;
+ clearTimeout(deadline);
+ if (error) reject(error); else resolve(value);
+ };
+ const req = http.request(url, { method, agent: false, headers: { ...headers,
+ 'Content-Length': body?.byteLength ?? 0, Connection: 'close' } }, (res) => {
+ const chunks = [];
+ let size = 0;
+ res.on('data', (chunk) => {
+ size += chunk.length;
+ if (size > MAX_PROJECT_BYTES) {
+ const error = new Error('서버 작업물이 허용 크기를 넘었습니다.');
+ finish(error);
+ res.destroy(error);
+ req.destroy(error);
+ } else chunks.push(chunk);
+ });
+ res.on('error', (error) => finish(error));
+ res.on('aborted', () => finish(new Error('응답이 완료되기 전에 연결이 끊겼습니다.')));
+ res.on('end', () => {
+ if (res.statusCode !== 200) {
+ const error = new Error(`원격 작업 실패: ${res.statusCode} ${res.headers['x-pure-error'] ?? ''}`.trim());
+ error.status = res.statusCode;
+ error.etag = res.headers.etag;
+ finish(error);
+ return;
+ }
+ try {
+ const match = /^"([1-9]\d*)"$/.exec(res.headers.etag ?? '');
+ if (!match) throw new Error('서버의 revision 응답이 올바르지 않습니다.');
+ const revision = revisionText(match[1]);
+ finish(null, { revision, bytes: Buffer.concat(chunks, size) });
+ } catch (error) { finish(error); }
+ });
+ });
+ const deadline = setTimeout(() => {
+ const error = new Error('원격 작업 시간 초과: 저장 완료 여부는 다시 확인해야 합니다.');
+ finish(error);
+ req.destroy(error);
+ }, 12000);
+ req.on('error', (error) => finish(error));
+ req.end(body);
+ });
+}
+
+export async function pushProject(target, expected, project) {
+ revisionText(expected, true);
+ const text = JSON.stringify(project);
+ parseProject(text);
+ const body = Buffer.from(text, 'utf8');
+ const headers = expected === '0' ? { 'If-None-Match': '*' } : { 'If-Match': `"${expected}"` };
+ const result = await request(target, 'PUT', body, headers);
+ return result.revision;
+}
+
+export async function pullProject(target) {
+ const result = await request(target, 'GET');
+ const text = new TextDecoder('utf-8', { fatal: true }).decode(result.bytes);
+ const project = parseProject(text);
+ if (project.version !== 2) throw new Error('현재 배치를 포함한 version 2 작업물이 필요합니다.');
+ return { project, revision: result.revision };
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/compiler.mjs b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/compiler.mjs
new file mode 100644
index 0000000..6aec335
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/compiler.mjs
@@ -0,0 +1,496 @@
+// Pure's experimental scalar interaction language. No host code is evaluated.
+const LIMITS = Object.freeze({ sourceBytes: 32768, states: 32, inputs: 8,
+ views: 24, handlers: 64, instructions: 512, depth: 64, stack: 64 });
+const RESERVED = new Set(['frame', 'dt', 'event_x', 'event_y', 'event_value', 'min', 'max', 'clamp']);
+const BINARY = new Map([
+ ['||', [1, 15]], ['&&', [2, 14]], ['==', [3, 12]], ['!=', [3, 13]],
+ ['<', [4, 8]], ['<=', [4, 9]], ['>', [4, 10]], ['>=', [4, 11]],
+ ['+', [5, 3]], ['-', [5, 4]], ['*', [6, 5]], ['/', [6, 6]],
+]);
+const FUNCTIONS = { min: [2, 17], max: [2, 18], clamp: [3, 19] };
+const VIEW_FIELDS = { box: ['x', 'y', 'width', 'height'],
+ circle: ['x', 'y', 'radius'], text: ['x', 'y', 'value'] };
+
+function fail(token, message) {
+ const error = new Error(`${message} (${token.line}:${token.column})`);
+ error.line = token.line;
+ error.column = token.column;
+ throw error;
+}
+
+function lex(source) {
+ const tokens = [];
+ let offset = 0, line = 1, column = 1;
+ const advance = () => {
+ const char = source[offset++];
+ if (char === '\n') { line++; column = 1; } else column++;
+ return char;
+ };
+ while (offset < source.length) {
+ const char = source[offset];
+ if (char === ' ' || char === '\t' || char === '\r') { advance(); continue; }
+ if (char === '#') { while (offset < source.length && source[offset] !== '\n') advance(); continue; }
+ const token = { line, column };
+ if (char === '\n') { advance(); tokens.push({ ...token, kind: 'nl' }); continue; }
+ if (char === '"') {
+ advance();
+ let value = '', closed = false;
+ while (offset < source.length) {
+ const next = advance();
+ if (next === '"') { closed = true; break; }
+ if (next === '\n' || next === '\r') fail(token, 'Strings must fit on one line');
+ if (next === '\\') {
+ const escaped = advance();
+ const escapes = { n: '\n', r: '\r', t: '\t', '"': '"', '\\': '\\' };
+ if (!Object.hasOwn(escapes, escaped)) fail(token, 'Unsupported string escape');
+ value += escapes[escaped];
+ } else value += next;
+ }
+ if (!closed) fail(token, 'Unterminated string');
+ tokens.push({ ...token, kind: 'string', value }); continue;
+ }
+ const remaining = source.slice(offset);
+ const number = remaining.match(/^(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?/);
+ if (number) {
+ const value = Number(number[0]);
+ if (!Number.isFinite(value)) fail(token, 'Number must be finite');
+ for (let i = 0; i < number[0].length; i++) advance();
+ tokens.push({ ...token, kind: 'number', value }); continue;
+ }
+ const name = remaining.match(/^[A-Za-z_][A-Za-z_0-9]*/);
+ if (name) {
+ for (let i = 0; i < name[0].length; i++) advance();
+ tokens.push({ ...token, kind: 'name', value: name[0] }); continue;
+ }
+ const pair = source.slice(offset, offset + 2);
+ if (['<=', '>=', '==', '!=', '&&', '||'].includes(pair)) {
+ advance(); advance(); tokens.push({ ...token, kind: pair }); continue;
+ }
+ if ('=+-*/!<>(){},.;:'.includes(char)) {
+ advance(); tokens.push({ ...token, kind: char }); continue;
+ }
+ fail(token, `Unexpected character ${JSON.stringify(char)}`);
+ }
+ tokens.push({ kind: 'eof', line, column });
+ return tokens;
+}
+
+class Parser {
+ constructor(tokens) { this.tokens = tokens; this.position = 0; this.depth = 0; }
+ peek() { return this.tokens[this.position]; }
+ take() { return this.tokens[this.position++]; }
+ is(kind, value) { return this.peek().kind === kind && (value === undefined || this.peek().value === value); }
+ expect(kind, description = kind) {
+ if (!this.is(kind)) fail(this.peek(), `Expected ${description}`);
+ return this.take();
+ }
+ newlines() { while (this.is('nl')) this.take(); }
+ separators() { while (this.is('nl') || this.is(';')) this.take(); }
+ end() {
+ if (!['nl', ';', '}', 'eof'].includes(this.peek().kind)) fail(this.peek(), 'Expected newline or semicolon');
+ this.separators();
+ }
+ reference(token) {
+ if (!this.is('.')) return token.value;
+ this.take();
+ return `${token.value}.${this.expect('name', 'field name').value}`;
+ }
+ initial() {
+ let sign = 1;
+ if (this.is('-') || this.is('+')) sign = this.take().kind === '-' ? -1 : 1;
+ return sign * this.expect('number', 'numeric state initializer').value;
+ }
+ node(token, properties, children = []) {
+ const depth = 1 + Math.max(0, ...children.map(child => child.depth));
+ if (depth > LIMITS.depth) fail(token, 'Expression nesting exceeds 64');
+ return { token, depth, ...properties };
+ }
+ expression(minimum = 0, multiline = false) {
+ if (++this.depth > LIMITS.depth) fail(this.peek(), 'Expression nesting exceeds 64');
+ if (multiline) this.newlines();
+ const token = this.take();
+ let left;
+ if (token.kind === 'number') left = this.node(token, { kind: 'constant', value: token.value });
+ else if (token.kind === '-' || token.kind === '!') {
+ const child = this.expression(7, multiline);
+ left = this.node(token, { kind: 'unary', op: token.kind === '-' ? 7 : 16, child }, [child]);
+ } else if (token.kind === '(') {
+ left = this.expression(0, true); this.newlines(); this.expect(')');
+ } else if (token.kind === 'name') {
+ if (Object.hasOwn(FUNCTIONS, token.value) && this.is('(')) {
+ this.take();
+ const args = [];
+ this.newlines();
+ if (!this.is(')')) {
+ for (;;) {
+ args.push(this.expression(0, true)); this.newlines();
+ if (!this.is(',')) break;
+ this.take();
+ }
+ }
+ this.expect(')');
+ if (args.length !== FUNCTIONS[token.value][0]) fail(token, `${token.value} expects ${FUNCTIONS[token.value][0]} arguments`);
+ left = this.node(token, { kind: 'call', op: FUNCTIONS[token.value][1], args }, args);
+ } else left = this.node(token, { kind: 'reference', name: this.reference(token) });
+ } else fail(token, 'Expected a number, state, or expression');
+ for (;;) {
+ if (multiline) this.newlines();
+ const entry = BINARY.get(this.peek().kind);
+ if (!entry || entry[0] < minimum) break;
+ const operator = this.take();
+ const right = this.expression(entry[0] + 1, multiline);
+ left = this.node(operator, { kind: 'binary', op: entry[1], left, right }, [left, right]);
+ }
+ this.depth--;
+ return left;
+ }
+ block(depth = 0) {
+ if (depth >= LIMITS.depth) fail(this.peek(), 'Handler nesting exceeds 64');
+ this.newlines(); this.expect('{'); this.separators();
+ const statements = [];
+ while (!this.is('}')) {
+ const token = this.expect('name', 'assignment, if, or closing brace');
+ if (token.value === 'if' && !this.is('=')) {
+ const condition = this.expression();
+ const body = this.block(depth + 1);
+ statements.push({ kind: 'if', token, condition, body });
+ } else {
+ const name = this.reference(token);
+ this.expect('=');
+ statements.push({ kind: 'assign', token, name, expression: this.expression() });
+ }
+ this.end();
+ }
+ this.take();
+ return statements;
+ }
+ parse() {
+ const declarations = [];
+ this.separators();
+ while (!this.is('eof')) {
+ const token = this.expect('name', 'declaration');
+ const kind = token.value;
+ if (kind === 'state') {
+ const name = this.expect('name', 'state name'); this.expect('=');
+ declarations.push({ kind, token, name, initial: this.initial() });
+ } else if (kind === 'record') {
+ const name = this.expect('name', 'record type'); this.newlines(); this.expect('{'); this.separators();
+ const fields = [];
+ while (!this.is('}')) {
+ const field = this.expect('name', 'field name'); this.expect('=');
+ fields.push({name:field, initial:this.initial()}); this.end();
+ }
+ this.take(); declarations.push({kind,token,name,fields});
+ } else if (kind === 'item') {
+ const name = this.expect('name', 'item name'); this.expect('=');
+ const type = this.expect('name', 'record type'); this.expect('('); this.newlines();
+ const fields = [];
+ while (!this.is(')')) {
+ const field = this.expect('name', 'field name'); this.expect('=');
+ fields.push({name:field, initial:this.initial()}); this.newlines();
+ if (!this.is(',')) break;
+ this.take(); this.newlines();
+ }
+ this.expect(')'); declarations.push({kind,token,name,type,fields});
+ } else if (kind === 'rule') {
+ const name = this.expect('name', 'rule name'); this.expect('(');
+ const parameter = this.expect('name', 'record parameter'); this.expect(':');
+ const type = this.expect('name', 'record type'); this.expect(')');
+ declarations.push({kind,token,name,parameter,type,body:this.block()});
+ } else if (kind === 'input') {
+ const name = this.expect('name', 'input name'); this.expect('=');
+ const key = this.expect('name', 'keyboard code or pointer(view)');
+ if (key.value === 'value') {
+ declarations.push({kind,token,name,valueInput:true}); this.end(); continue;
+ }
+ if (key.value === 'pointer') {
+ if (this.is('{')) {
+ this.take(); this.separators(); const routes = [];
+ while (!this.is('}')) {
+ const target = this.expect('name', 'view ID'); this.expect(':');
+ const item = this.expect('name', 'item name'); routes.push({target,item}); this.end();
+ }
+ this.take(); declarations.push({kind,token,name,routes}); this.end(); continue;
+ }
+ this.expect('(');
+ const target = this.expect('name', 'view ID'); this.expect(')');
+ declarations.push({ kind, token, name, target });
+ this.end(); continue;
+ }
+ if (!/^(?:Space|Enter|Arrow(?:Left|Right|Up|Down)|Key[A-Z]|Digit[0-9])$/.test(key.value)) fail(key, 'Unsupported keyboard code');
+ declarations.push({ kind, token, name, key });
+ } else if (Object.hasOwn(VIEW_FIELDS, kind)) {
+ const name = this.expect('name', 'view ID'); this.expect('(');
+ const expressions = [];
+ for (let i = 0; i < VIEW_FIELDS[kind].length; i++) {
+ if (i) { this.newlines(); this.expect(','); }
+ expressions.push(this.expression(0, true));
+ }
+ this.newlines();
+ let color, prefix = '';
+ if (kind !== 'text') {
+ this.expect(','); this.newlines();
+ const value = this.expect('string', 'literal hex color');
+ if (!/^#[0-9a-fA-F]{6}$/.test(value.value)) fail(value, 'Color must use six hexadecimal digits, such as "#356548"');
+ color = value.value;
+ } else if (this.is(',')) { this.take(); this.newlines(); prefix = this.expect('string', 'literal text prefix').value; }
+ this.newlines(); this.expect(')');
+ declarations.push({ kind: 'view', type: kind, token, name, expressions, color, prefix });
+ } else if (kind === 'on') {
+ const event = this.expect('name', 'input name or frame');
+ let edge;
+ if (event.value !== 'frame') {
+ this.expect('.'); edge = this.expect('name', 'down, up, move or cancel');
+ if (!['down', 'up', 'move', 'cancel', 'change'].includes(edge.value)) fail(edge, 'Expected down or up, move, cancel or change');
+ }
+ if (this.is('name', 'use')) {
+ this.take(); const rule = this.expect('name', 'rule name'); this.expect('(');
+ const item = this.expect('name', 'item name or input.target');
+ const argument = this.reference(item); this.expect(')');
+ declarations.push({kind:'handler',token,event,edge,rule,item,argument});
+ } else declarations.push({ kind: 'handler', token, event, edge, body: this.block() });
+ } else fail(token, `Unknown declaration ${kind}`);
+ this.end();
+ }
+ return declarations;
+ }
+}
+
+export function compile(source) {
+ if (typeof source !== 'string') fail({ line: 1, column: 1 }, 'Source must be a string');
+ const sourceBytes = new TextEncoder().encode(source).length;
+ if (sourceBytes > LIMITS.sourceBytes) fail({ line: 1, column: 1 }, 'Source exceeds 32768 UTF-8 bytes');
+ const declarations = new Parser(lex(source)).parse();
+ const program = { states: [], inputs: [], instructions: [], handlers: [], views: [], pointerTargets: [], metrics: {} };
+ const states = new Map(), inputs = new Map(), views = new Set(), keys = new Set(), targets = new Set();
+ const records = new Map(), items = new Map(), rules = new Map();
+ const scalarNames = new Set(declarations.filter(d => d.kind === 'state').map(d => d.name.value));
+ for (const declaration of declarations) {
+ if (!['record','rule'].includes(declaration.kind)) continue;
+ const {name,fields,kind} = declaration, symbols = kind === 'record' ? records : rules;
+ if (RESERVED.has(name.value)) fail(name, `Reserved name ${name.value}`);
+ if (symbols.has(name.value)) fail(name, `Duplicate ${kind} ${name.value}`);
+ if (kind === 'record') {
+ if (!fields.length || fields.length > 8) fail(name, 'A record needs 1..8 fields');
+ const used = new Set();
+ for (const field of fields) {
+ if (used.has(field.name.value)) fail(field.name, `Duplicate field ${field.name.value}`);
+ if (RESERVED.has(field.name.value)) fail(field.name, `Reserved name ${field.name.value}`);
+ used.add(field.name.value);
+ }
+ }
+ symbols.set(name.value, declaration);
+ }
+ let handlerCount = 0;
+ for (const declaration of declarations) {
+ const { kind, name, token } = declaration;
+ if (name && RESERVED.has(name.value)) fail(name, `Reserved name ${name.value}`);
+ if (kind === 'record' || kind === 'rule') continue;
+ if (kind === 'item') {
+ if (items.has(name.value) || scalarNames.has(name.value)) fail(name, `Duplicate state/item ${name.value}`);
+ const record = records.get(declaration.type.value);
+ if (!record) fail(declaration.type, `Unknown record ${declaration.type.value}`);
+ const overrides = new Map();
+ for (const field of declaration.fields) {
+ if (!record.fields.some(f => f.name.value === field.name.value)) fail(field.name, `Unknown field ${field.name.value}`);
+ if (overrides.has(field.name.value)) fail(field.name, `Duplicate field ${field.name.value}`);
+ overrides.set(field.name.value, field.initial);
+ }
+ const base = states.size;
+ for (const field of record.fields) {
+ if (states.size >= LIMITS.states) fail(name, 'At most 32 states are allowed, including item fields');
+ const qualified = `${name.value}.${field.name.value}`, index = states.size;
+ states.set(qualified,index);
+ program.states.push({name:qualified,initial:overrides.has(field.name.value) ? overrides.get(field.name.value) : field.initial,line:token.line});
+ }
+ items.set(name.value,{type:declaration.type.value,base,count:record.fields.length});
+ } else if (kind === 'state' || kind === 'input') {
+ const symbols = kind === 'state' ? states : inputs;
+ if (symbols.has(name.value)) fail(name, `Duplicate ${kind} ${name.value}`);
+ if (symbols.size >= LIMITS[`${kind}s`]) fail(name, `At most ${LIMITS[`${kind}s`]} ${kind}s are allowed`);
+ symbols.set(name.value, symbols.size);
+ if (kind === 'state') program.states.push({ name: name.value, initial: declaration.initial, line: token.line });
+ else if (declaration.valueInput) {
+ program.inputs.push({name:name.value,kind:'value',line:token.line});
+ } else if (declaration.routes) {
+ if (!declaration.routes.length) fail(name, 'A pointer group needs at least one target');
+ program.inputs.push({name:name.value, routes:[], line:token.line});
+ } else if (declaration.target) {
+ const target = declaration.target;
+ if (targets.has(target.value)) fail(target, `Duplicate pointer target ${target.value}`);
+ targets.add(target.value);
+ program.inputs.push({ name: name.value, target: target.value, line: token.line });
+ } else {
+ if (keys.has(declaration.key.value)) fail(declaration.key, `Duplicate keyboard code ${declaration.key.value}`);
+ keys.add(declaration.key.value);
+ program.inputs.push({ name: name.value, key: declaration.key.value, line: token.line });
+ }
+ } else if (kind === 'view') {
+ if (views.has(name.value)) fail(name, `Duplicate view ID ${name.value}`);
+ if (views.size >= LIMITS.views) fail(name, 'At most 24 views are allowed');
+ views.add(name.value);
+ } else if (++handlerCount > LIMITS.handlers) fail(token, 'At most 64 handlers are allowed');
+ }
+ for (const declaration of declarations) {
+ if (declaration.target && !views.has(declaration.target.value))
+ fail(declaration.target, `Unknown pointer target ${declaration.target.value}`);
+ }
+ const routedItems = new Set();
+ for (const declaration of declarations) {
+ if (!declaration.routes) continue;
+ const input = inputs.get(declaration.name.value), resolved = program.inputs[input];
+ let type;
+ for (const {target,item:token} of declaration.routes) {
+ if (!views.has(target.value)) fail(target, `Unknown pointer target ${target.value}`);
+ if (targets.has(target.value)) fail(target, `Duplicate pointer target ${target.value}`);
+ const item = items.get(token.value);
+ if (!item) fail(token, `Unknown item ${token.value}`);
+ if (type && type !== item.type) fail(token, 'Pointer group targets must share one record type');
+ if (routedItems.has(token.value)) fail(token, `Item ${token.value} already has a pointer route`);
+ targets.add(target.value); routedItems.add(token.value); type = item.type;
+ const route = program.pointerTargets.length;
+ if (route >= 24) fail(target, 'At most 24 pointer targets are allowed');
+ program.pointerTargets.push({input,base:item.base,count:item.count});
+ resolved.routes.push({target:target.value, item:token.value, route});
+ }
+ resolved.type = type;
+ }
+ for (const rule of rules.values()) {
+ if (!records.has(rule.type.value)) fail(rule.type, `Unknown record ${rule.type.value}`);
+ if (RESERVED.has(rule.parameter.value)) fail(rule.parameter, `Reserved name ${rule.parameter.value}`);
+ }
+ let pointHandler = false, valueHandler = false;
+ let parameters = null;
+ let parameterPrefix = null;
+ let stack = 0, maxStack = 0;
+ const emit = (op, token, arg = 0, value = 0, delta = 0) => {
+ if (program.instructions.length >= LIMITS.instructions) fail(token, 'At most 512 instructions are allowed');
+ stack += delta;
+ if (stack < 0 || stack > LIMITS.stack) fail(token, 'Expression stack exceeds 64');
+ maxStack = Math.max(maxStack, stack);
+ program.instructions.push({ op, arg, value, line: token.line });
+ };
+ const expression = (node, binding = false) => {
+ const { token } = node;
+ if (node.kind === 'constant') emit(0, token, 0, node.value, 1);
+ else if (node.kind === 'reference') {
+ if (node.name === 'event_value') {
+ if (binding || !valueHandler) fail(token, 'event_value is only available in value change handlers');
+ emit(26, token, 0, 0, 1);
+ } else if (node.name === 'event_x' || node.name === 'event_y') {
+ if (binding || !pointHandler) fail(token, 'event_x and event_y are only available in pointer handlers');
+ emit(node.name === 'event_x' ? 22 : 23, token, 0, 0, 1);
+ } else if (node.name === 'dt') {
+ if (binding) fail(token, 'dt is only available in handlers');
+ emit(2, token, 0, 0, 1);
+ } else {
+ if (parameterPrefix && node.name.startsWith(parameterPrefix) && !parameters.has(node.name))
+ fail(token, `Unknown parameter field ${node.name}`);
+ if (parameters?.has(node.name)) {
+ emit(24, token, parameters.get(node.name), 0, 1);
+ return;
+ }
+ if (!states.has(node.name)) fail(token, `Unknown state ${node.name}`);
+ emit(1, token, states.get(node.name), 0, 1);
+ }
+ } else if (node.kind === 'unary') { expression(node.child, binding); emit(node.op, token); }
+ else if (node.kind === 'binary') {
+ expression(node.left, binding); expression(node.right, binding); emit(node.op, token, 0, 0, -1);
+ } else {
+ for (const arg of node.args) expression(arg, binding);
+ emit(node.op, token, 0, 0, 1 - node.args.length);
+ }
+ };
+ const statements = body => {
+ for (const statement of body) {
+ if (statement.kind === 'assign') {
+ if (parameterPrefix && statement.name.startsWith(parameterPrefix) && !parameters.has(statement.name))
+ fail(statement.token, `Unknown parameter field ${statement.name}`);
+ const parameter = parameters?.get(statement.name);
+ if (parameter === undefined && !states.has(statement.name)) fail(statement.token, `Unknown state ${statement.name}`);
+ expression(statement.expression);
+ emit(parameter === undefined ? 20 : 25, statement.token, parameter === undefined ? states.get(statement.name) : parameter, 0, -1);
+ } else {
+ expression(statement.condition);
+ const branch = program.instructions.length;
+ emit(21, statement.token, 0, 0, -1);
+ statements(statement.body);
+ program.instructions[branch].arg = program.instructions.length;
+ }
+ }
+ };
+ const bodies = new Map();
+ function ruleBody(rule) {
+ if (bodies.has(rule.name.value)) return bodies.get(rule.name.value);
+ parameterPrefix = `${rule.parameter.value}.`;
+ parameters = new Map(records.get(rule.type.value).fields.map((field,index) => [`${rule.parameter.value}.${field.name.value}`,index]));
+ // A shared body may read coordinates; every binding is checked below.
+ pointHandler = true; valueHandler = true; stack = 0;
+ const start = program.instructions.length;
+ statements(rule.body);
+ const length = program.instructions.length - start;
+ const point = program.instructions.slice(start).some(op => op.op === 22 || op.op === 23);
+ parameters = null; parameterPrefix = null;
+ const value = program.instructions.slice(start).some(op => op.op === 26);
+ const body = {start,length,point,value}; bodies.set(rule.name.value,body); return body;
+ }
+ for (const declaration of declarations) {
+ if (declaration.kind === 'handler') {
+ let event = 0;
+ pointHandler = false; valueHandler = false;
+ if (declaration.event.value !== 'frame') {
+ if (!inputs.has(declaration.event.value)) fail(declaration.event, `Unknown input ${declaration.event.value}`);
+ const index = inputs.get(declaration.event.value), edge = declaration.edge.value;
+ pointHandler = Boolean(program.inputs[index].target || program.inputs[index].routes);
+ valueHandler = program.inputs[index].kind === 'value';
+ if (valueHandler !== (edge === 'change')) fail(declaration.edge, 'Value inputs require change; change requires a value input');
+ if (!pointHandler && (edge === 'move' || edge === 'cancel')) fail(declaration.edge, 'move and cancel require a pointer input');
+ event = edge === 'change' ? 33 + index : edge === 'move' ? 17 + index : edge === 'cancel' ? 25 + index : 1 + index * 2 + (edge === 'up' ? 1 : 0);
+ }
+ if (declaration.rule) {
+ const rule = rules.get(declaration.rule.value);
+ const routed = declaration.argument.includes('.');
+ const input = program.inputs[inputs.get(declaration.event.value)];
+ if (routed && (!input?.routes || declaration.argument !== `${declaration.event.value}.target`))
+ fail(declaration.item, 'Use the current pointer group target');
+ const item = routed ? {type:input.type, count:records.get(input.type).fields.length} : items.get(declaration.item.value);
+ if (!rule) fail(declaration.rule, `Unknown rule ${declaration.rule.value}`);
+ if (!item) fail(declaration.item, `Unknown item ${declaration.item.value}`);
+ if (item.type !== rule.type.value) fail(declaration.item, `Rule ${rule.name.value} requires ${rule.type.value}`);
+ const pointer = pointHandler, value = valueHandler;
+ const body = ruleBody(rule);
+ if (body.value && !value) fail(declaration.rule, 'Value-reading rules require a value input');
+ if (body.point && !pointer) fail(declaration.rule, 'Coordinate-reading rules require a pointer input');
+ program.handlers.push({event,start:body.start,length:body.length,line:declaration.token.line,parameterBase:routed ? 255 : item.base,parameterCount:item.count});
+ } else {
+ const start = program.instructions.length;
+ stack = 0; statements(declaration.body);
+ program.handlers.push({ event, start, length: program.instructions.length - start, line: declaration.token.line });
+ }
+ } else if (declaration.kind === 'view') {
+ const view = { id: declaration.name.value, type: declaration.type, line: declaration.token.line, bindings: {} };
+ if (view.type === 'text') view.prefix = declaration.prefix;
+ else view.color = declaration.color;
+ declaration.expressions.forEach((node, index) => {
+ const start = program.instructions.length;
+ stack = 0; expression(node, true);
+ view.bindings[VIEW_FIELDS[view.type][index]] = { start, length: program.instructions.length - start };
+ });
+ program.views.push(view);
+ }
+ }
+ // Unused definitions still receive name/type checking, but reserve no VM body.
+ for (const rule of rules.values()) {
+ if (bodies.has(rule.name.value)) continue;
+ const instructions = program.instructions, previousMax = maxStack;
+ program.instructions = [];
+ ruleBody(rule);
+ program.instructions = instructions; maxStack = previousMax;
+ }
+ program.metrics = { sourceBytes, sourceLines: source === '' ? 0 : source.split('\n').length,
+ states: states.size, inputs: inputs.size, views: views.size,
+ handlers: program.handlers.length, instructions: program.instructions.length, maxStack };
+ return program;
+}
+
+export { LIMITS };
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/core.wasm b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/core.wasm
new file mode 100644
index 0000000..79c50a8
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/core.wasm
Binary files differ
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/project.mjs b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/project.mjs
new file mode 100644
index 0000000..861e0fc
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/project.mjs
@@ -0,0 +1,47 @@
+import { compile } from './compiler.mjs';
+
+// Two escaped source strings plus up to 32 generated item.field names. A long
+// schema field can appear in every item without repeating in the source text.
+export const MAX_PROJECT_BYTES = (2 * 6 + 32) * 32768 + 8192;
+const encoder = new TextEncoder();
+function sourceText(value, label) {
+ if (typeof value !== 'string' || encoder.encode(value).length > 32768)
+ throw new Error(`${label}: UTF-8 32 KiB 이하의 코드가 필요합니다.`);
+ return value;
+}
+
+// No runtime mutation. Validate every saved value before opening core staging.
+export function validateDocument(document) {
+ if (!document || typeof document !== 'object' || Array.isArray(document) ||
+ document.format !== 'pure-workbench' || document.version !== 2)
+ throw new Error('배치 파일 형식이 맞지 않습니다. pure-workbench version 2가 필요합니다.');
+ const source = sourceText(document.source, '적용된 코드');
+ const draft = sourceText(Object.hasOwn(document, 'draft') ? document.draft : source, '편집 중인 코드');
+ const program = compile(source);
+ if (!Array.isArray(document.states) || document.states.length !== program.states.length)
+ throw new Error('저장된 상태 목록이 적용된 코드와 일치하지 않습니다.');
+ const values = new Map();
+ for (const entry of document.states) {
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry) || typeof entry.name !== 'string' || values.has(entry.name))
+ throw new Error('상태 이름이 잘못됐거나 중복됐습니다.');
+ const value = entry.value === '-0' ? -0 : entry.value;
+ if (typeof value !== 'number' || !Number.isFinite(value)) throw new Error('상태 값은 유한한 숫자여야 합니다.');
+ values.set(entry.name, value);
+ }
+ for (const state of program.states)
+ if (!values.has(state.name)) throw new Error(`저장된 상태가 없습니다: ${state.name}`);
+ return { source, draft, program, values: program.states.map(state => values.get(state.name)) };
+}
+
+export function parseProject(text) {
+ if (typeof text !== 'string' || encoder.encode(text).length > MAX_PROJECT_BYTES)
+ throw new Error('작업 파일이 너무 큽니다.');
+ let project;
+ try { project = JSON.parse(text); } catch { throw new Error('올바른 JSON 파일이 아닙니다.'); }
+ if (!project || typeof project !== 'object' || Array.isArray(project) || project.format !== 'pure-workbench')
+ throw new Error('Pure 작업물 형식이 아닙니다.');
+ if (project.version === 1) sourceText(project.source, '코드');
+ else if (project.version === 2) validateDocument(project);
+ else throw new Error('지원하지 않는 작업 파일 버전입니다.');
+ return project;
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/runtime.mjs b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/runtime.mjs
new file mode 100644
index 0000000..d8d6618
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/sources/prototypes/workbench/web/runtime.mjs
@@ -0,0 +1,350 @@
+import { compile } from './compiler.mjs';
+import { validateDocument } from './project.mjs';
+
+const messages = [
+ '', '실행기의 용량 한도를 넘었습니다.', '실행 정의가 유효하지 않습니다.',
+ '계산 스택의 범위를 벗어났습니다.', '0으로 나눌 수 없습니다.',
+ '계산 결과가 유한한 수의 범위를 벗어났습니다.', '조건 분기 범위가 유효하지 않습니다.',
+ '존재하지 않는 상태를 참조했습니다.', '시간 간격이 유효하지 않습니다.',
+ '정의되지 않은 입력 사건입니다.',
+];
+const sourceLimit = 32768;
+
+function problem(message, line = null, column = null) {
+ return Object.assign(new Error(message), { line, column });
+}
+
+function freezeProgram(value) {
+ if (value && typeof value === 'object') {
+ for (const child of Object.values(value)) freezeProgram(child);
+ Object.freeze(value);
+ }
+ return value;
+}
+
+export async function createRuntime(wasmBytes, evaluationOptions = {}) {
+ if (wasmBytes === undefined) {
+ const response = await fetch(new URL('./core.wasm', import.meta.url), { cache: 'no-store' });
+ if (!response.ok) throw new Error(`실행기를 불러오지 못했습니다 (HTTP ${response.status}).`);
+ wasmBytes = await response.arrayBuffer();
+ }
+ const module = await WebAssembly.compile(wasmBytes);
+ if (WebAssembly.Module.imports(module).length) throw new Error('이 실행기는 호스트 함수 없이 동작해야 합니다.');
+ const { exports: core } = await WebAssembly.instantiate(module, {});
+ if (typeof core.eval_bounded !== 'function' || typeof core.abort_program !== 'function' || typeof core.dispatch_point !== 'function' || typeof core.put_restored_value !== 'function' || typeof core.commit_restored_program !== 'function' || typeof core.bind_handler !== 'function' || typeof core.put_pointer_target !== 'function' || typeof core.bind_target_handler !== 'function' || typeof core.dispatch_target !== 'function' || typeof core.dispatch_value !== 'function')
+ throw new Error('실행기 버전이 맞지 않습니다. 새로고침하거나 core.wasm을 다시 빌드하세요.');
+ core.reset_all();
+ let program = null;
+ let appliedSource = '';
+ let lastEvent = null;
+ // Keep a failed event visible through its release/focus-loss cleanup.
+ // The active program can clear this diagnostic by apply or explicit reset.
+ let lastFailure = null;
+ const held = new Map();
+ const points = new Map();
+ let presenting = false;
+ let bindings = [];
+ let pointRoutes = new Map();
+ // One bounded publication buffer, never exposed to callers. No state mirror.
+ let displayValues = null, displayValid = null;
+ function available() {
+ if (presenting) throw new Error('출력 전달 중에는 실행기를 다시 호출할 수 없습니다.');
+ }
+ let evaluationPolicy = { cacheEntries: 0, historyEntries: 8, workLimit: 2048 };
+
+ function checked(code, line = null) {
+ if (code !== 0) throw problem(messages[code] || `실행기 오류 ${code}`, line);
+ }
+ function inputIndex(name) {
+ const index = program?.inputs.findIndex((input) => input.name === name) ?? -1;
+ if (index < 0) throw new Error(`정의되지 않은 입력: ${name}`);
+ return index;
+ }
+ function dispatch(event, name, phase, source, point = null, value = undefined) {
+ const status = value !== undefined ? core.dispatch_value(event, value) : point ? (point.route === undefined ? core.dispatch_point(event, point.x, point.y)
+ : core.dispatch_target(event, point.route, point.x, point.y)) : core.dispatch(event, event === 0 ? 1 / 60 : 0);
+ const pc = core.info(2) >>> 0;
+ lastEvent = { name, phase, source, status,
+ line: program?.instructions[pc]?.line ?? null, ops: core.info(3) >>> 0 };
+ if (point) { lastEvent.x = point.x; lastEvent.y = point.y; if (point.target) lastEvent.target = point.target; }
+ if (value !== undefined) lastEvent.value = value;
+ if (status) lastFailure = { ...lastEvent };
+ return status;
+ }
+
+ function evaluateDisplay() {
+ core.begin_evaluation(evaluationPolicy.workLimit);
+ if (!bindings.length) return null;
+ displayValues ??= new Float64Array(96);
+ displayValid ??= new Uint8Array(24);
+ let error = null, slot = 0;
+ for (let i = 0; i < bindings.length; i++) {
+ const view = program.views[i];
+ displayValid[i] = 1;
+ for (const [name, binding] of bindings[i]) {
+ const value = core.eval_bounded(binding.start, binding.length);
+ if (core.evaluation_info(0) === 10) {
+ displayValid.fill(0);
+ return { code: 101, line: view.line,
+ message: '표시 계산의 작업량 한도를 넘었습니다. 한도를 늘리거나 표시식을 줄이세요.' };
+ }
+ if (!Number.isFinite(value) || ((name === 'width' || name === 'height' || name === 'radius') && value < 0)) {
+ error ??= { line: view.line, message: `${view.id}.${name}: 표시할 수 없는 값입니다. 0 나눗셈이나 음수 크기를 확인하세요.` };
+ displayValid[i] = 0;
+ }
+ displayValues[slot++] = value;
+ }
+ }
+ return error;
+ }
+
+ function status(viewError) {
+ const executionError = lastFailure?.status || 0;
+ return {
+ tick: core.info(0) >>> 0, revision: core.info(4) >>> 0,
+ displayError: viewError ? { code: viewError.code || 100, ...viewError } : null,
+ lastError: executionError || (viewError ? viewError.code || 100 : 0),
+ errorMessage: executionError ? messages[executionError] || `실행 오류 ${executionError}` : viewError?.message || '',
+ errorLine: executionError ? lastFailure.line : viewError?.line ?? null,
+ lastOps: core.info(3) >>> 0, successfulEvents: core.info(9) >>> 0,
+ held: [...held.keys()], lastEvent: lastEvent ? { ...lastEvent } : null,
+ lastFailure: lastFailure ? { ...lastFailure } : null,
+ memory: {
+ linearBytes: core.memory.buffer.byteLength,
+ reservedEngineBytes: core.layout(0), programReservedBytes: core.layout(1),
+ instructionBytes: core.layout(2), handlerBytes: core.layout(3),
+ activeIRBytes: core.layout(4), activeStateBytes: core.layout(5),
+ stagingReservedBytes: core.layout(6), evalStackBytes: core.layout(7),
+ pointerTargetBytes: core.layout(8), pointerTargets: core.layout(9),
+ },
+ };
+ }
+
+ function load(next, source, restored = null) {
+ const oldIds = new Map(restored ? [] : program?.states.map((state, index) => [state.name, index]) ?? []);
+ checked(core.begin_program(next.states.length, next.inputs.length));
+ try {
+ for (let index = 0; index < next.states.length; index++) {
+ const state = next.states[index];
+ checked(core.put_state(index, state.initial, oldIds.get(state.name) ?? -1), state.line);
+ if (restored) checked(core.put_restored_value(index, restored[index]), state.line);
+ }
+ for (const op of next.instructions) checked(core.put_instruction(op.op, op.arg, op.value), op.line);
+ for (const target of next.pointerTargets) checked(core.put_pointer_target(target.input, target.base, target.count));
+ for (const [index, handler] of next.handlers.entries()) {
+ checked(core.put_handler(handler.event, handler.start, handler.length), handler.line);
+ if (handler.parameterCount)
+ checked(handler.parameterBase === 255 ? core.bind_target_handler(index, handler.parameterCount)
+ : core.bind_handler(index, handler.parameterBase, handler.parameterCount), handler.line);
+ }
+ checked(restored ? core.commit_restored_program() : core.commit_program());
+ } catch (error) {
+ core.abort_program();
+ throw error;
+ }
+ pointRoutes = new Map(next.inputs.flatMap(input => (input.routes ?? []).map(route => [route.target, route])));
+ program = next;
+ bindings = next.views.map(view => Object.entries(view.bindings));
+ appliedSource = source;
+ lastEvent = null;
+ lastFailure = null;
+ }
+
+ const api = {
+ get currentProgram() { return program; },
+ configureEvaluation({ cacheEntries = evaluationPolicy.cacheEntries,
+ historyEntries = evaluationPolicy.historyEntries, workLimit = evaluationPolicy.workLimit } = {}) {
+ available();
+ for (const [name, value, maximum] of [['cacheEntries', cacheEntries, 32],
+ ['historyEntries', historyEntries, 8], ['workLimit', workLimit, 0xffffffff]]) {
+ if (!Number.isInteger(value) || value < 0 || value > maximum)
+ throw new Error(`${name}: 0~${maximum} 사이의 정수여야 합니다.`);
+ }
+ checked(core.configure_evaluation(cacheEntries, historyEntries));
+ evaluationPolicy = { cacheEntries, historyEntries, workLimit };
+ return { ...evaluationPolicy };
+ },
+ forgetEvaluation(part = 'all') {
+ available();
+ const flags = part === 'all' ? 3 : part === 'values' ? 1 : part === 'history' ? 2 : undefined;
+ if (flags === undefined) throw new Error('삭제할 기록은 values, history, all 중 하나여야 합니다.');
+ core.forget_evaluation(flags);
+ },
+ evaluationStats() {
+ return { ...evaluationPolicy, work: core.evaluation_info(1),
+ instructions: core.evaluation_info(2), cacheHits: core.evaluation_info(3),
+ reservedBytes: core.evaluation_info(6), dedicatedBytes: core.evaluation_info(7),
+ sharedBytes: core.evaluation_info(8), reuseAvailable: Boolean(core.evaluation_info(9)),
+ workspaceTagBytes: core.evaluation_info(10) };
+ },
+ apply(source) {
+ available();
+ if (typeof source !== 'string' || new TextEncoder().encode(source).length > sourceLimit) {
+ throw problem('정의는 UTF-8 기준 32,768바이트 이하의 텍스트여야 합니다.');
+ }
+ if (held.size) throw problem('누르고 있는 입력을 놓은 뒤 적용하세요. 현재 작업은 그대로 유지합니다.');
+ const next = freezeProgram(compile(source));
+ load(next, source);
+ return next;
+ },
+ restoreDocument(document) {
+ available();
+ if (held.size) throw problem('누르고 있는 입력을 놓은 뒤 복원하세요.');
+ const next = validateDocument(document);
+ load(freezeProgram(next.program), next.source, next.values);
+ return { source: next.source, draft: next.draft };
+ },
+ exportDocument(draft = appliedSource) {
+ available();
+ if (!program) throw problem('먼저 코드를 적용하세요.');
+ if (held.size) throw problem('조작을 끝낸 뒤 배치를 저장하세요.');
+ if (lastFailure) throw problem('실행 오류를 해결한 뒤 배치를 저장하세요.');
+ if (typeof draft !== 'string' || new TextEncoder().encode(draft).length > sourceLimit)
+ throw problem('편집 중인 코드는 UTF-8 32 KiB 이하여야 합니다.');
+ return { format: 'pure-workbench', version: 2, source: appliedSource, draft,
+ states: program.states.map((state, i) => {
+ const value = core.get_state(i);
+ return { name: state.name, value: Object.is(value, -0) ? '-0' : value };
+ }) };
+ },
+ reset() {
+ available();
+ held.clear();
+ points.clear();
+ core.reset_state();
+ lastEvent = null;
+ lastFailure = null;
+ },
+ frame(count = 1) {
+ available();
+ if (!Number.isInteger(count) || count < 0 || count > 600) throw new Error('프레임 수는 0~600 사이의 정수여야 합니다.');
+ if (!program) return 0;
+ for (let i = 0; i < count; i++) {
+ const code = dispatch(0, 'frame', 'frame', 'clock');
+ if (code !== 0) return code;
+ }
+ return 0;
+ },
+ down(name, source = 'external') {
+ available();
+ const index = inputIndex(name);
+ if (program.inputs[index].kind === 'value') throw new Error('숫자 입력은 change(name, value)를 사용하세요.');
+ if (program.inputs[index].target || program.inputs[index].routes) throw new Error('좌표 입력은 point(name, phase, x, y)를 사용하세요.');
+ const sources = held.get(name) || new Set();
+ if (sources.has(source)) return 0;
+ const wasDown = sources.size > 0;
+ sources.add(source);
+ held.set(name, sources);
+ return wasDown ? 0 : dispatch(1 + index * 2, name, 'down', source);
+ },
+ up(name, source = 'external') {
+ available();
+ const index = inputIndex(name);
+ if (program.inputs[index].kind === 'value') throw new Error('숫자 입력은 change(name, value)를 사용하세요.');
+ if (program.inputs[index].target || program.inputs[index].routes) throw new Error('좌표 입력은 point(name, phase, x, y)를 사용하세요.');
+ const sources = held.get(name);
+ if (!sources?.delete(source)) return 0;
+ if (sources.size) return 0;
+ held.delete(name);
+ return dispatch(2 + index * 2, name, 'up', source);
+ },
+ change(name, value, source = 'external') {
+ available();
+ const index = inputIndex(name);
+ if (program.inputs[index].kind !== 'value') throw new Error('숫자 값에 연결된 입력이 아닙니다.');
+ if (!Number.isFinite(value)) throw new Error('입력 값은 유한한 숫자여야 합니다.');
+ return dispatch(33 + index, name, 'change', source, null, value);
+ },
+ point(name, phase, x, y, source = 'external', target = undefined) {
+ available();
+ const index = inputIndex(name);
+ const input = program.inputs[index];
+ if (!input.target && !input.routes) throw new Error('포인터에 연결된 입력이 아닙니다.');
+ const route = input.routes ? pointRoutes.get(target) : undefined;
+ if (input.routes && (!route || program.pointerTargets[route.route].input !== index)) throw new Error('포인터 그룹에 연결된 도형 이름이 필요합니다.');
+ if (!input.routes && target !== undefined) throw new Error('단일 포인터 입력에는 대상 인자를 지정하지 않습니다.');
+ const owner = route ? `${name}:${target}` : name;
+ if (!['down', 'move', 'up', 'cancel'].includes(phase)) throw new Error('포인터 단계는 down, move, up, cancel 중 하나여야 합니다.');
+ if (!Number.isFinite(x) || !Number.isFinite(y)) throw new Error('포인터 좌표는 유한한 숫자여야 합니다.');
+ if (typeof source !== 'string' || source.length === 0) throw new Error('포인터 출처 이름이 필요합니다.');
+ let point = points.get(owner);
+ if (phase === 'down') {
+ if (point?.source === source) return 0;
+ if (point) throw new Error('이 입력은 다른 포인터가 사용 중입니다.');
+ point = {name, source, x, y, target, route:route?.route};
+ points.set(owner, point);
+ held.set(owner, new Set([source]));
+ } else {
+ if (!point || point.source !== source) return 0;
+ point.x = x; point.y = y;
+ if (phase === 'up' || phase === 'cancel') { points.delete(owner); held.delete(owner); }
+ }
+ const event = phase === 'move' ? 17 + index : phase === 'cancel' ? 25 + index : 1 + index * 2 + (phase === 'up' ? 1 : 0);
+ return dispatch(event, name, phase, source, point);
+ },
+ releaseAll() {
+ available();
+ let firstError = 0;
+ for (const point of [...points.values()]) {
+ const status = api.point(point.name, 'cancel', point.x, point.y, point.source, point.target);
+ if (!firstError) firstError = status;
+ }
+ for (const [name, sources] of [...held]) {
+ for (const source of [...sources]) {
+ const status = api.up(name, source);
+ if (!firstError) firstError = status;
+ }
+ }
+ return firstError;
+ },
+ exportProject() {
+ return { format: 'pure-workbench', version: 1, source: appliedSource };
+ },
+ // Synchronous trusted output adapter. Callbacks run only after the whole
+ // display has been evaluated. Runtime mutation/reentrant reads are refused.
+ // Exceptions from an adapter propagate; the next call republishes all values.
+ present(target) {
+ available();
+ presenting = true;
+ try {
+ const { begin, state, view, value, end } = target;
+ for (const callback of [begin, state, view, value, end])
+ if (typeof callback !== 'function') throw new TypeError('출력 어댑터 함수가 필요합니다.');
+ const error = evaluateDisplay();
+ begin.call(target, program);
+ for (let i = 0; i < (program?.states.length ?? 0); i++) state.call(target, i, core.get_state(i));
+ let slot = 0, visible = 0;
+ for (let i = 0; i < bindings.length; i++) {
+ const valid = Boolean(displayValid[i]);
+ view.call(target, i, valid);
+ for (const [name] of bindings[i]) {
+ if (valid) value.call(target, i, name, displayValues[slot]);
+ slot++;
+ }
+ if (valid) visible++;
+ }
+ end.call(target, visible);
+ return status(error);
+ } finally { presenting = false; }
+ },
+ snapshot() {
+ available();
+ const error = evaluateDisplay();
+ const states = Object.fromEntries((program?.states ?? []).map((state, index) => [state.name, core.get_state(index)]));
+ const views = [];
+ let slot = 0;
+ for (let i = 0; i < bindings.length; i++) {
+ const view = program.views[i];
+ const rendered = displayValid[i] ? { id: view.id, type: view.type, color: view.color, prefix: view.prefix } : null;
+ for (const [name] of bindings[i]) {
+ if (rendered) rendered[name] = displayValues[slot];
+ slot++;
+ }
+ if (rendered) views.push(rendered);
+ }
+ return { states, views, ...status(error) };
+ },
+ };
+ api.configureEvaluation(evaluationOptions);
+ return Object.freeze(api);
+}
diff --git a/prototypes/connections/results/2026-09-23-document-edits/verification.json b/prototypes/connections/results/2026-09-23-document-edits/verification.json
new file mode 100644
index 0000000..598aed9
--- /dev/null
+++ b/prototypes/connections/results/2026-09-23-document-edits/verification.json
@@ -0,0 +1,32 @@
+{
+ "sources_verified_and_frozen": 37,
+ "native_and_sanitized_source_hashes_match": true,
+ "recorded_binaries_verified": 8,
+ "integration_scenarios_per_build": 36,
+ "server_runs_per_build": 19,
+ "all_server_runs_drained": true,
+ "compiler": "cc (Debian 14.2.0-19) 14.2.0",
+ "core_sections": {
+ "text": 5932,
+ "data": 0,
+ "bss": 0
+ },
+ "structure_sizes": {
+ "domain_bytes": 200,
+ "work_slot_bytes": 224,
+ "ticket_bytes": 24,
+ "prepared_program_bytes": 680,
+ "pointer_bytes": 8
+ },
+ "core_external_symbols": [
+ "memcpy",
+ "strlen"
+ ],
+ "server_structure_bytes": [41528],
+ "limitations": [
+ "synchronous full-file rewrite with 4096-byte host scratch",
+ "11-byte credit test does not measure total memory",
+ "limited storage authoring profile, no native GUI or secure peer RPC",
+ "GNU footprint tooling validated on Linux AArch64; macOS unverified"
+ ]
+}