From 3195c8d412f4123dcdb8b68f3e7b3a5a60135f73 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 29 Oct 2026 01:24:30 +0000 Subject: [PATCH 1/3] docs: name the parent and unlisted endpoints in the change feed's list The sentence listing what the change feed reports beyond snapshotting still named a PATCH carrying only no-bump keys, an endpoint the wire no longer has. The writes it meant are PUT .../parent and PUT .../unlisted. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01XRRrTNcLcf2TtfuL9wB8Z8 --- docs/spec/wire-format.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/spec/wire-format.md b/docs/spec/wire-format.md index 1a4b0164..28099841 100644 --- a/docs/spec/wire-format.md +++ b/docs/spec/wire-format.md @@ -484,7 +484,7 @@ The second durable tier a mutation writes is [the change journal](./journal.md), `POST .../restore/:version` accepts the same optional `If-Match` precondition described under [Optimistic concurrency](#optimistic-concurrency). It settles `content` and `typeId` alone, so it never moves the record and never lists or unlists it: neither the **403** nor the **409** a `PUT .../parent` can earn has a site here. A snapshot naming a `file-ref` the requester cannot currently reach still answers **403**, which is the only reference a restore can re-convey. See [Versioning § Restore semantics](./versioning.md#restore-semantics). -**The [change feed](./change-feed.md) reports on a wider list than snapshotting does**: every endpoint above, plus create, purge, the association and permission endpoints, and a `PATCH` naming only no-bump keys — none of which snapshots. A server that skips an endpoint there loses reactivity for that verb exactly as silently as a version-bumping endpoint's omission loses rollback history here. +**The [change feed](./change-feed.md) reports on a wider list than snapshotting does**: every endpoint above, plus create, purge, the parent and unlisted endpoints, and the association and permission endpoints — none of which snapshots. A server that skips an endpoint there loses reactivity for that verb exactly as silently as a version-bumping endpoint's omission loses rollback history here. ## Journal From 909542070c26a2a12c9fe560fd4aed4748e9fea9 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 15:11:26 +0000 Subject: [PATCH 2/3] docs: list parseInstallBody() in the wire parser table POST /installs has a core parser like every other endpoint that takes input, and the table naming them left it out. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01XRRrTNcLcf2TtfuL9wB8Z8 --- docs/spec/wire-format.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/spec/wire-format.md b/docs/spec/wire-format.md index 28099841..2b12fe90 100644 --- a/docs/spec/wire-format.md +++ b/docs/spec/wire-format.md @@ -221,6 +221,7 @@ A server built on core reaches this through the wire parsers in `@haverstack/cor | `GET /changes` | `parseChangeParams()` | | `GET /attachments/:fileId` | `parseDownloadParams()` | | `POST /types` | `parseTypeBody()` | +| `POST /installs` | `parseInstallBody()` | | `POST /auth/challenge` | `parseAuthChallengeBody()` | | `POST /auth/token` | `parseAuthTokenBody()` | From d465465ab022866708b0f3a7f8ad73ec0fd360dc Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 16:29:18 +0000 Subject: [PATCH 3/3] docs: name the change feed's no-bump coverage by the no-bump write term MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wire-format.md § Versions and change-feed.md's checklist each enumerated the non-snapshotting endpoints by hand, and change-feed.md still named a PATCH the wire no longer has. Both now point at versioning.md's no-bump write, as events.md already does, so the set is defined in one place. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01XRRrTSe78uQTHCvNi9ZFL1 --- docs/spec/change-feed.md | 2 +- docs/spec/wire-format.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/spec/change-feed.md b/docs/spec/change-feed.md index 6a7a0812..c032e277 100644 --- a/docs/spec/change-feed.md +++ b/docs/spec/change-feed.md @@ -120,7 +120,7 @@ As with [the auth checklist](./wire-format.md#server-implementation-checklist), - **Close on buffer overflow; never drop a frame silently.** - **Only the storage owner can emit.** [Exactly one process owns a stack's storage](./adapters.md#concurrency--storage-ownership), so events exist only in that process. A multi-process server needs its own fan-out from the owner; a second process subscribing to its own `Stack` sees nothing and looks fine in testing. - **Mint cursors in the base64url alphabet only** — a value containing a newline truncates the frame that carries it. -- **Emit for every mutating endpoint**, not the convenient ones. The list is the exhaustive one under [Versions](./wire-format.md#versions), plus create, purge, the [association](./wire-format.md#associations) and [permission](./wire-format.md#permissions) endpoints, and a `PATCH` naming only no-bump keys. None of that second group bumps `version`, so a server that emits off its snapshot path alone silently serves no association, permission, move or listing events at all. +- **Emit for every mutating endpoint**, not the convenient ones. The list is the exhaustive one under [Versions](./wire-format.md#versions), plus create, purge and every [no-bump write](./versioning.md#version-history). None of that second group bumps `version`, so a server that emits off its snapshot path alone silently serves no association, permission, move or listing events at all. ## Why SSE, and why not `EventSource` diff --git a/docs/spec/wire-format.md b/docs/spec/wire-format.md index 2b12fe90..1702d246 100644 --- a/docs/spec/wire-format.md +++ b/docs/spec/wire-format.md @@ -465,7 +465,7 @@ A move that would make the record its own ancestor answers **409** (code `confli ## Versions -**The server snapshots prior state automatically on every mutating endpoint that bumps `version`** — there is no client-initiated endpoint to write a version directly. The list is exhaustive on purpose: `PATCH /records/:id/content`, `DELETE` (soft), `POST .../undelete`, `POST .../migrate`, and `POST .../restore/:version` itself (restore always creates a new version). The parent, unlisted, association and permission endpoints are the deliberate exception: none of them bumps `version`, so none snapshots either. `APIAdapter` has no [`importRecord()`](./portability.md#writing-history) — the server is the only snapshot writer for this adapter — so a server that implements anything less than every endpoint above silently loses rollback history for that endpoint's mutations. +**The server snapshots prior state automatically on every mutating endpoint that bumps `version`** — there is no client-initiated endpoint to write a version directly. The list is exhaustive on purpose: `PATCH /records/:id/content`, `DELETE` (soft), `POST .../undelete`, `POST .../migrate`, and `POST .../restore/:version` itself (restore always creates a new version). The parent, unlisted, association and permission endpoints are the deliberate exception: each is a [no-bump write](./versioning.md#version-history), so none snapshots either. `APIAdapter` has no [`importRecord()`](./portability.md#writing-history) — the server is the only snapshot writer for this adapter — so a server that implements anything less than every endpoint above silently loses rollback history for that endpoint's mutations. ``` GET /records/:id/versions — list all versions (newest first) @@ -485,7 +485,7 @@ The second durable tier a mutation writes is [the change journal](./journal.md), `POST .../restore/:version` accepts the same optional `If-Match` precondition described under [Optimistic concurrency](#optimistic-concurrency). It settles `content` and `typeId` alone, so it never moves the record and never lists or unlists it: neither the **403** nor the **409** a `PUT .../parent` can earn has a site here. A snapshot naming a `file-ref` the requester cannot currently reach still answers **403**, which is the only reference a restore can re-convey. See [Versioning § Restore semantics](./versioning.md#restore-semantics). -**The [change feed](./change-feed.md) reports on a wider list than snapshotting does**: every endpoint above, plus create, purge, the parent and unlisted endpoints, and the association and permission endpoints — none of which snapshots. A server that skips an endpoint there loses reactivity for that verb exactly as silently as a version-bumping endpoint's omission loses rollback history here. +**The [change feed](./change-feed.md) reports on a wider list than snapshotting does**: every endpoint above, plus create, purge and every [no-bump write](./versioning.md#version-history) — none of which snapshots. A server that skips an endpoint there loses reactivity for that verb exactly as silently as a version-bumping endpoint's omission loses rollback history here. ## Journal