<feed xmlns='http://www.w3.org/2005/Atom'>
<title>pure/serve/deliver.h, 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-10-01T08:10:55Z</updated>
<entry>
<title>Deliver wires on the sending loop, a step at a time (017, 2b-2)</title>
<updated>2026-10-01T08:10:55Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-10-01T08:10:55Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=5f5603ce239dce08ae2ec4b0fa828787b220493c'/>
<id>urn:sha1:5f5603ce239dce08ae2ec4b0fa828787b220493c</id>
<content type='text'>
A wire is now a sender of link/sending.h: its request goes on a
non-blocking socket as far as the socket takes it (connect, TLS
handshake, write, answer read), and its round waits for the socket or
its deadline (10 s with nothing moved). The answer is read as it comes:
the head whole, then a sized body counted down, a chunked one (few and
small) parsed again as it grows, or a body to the close. The crypto
table (version 6) takes the TLS handshake a step at a time, and reads
and writes say what they wait for. The owner pushes a wire once a turn,
as it does a link. A host whose app sends to ten links and ten wires
has 5 threads where it had 24 (none: 3).
</content>
</entry>
<entry>
<title>Hold a window of each output's sends in its transport, not the outbox</title>
<updated>2026-09-30T02:32:07Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-30T02:32:07Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=d9e0b6870201d9200b3c225903b43b850475600b'/>
<id>urn:sha1:d9e0b6870201d9200b3c225903b43b850475600b</id>
<content type='text'>
A link's ring and a wire's queue took every saved send of their output
and kept it until delivered: with the receiver down they held the
outbox a second time, 178 B and 313 B more a send (104). Each outlet now
holds a window, --window bytes (4 MiB) and 65,536 sends past what its
receiver has, at least one; the outbox keeps the rest.

The owner remembers each outlet's place in the outbox and looks on from
there after a save and after its transports deliver. Places move back by
the sends that left the outbox since (PureApp.sends_gone), so a trim
before a place skips nothing, and sends queued before are not looked at
again however many wait. pure_app_sent reads a send by its place (the
newest-first visit it replaces is gone); pure_link_held and
pure_wire_held say what a transport holds.

With the receiver down a node now grows by the outbox alone once the
window is full: 219 and 218 B a send over the link and HTTP (399 and
534 B before). check.py server_windows keeps the receivers of a sender's
two outputs, one linked and one over HTTP, down through 300 buys with a
2,000-byte window, then starts them: each applies all 300 once. Without
the refill after deliveries the link stops at 117.
</content>
</entry>
<entry>
<title>Bound what an app holds (--memory): refuse what would grow past it</title>
<updated>2026-09-30T02:04:03Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-30T02:04:03Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=a6df26a8499522033277ce4f3cd76eee155169ee'/>
<id>urn:sha1:a6df26a8499522033277ce4f3cd76eee155169ee</id>
<content type='text'>
pure-serve --memory BYTES gives the app a budget of state bytes: its
lists' items as they are stored, its texts, the outbox and the numbers
heard (docs/design/013-memory-budget.md). The count is deterministic,
the same on any device. An event after which the states hold more than
the budget, and more than before it, fails with the fault memory and
changes nothing; HTTP answers 503 memory. One that frees or keeps them
goes on, so an app over its budget can always shrink.

Sends waiting for their receivers are state: a full outbox refuses the
next send until some are stored, which is the backpressure a slow
receiver puts on clients. A delivery refused for memory is not heard:
the link keeps it (c9c0edf) and HTTP senders try again after 503.

An answer (--reply) now takes its send out of the outbox in its own
event (pure_app_answer), so it has the room its send held. Apart, an app
whose outbox filled the budget could never apply an answer that keeps
anything, and the send leaves only after its answer: both would stay for
good. An answer that still does not fit waits, with the wire's after it,
and is tried again every 100 ms: pure_wire_answer leaves it in place
until pure_wire_answered.

Checks: test-module memory_budget (refused and undone, freeing over the
budget, a full outbox, a delivery not heard, answers that fit or wait,
across a restart); check.py server_memory (a sender refused 503 memory
with its receiver down and taking buys once it is up; a receiver
restarted below what it keeps, refusing 7 times in 2 s, then taking all)
and server_answers_memory (answers wait while receipts fill the budget,
then apply once each; the API called once per order). The stats report
state_bytes and memory_refused.
</content>
</entry>
<entry>
<title>Put the links and the crypto they use in link/, a part of their own</title>
<updated>2026-09-29T06:06:27Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-29T06:06:27Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=a052b95c8135cdc5f9b91f8efc991cac80fbbe8b'/>
<id>urn:sha1:a052b95c8135cdc5f9b91f8efc991cac80fbbe8b</id>
<content type='text'>
libpure-link.a holds them; pure-serve and the M5 harness link it instead
of naming its source files.
</content>
</entry>
<entry>
<title>Seal in one session a wire, authenticated by the sender's key (088)</title>
<updated>2026-09-27T18:17:02Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-27T18:17:02Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=6d276be51ba89b04a60bb16b5179c015ad202c7c'/>
<id>urn:sha1:6d276be51ba89b04a60bb16b5179c015ad202c7c</id>
<content type='text'>
A sealed request cost three X25519 operations (about 0.5 ms), so sealed
sends drained at half the plain rate. A wire now keeps one HPKE context,
encapsulated at its first seal, and seals each request as the context's
next number (a failed seal or a restart starts a new session); the
header carries the session's encapsulated key and the number, so a
receiver opens a session once per connection thread (16 remembered, the
least used replaced) and each seal by its number, also after it restarts,
unasked. A sender with a key of its own seals in HPKE auth mode and names
that key in the header; a receiver started with --sender NAME=KEY takes
deliveries only from the senders it names, each sealed with its key
(403 sender otherwise). The body is now the ciphertext and its tag.

Sealed sends, sender authenticated, drain at 461-464k a second against
462-470k plain and 207-234k sealed a request at a time (Raspberry Pi 5).
The check adds: a wire's requests share one session numbered from 0; a
changed number or sender key does not open; a receiver restarted naming
its sender opens the same session again; another node claiming that
sender's name with its own key is refused and applies nothing.

</content>
</entry>
<entry>
<title>Seal delivered sends to the receiver's key (086)</title>
<updated>2026-09-27T17:26:41Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-27T17:26:33Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=c635e41d8576f5587d47e51a98dfd4a8920315f0'/>
<id>urn:sha1:c635e41d8576f5587d47e51a98dfd4a8920315f0</id>
<content type='text'>
--seal OUTPUT=KEY seals each request's body whole to the receiving node's
public key with HPKE (RFC 9180, base mode: X25519, HKDF-SHA256, AES-128-GCM
where the CPU has AES, else ChaCha20-Poly1305), bound to the request's
source, first number and count; X-Pure-Seal names the suite. A receiver's
--key is a raw 32-byte file, made 0600 when missing, held in OpenSSL's
secure heap; it opens the body where it lies (400 seal when it does not
open) and zeroes the plain text when the request's ticket goes.
--sealed-only refuses unsealed deliveries (403 unsealed).

The check puts a recording relay between two apps: every order applies
once, no body shows an item or a field name, a flipped bit is refused, a
replayed request applies nothing twice, and a seal to another key does not
open. Its hosts choose their own ports (--port 0). Sealed sends drain at
233-235k a second against 469-470k plain (Raspberry Pi 5): three X25519
operations a request, 164 us each. The plain request path measured the
same as before.

</content>
</entry>
<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>
</feed>
