<feed xmlns='http://www.w3.org/2005/Atom'>
<title>pure/prototypes/connections/Makefile, branch master</title>
<subtitle>Verified execution runtime unifying state, persistence, and replication.
</subtitle>
<id>http://git.yeowoo.org/pure/atom?h=master</id>
<link rel='self' href='http://git.yeowoo.org/pure/atom?h=master'/>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/'/>
<updated>2026-09-27T12:14:38Z</updated>
<entry>
<title>Lay Pure out as a core with the parts selected around it</title>
<updated>2026-09-27T12:14:38Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-27T12:14:38Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=37d3a1e152707d2da587440c4cea8601b9ef0fd2'/>
<id>urn:sha1:37d3a1e152707d2da587440c4cea8601b9ef0fd2</id>
<content type='text'>
The app model, the tree store and the HTTP host lived in
prototypes/connections among the earlier document runtime, the store was
known only by its format's name, and Vega compiled six Pure sources by path.
Now, as the README's principle has it:

  core/   runtime, flow and the app model (module*.c), with what the core
          asks of storage (state.h, store.h)
  store/  the tree store (PURETRE3, PUREREC1)
  serve/  pure-serve: HTTP host, outbound delivery, JSON in place
  cli/    pure-run, pure-edit-module

A top-level make builds libpure.a (app model and store, for hosts to link)
and the hosts; make check runs the store's and the app model's tests. The
earlier runtime still builds from prototypes/connections against core/ and
store/ (check, check-tree and check-core pass). Design 009 records the rule:
parts by role behind libraries; git repositories split by coupling, so the
store stays here while its contract moves with the core, and Vega stays apart.

</content>
</entry>
<entry>
<title>Read JSON messages in message-json.c, for requests and answers alike</title>
<updated>2026-09-27T07:15:05Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-27T07:15:05Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=25397ebb79fb554f4fa795603ee84d2aede83594'/>
<id>urn:sha1:25397ebb79fb554f4fa795603ee84d2aede83594</id>
<content type='text'>
The in-place JSON reader of pure-serve's request bodies moves into its
own file with a small interface (pure_json_message, pure_json_fixed,
pure_json_space), so the delivery client can read an API's answers
with it. It gains a lenient mode for answers: a member that names no
field is skipped, value and all. Requests read as before.

</content>
</entry>
<entry>
<title>Deliver to https receivers, verifying their certificates (083)</title>
<updated>2026-09-27T07:12:23Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-27T07:12:23Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=24a07a0bbfe98924b339f4ffeeaef093e74f73fb'/>
<id>urn:sha1:24a07a0bbfe98924b339f4ffeeaef093e74f73fb</id>
<content type='text'>
A wire to an https:// URL speaks TLS 1.2 or later through OpenSSL: the
receiver's certificate must chain to the system's CAs (or to the file
--send-ca names) and name its host (SNI and SSL_set1_host, or the IP
address). An untrusted receiver gets nothing: the send stays in the
outbox, the wire logs it and tries again every 10 s. pure-serve now
links libssl and libcrypto.

</content>
</entry>
<entry>
<title>Deliver an app's saved sends over HTTP, in order and in batches (083)</title>
<updated>2026-09-27T07:09:40Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-27T07:09:40Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=5d3a7cefa27f3fe20a9c6991fb044815b38aac01'/>
<id>urn:sha1:5d3a7cefa27f3fe20a9c6991fb044815b38aac01</id>
<content type='text'>
pure-serve --send OUTPUT=http://host:port/path wires an output: after
every save the owner queues the new sends as JSON (fields and groups)
and a thread per output posts them in order with X-Pure-Source,
X-Pure-Sequence and Idempotency-Key. A 2xx, or a Pure receiver's
refusal, delivers; the owner then trims. 408, 429, 5xx and no answer
are sent again after a pause growing to 10 s, other answers every 10 s:
nothing is dropped. A Pure receiver applies a delivered message with
pure_app_deliver (now taking placed fields) and advertises
X-Pure-Batch: 256; the sender then posts up to that many numbers in a
row as one JSON array (X-Pure-Count), applied in order in one burst
with one save.

Delivery kept up with orders once batched (391 deliveries/s one at a
time; a backlog of 20,000 went at 60k/s). With four clients ordering,
killing the receiver and then the sender (-9) left the receiver's count
and total equal to what the sender saved, five times and under ASan.

</content>
</entry>
<entry>
<title>Snapshot an app's saved states for readers on other threads</title>
<updated>2026-09-26T21:56:32Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-26T21:56:32Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=42021a500d19dbe091075338d1a621498a81f167'/>
<id>urn:sha1:42021a500d19dbe091075338d1a621498a81f167</id>
<content type='text'>
Right after a save, pure_app_snapshot makes a read-only snapshot of the
saved states: numbers are copied, text states are frozen drafts that
share the store mapping (pure_draft_freeze, no copy), and lists are
copies of their item pointers that share the items. An unchanged list
shares the last snapshot's copy. pure_app_read binds a reader app on
another thread to a snapshot so the existing view functions read it.

