Skip to content
C.W.K.
Lesson 04 of 05 · published

A Write the Owner Makes

~13 min · write-call, canonical-writer, authorization, request-id, soul-vault

Level 0Loose File
0 XP0/43 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

Some Data Has a Writer

Every write verb Delta had before this one moves a file: upload and commit land bytes, mkdir and symlink make entries, keep sets a file aside, DELETE removes one. That is the right vocabulary for a folder of photos. It is the wrong vocabulary for data that has an owner: an app with a canonical writer that validates what it is given, takes its own locks, compares a revision before it writes, and records history.

The soul vault's store is the first such owner. A note written there goes through compare-and-swap (the writer names the revision it read; a stale one is refused), a write gate judged per Mac, and a commit that records who wrote it. If another Mac simply uploaded the note's file into the store's folder, every one of those guarantees would be bypassed by a file appearing underneath the writer. So the other Mac must not write the file. It must ask the owner to write.

Before Coop 1110-41, that asking was assembled from file verbs: a request file delivered by a transfer job, then applied by the owner through api. It worked, and took 0.34 s for one write. The call verb replaced it.

The Call, End to End

  1. The app asks its own Mac's Delta on loopback: POST /v1/peer/<mac>/call/<share>/<op>, a JSON body, and four headers: the local token, X-Delta-App, X-Delta-Request-Id, and optionally X-Delta-Timeout.
  2. This Mac's engine checks the request id and the time limit before anything leaves; a missing id or a limit that is not a number of seconds is bad_request right there.
  3. The engine carries it to the owner's gateway as POST /v1/call/<share>/<op> over the chosen route, with Delta's own authentication. The body is held to MAX_JSON_BODY (4 MiB).
  4. The owner's gateway checks who may (_require_write), reads the body, and hands it to the share's call().
  5. The child's answer goes back as JSON with Cache-Control: no-store. Delta keeps neither the request nor the answer.

When the owner is this Mac, step 3 disappears: the engine runs the share's call in place, with no network at all. Measured on the live fleet (2026-11-10, Soul Vault's store on the Pippa-role Mac, three calling Macs on Thunderbolt): a note written from another Mac took 72 to 83 ms from the app's call to its answer, 58 to 72 ms of it inside the owner's handler, which is the store's own commit. A stale revision the store refused took 1.1 ms in the handler and 7 to 16 ms for the caller.

The Root Class Refuses; the Child Opts In

DataShare.call raises Forbidden, like every write on the root class. A share that owns a canonical writer overrides two methods: writable() returns true, and call() does the work. Overriding only call is not enough, because the authorization check asks writable() first. And the file verbs stay refused on such a share, with a message that says why: it "takes no file writes: its owner writes through a call". Soul Vault's StoreShare is exactly that shape, with three operations (write, create_soul, delete_soul); its read-only cousin for the household's Mac returns writable() == False and refuses every call.

Who May, and What the Child Is Told

_require_write is the same check every write passes. The share must be writable; the calling Mac, as Delta verified it (the tailnet roster on the tailnet, the issued ticket on the LAN), must be this Mac or allowed by the share's writers; and the calling app, from X-Delta-App, must be in the share's apps. Then the child receives caller, app and request_id as arguments.