A shared item never changes again: a list stamps each item with its
share count, copies a shared item it changes, and retires shared items
it lets go instead of freeing them. Snapshots form a chain that goes
oldest first, and items retired while a snapshot was the newest go
with it. References are atomic and may be released on any thread.

test-module checks that each snapshot equals the app, that kept
snapshots stay as made through changes, removals, a module switch, the
app stopping and the store closing, that a failed save's snapshot
equals the one before, and that two threads read the newest snapshots
while the app goes on (also under ASan, UBSan and LeakSanitizer).

</content>
</entry>
<entry>
<title>Rebuild module hosts when the executor or store changes</title>
<updated>2026-09-26T06:12:17Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-26T06:12:17Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=d6c67de580fb7ec2b75ec73a14a7cbb551b93099'/>
<id>urn:sha1:d6c67de580fb7ec2b75ec73a14a7cbb551b93099</id>
<content type='text'>
MODULE and MODULE_HEADERS were defined below the pure-serve rule, and a
rule's prerequisites expand when make reads it, so pure-serve depended on
neither: changing the store or the executor left a stale server behind.
Define them before any rule names them.

</content>
</entry>
<entry>
<title>Serve modules over persistent connections</title>
<updated>2026-09-26T04:40:20Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-26T04:40:20Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=7771461a93f993425f97d4e05c91e64d17179e60'/>
<id>urn:sha1:7771461a93f993425f97d4e05c91e64d17179e60</id>
<content type='text'>
pure-serve replaces the module mode of server.c, which goes back to what
it was. It keeps the document contract, the runtime core (a work slot per
connection, the payload budget, core-owned ingress, borrowed PUT replies)
and the group commits, and adds what server.c lacked: HTTP/1.1 persistent
connections with in-order pipelining, an edge-triggered epoll owner
thread, up to 1,024 connections allocated as they arrive and reused, one
writev per answer, and documents opened through a store handle.

On the Pi 5 with one thread it serves 106k small keep-alive reads per
second (axum on three cores: 126k) at the same p99, 1,741 1 MiB reads
(axum: 1,370), and 1,126 durable writes from 64 connections (crash-safe
axum: 372), in 7.3 MiB against axum's 17-20 MiB. Note 075 has the table.

</content>
</entry>
<entry>
<title>Serve modules through the runtime core with group commits</title>
<updated>2026-09-26T03:53:55Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-26T03:53:55Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=3b89ae82ea9468d54c60a63fd03b9a829748a0ac'/>
<id>urn:sha1:3b89ae82ea9468d54c60a63fd03b9a829748a0ac</id>
<content type='text'>
pure-connections-module offers the document server's HTTP contract with an
aup module: GET is its show message and PUT its edit message. Requests go
through the runtime core as before (work slots, payload budget, ingress,
replies borrowed from the request), and effects are taken on the owner
thread with the core's asynchronous interface.

Each poll round is one burst: every ready request is applied to the app
with deferred saving, one save stores them, and only then are the tickets
completed and answered. A failed save fails the whole burst, reads too. A
key seen again ends the burst first, and the module server accepts every
waiting connection at once so concurrent requests share a burst. On the
Pi's SD card eight clients' 240 edits take 0.59 s instead of 2.14 s.

</content>
</entry>
<entry>
<title>Keep app states in the tree store</title>
<updated>2026-09-25T14:49:48Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-25T14:49:48Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=18675f3e45fa0896efd777bf66ad0ec4c8157d36'/>
<id>urn:sha1:18675f3e45fa0896efd777bf66ad0ec4c8157d36</id>
<content type='text'>
When the data host keeps states (PureData.state and .save, implemented by
pure_tree_data), every state of an app lives in the store: a text state's
draft is its stored value, a list mirrors each change into a stored draft
(record header, then items), and numbers, cursors and indices are stored
together by name. An app starts from what is stored, moves list fields by
name when a record changed, resets cursors and indices that no longer fit,
and refuses damaged stored values.

Each key, text and message event publishes the states it changed together
with the message's document in one store commit, or fails and leaves
memory and store as they were. Frame changes go with the next event or
pure_app_save. pure-run takes --store PATH.

Tests run the same random events on an app in memory and on a stored app
that restarts every few events and require equal states after every step;
kill a process at every commit stage of an event that changes a number, a
text and a list; and check frames, message atomicity and migration by
restart and by replacement. A stored event costs about 10.6 ms more on the
Pi's SD card, mostly two fsyncs.

</content>
</entry>
<entry>
<title>Add records, lists and indices to Pure modules</title>
<updated>2026-09-25T12:25:38Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-25T12:25:38Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=e22b6f5c51e9133495c632a0c80674c14083c382'/>
<id>urn:sha1:e22b6f5c51e9133495c632a0c80674c14083c382</id>
<content type='text'>
Module format v4 declares record types and adds list states (items of a
record) and index states (a position in one list). The verifier types
record operands field by field and rejects an index used on another list.
Indices follow their item across inserts and removes. List changes are
logged per event and undone when the event fails. Replacing a module keeps
a list by name and moves its fields by name when the record changed.

pure-run prints lists as arrays and a failed view as null.

</content>
</entry>
</feed>