The caller argument is the verified Mac, never a name the request body carries. A request may still describe itself (Soul Vault's request documents name their own caller and request id), and that is the child's to compare, never to trust: Soul Vault refuses a request whose stated caller differs from the Mac Delta verified, or whose own request id differs from the id of the call that carried it. Be honest about what the app name is worth, too: X-Delta-App is what the calling process says it is, on a Mac whose local token it holds. It separates apps that cooperate. A writer that must tell two apps on one Mac apart needs more than that header.

The Request Id Is the Caller's Name for One Call

X-Delta-Request-Id is required: letters, digits, . _ : -, starting with a letter or digit, at most 128 characters. The owner keeps each outcome by it and answers a repeated id with the first result instead of writing again. That one rule is what makes asking again safe after a lost answer, which is the whole subject of the next lesson. The gateway's access log names it too (call=<id>), beside the Mac and the app, so one call can be followed across both Macs.

Code

The owner's gateway receives a call (trimmed excerpt)·python
# delta/server.py (trimmed excerpt): the owner's gateway receives a call
REQUEST_ID = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$")   # a write call's own name


def call_request_id(h: Handler) -> str:
    """The caller's own name for one write call, from ``X-Delta-Request-Id``."""
    request_id = h.headers.get("X-Delta-Request-Id") or ""
    if not REQUEST_ID.match(request_id):
        raise BadRequest("a call names itself in X-Delta-Request-Id: the owner keeps its outcome "
                         "by that id, which is what makes asking again safe")
    return request_id


def _require_write(h: Handler, share) -> None:
    if not share.can_write(h.caller, h.app or None):
        raise Forbidden(f"{h.caller} may not write {share.id}" + (f" for {h.app}" if h.app else ""))


def serve_call(h: Handler, tail: str) -> None:
    """Who may is the share's: the calling Mac (from the tailnet roster or its
    ticket) held to ``writers``, the app (``X-Delta-App``) held to ``apps``. The
    child gets the verified Mac, never a name the request carries. The answer is
    the child's JSON, kept nowhere by Delta."""
    share, op = _share_and_op(h, tail)
    _require_write(h, share)
    request_id = call_request_id(h)
    body = h.read_json()
    h.delta.count("calls")
    result = share.call(op, dict(h.query), body, caller=h.caller, app=h.app, request_id=request_id)
    h.send_json(200, result, {"X-Delta-Share": share.id, "X-Delta-Request-Id": request_id})
The smallest owner Delta's suite declares (trimmed excerpt)·python
# tests/test_write_call.py (trimmed excerpt): the smallest owner Delta's suite declares
import json

from delta.errors import Conflict
from delta.shares import DataShare


class LedgerShare(DataShare):
    """An owner with one canonical writer: every call it carries out is one line."""

    def writable(self):
        return True

    def call(self, op, params, body, *, caller, app, request_id):
        done = self.repo_root / ("done-" + self.name) / (request_id + ".json")
        if done.exists():  # the same call again: its first answer, never a second line
            return dict(json.loads(done.read_text()), replayed=True)
        if op == "refuse":
            raise Conflict("the ledger refuses this entry")
        entry = {"op": op, "params": params, "body": body, "caller": caller, "app": app,
                 "request_id": request_id}
        with open(self.repo_root / ("ledger-" + self.name + ".jsonl"), "a") as handle:
            handle.write(json.dumps(entry) + "\n")
        answer = {"ok": True, "entry": entry}
        done.parent.mkdir(exist_ok=True)
        done.write_text(json.dumps(answer))
        return answer
Your own canonical writer: the write and its outcome in one transaction, keyed by request id·python
# owner.py: a canonical writer that answers a repeated request id with its first answer
import json
import sqlite3


class Owner:
    """One writer, one ledger; every outcome kept by the caller's request id."""

    def __init__(self, path: str = ":memory:"):
        self.db = sqlite3.connect(path)
        self.db.execute("CREATE TABLE IF NOT EXISTS notes (name TEXT PRIMARY KEY, text TEXT, rev INTEGER)")
        self.db.execute("CREATE TABLE IF NOT EXISTS outcomes (request_id TEXT PRIMARY KEY, answer TEXT)")

    def call(self, op: str, body: dict, *, caller: str, request_id: str) -> dict:
        with self.db:  # one transaction: the write and its outcome land together, or neither
            row = self.db.execute("SELECT answer FROM outcomes WHERE request_id=?", (request_id,)).fetchone()
            if row:
                return dict(json.loads(row[0]), replayed=True)
            if op != "write":
                raise ValueError(f"no operation {op!r}")
            cur = self.db.execute("SELECT rev FROM notes WHERE name=?", (body["name"],)).fetchone()
            rev = cur[0] if cur else 0
            if body.get("expected_rev", rev) != rev:
                answer = {"ok": False, "error": "conflict", "rev": rev}
            else:
                self.db.execute("INSERT OR REPLACE INTO notes VALUES (?,?,?)", (body["name"], body["text"], rev + 1))
                answer = {"ok": True, "rev": rev + 1, "by": caller}
            self.db.execute("INSERT INTO outcomes VALUES (?,?)", (request_id, json.dumps(answer)))
            return answer


owner = Owner()
print(owner.call("write", {"name": "a", "text": "one", "expected_rev": 0}, caller="laptop", request_id="w-1"))
# The answer was lost on the way back; the caller asks again under the same id.
print(owner.call("write", {"name": "a", "text": "one", "expected_rev": 0}, caller="laptop", request_id="w-1"))
# A new request from a stale view is refused by the writer's own rule.
print(owner.call("write", {"name": "a", "text": "two", "expected_rev": 0}, caller="laptop", request_id="w-2"))
print(owner.db.execute("SELECT * FROM notes").fetchall())

External links

Exercise

Run the owner demo and then break it on purpose: move the INSERT into outcomes outside the with-block, raise an exception between the note write and the outcome write, and call again with the same request id. Describe what the caller now gets, and why keeping the write and its outcome in one transaction is the property that makes a repeated id safe.
Hint
With the outcome recorded separately, a crash between the two leaves a written note and no remembered answer, so the retry writes a second time (or, with expected_rev, is refused as a conflict for a write that actually succeeded). SQLite's with-connection block commits both or neither.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.