TS: write_admitted / error.v1 decoder, WriteTracker, vector replay runner #62

Merged
libby merged 10 commits from libby/ts-write-receipt-client into main 2026-11-08 19:52:38 +00:00
Member

TS client half of the write receipt spec (#59); stacked on #59 (its commits appear until #59 merges; review only the top commits).

  • cultnet.write_admitted.v0 and cultnet.error.v1 decode/encode in cultnet-ts (closed code set incl. limit_reached); error.v0 untouched; a hello is receipt-capable only when it lists both frames.
  • WriteTracker (packages/cultnet-ts/src/write-tracker.ts): outcomes admitted / refused(code) / unconfirmed(window_elapsed|session_ended), admitted_late / refused_late recorded, id-less errors attributed only with exactly one unanswered write, window from send (5000 ms receipt peer, 500 ms legacy).
  • cultmesh-ts publishRudpDocumentOnce: opt-in writeReceipts: true (sends hello, waits 500 ms for the server hello); otherwise behaviour unchanged. Silence or session end against a receipt peer throws CultMeshRudpWriteUnconfirmedError.
  • Replay runner packages/cultnet-ts/tools/replay-write-receipt-vectors.mjs: 32/32 (constants, 6 wire frames, 7 invalid frames, 18 scenarios); exit nonzero on failure; interface documented in the cultnet-ts README ("Write receipt replay runner") for Rust and C# to port.

Tests: cultnet-ts 301 (1 pre-existing esbuild failure), cultmesh-ts 256 (198 pass, 0 fail). StrykerJS absent: 31 hand-run tracker mutants, 27 killed, 2 compile errors, 2 survivors killed after new tests.
Not reached: publishRudpDocumentAndWaitForReceipt; server dedupe vectors not replayed; no run against a real cultmesh-ts server; schemas read from contracts/cultnet/interop/. No tag, no publish.

🤖 Generated with Claude Code

TS client half of the write receipt spec (#59); stacked on #59 (its commits appear until #59 merges; review only the top commits). - `cultnet.write_admitted.v0` and `cultnet.error.v1` decode/encode in cultnet-ts (closed code set incl. `limit_reached`); error.v0 untouched; a hello is receipt-capable only when it lists both frames. - `WriteTracker` (packages/cultnet-ts/src/write-tracker.ts): outcomes admitted / refused(code) / unconfirmed(window_elapsed|session_ended), admitted_late / refused_late recorded, id-less errors attributed only with exactly one unanswered write, window from send (5000 ms receipt peer, 500 ms legacy). - cultmesh-ts `publishRudpDocumentOnce`: opt-in `writeReceipts: true` (sends hello, waits 500 ms for the server hello); otherwise behaviour unchanged. Silence or session end against a receipt peer throws `CultMeshRudpWriteUnconfirmedError`. - Replay runner `packages/cultnet-ts/tools/replay-write-receipt-vectors.mjs`: 32/32 (constants, 6 wire frames, 7 invalid frames, 18 scenarios); exit nonzero on failure; interface documented in the cultnet-ts README ("Write receipt replay runner") for Rust and C# to port. Tests: cultnet-ts 301 (1 pre-existing esbuild failure), cultmesh-ts 256 (198 pass, 0 fail). StrykerJS absent: 31 hand-run tracker mutants, 27 killed, 2 compile errors, 2 survivors killed after new tests. Not reached: `publishRudpDocumentAndWaitForReceipt`; server dedupe vectors not replayed; no run against a real cultmesh-ts server; schemas read from contracts/cultnet/interop/. No tag, no publish. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
spec: cultnet write receipt (write_admitted.v0, error.v1 id echo, three-outcome clients)
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
662ae048d8
Specification and shared vectors only, no runtime code. A write is answered
exactly once with cultnet.write_admitted.v0 or cultnet.error.v1 carrying its
messageId; the new frames go only to connections whose hello lists them (today's
TS decoder rejects unknown keys and versions, so "old clients ignore it" is
false). Clients settle admitted | refused | unconfirmed; the result window is the
pre-receipt fallback and ends unconfirmed. Wire vectors, schema-invalid cases and
16 replay scenarios in write-receipt-vectors.json.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
spec: write receipt per Heimdall's review (dedupe by actor+content hash, admitted-late, 5 s window, capability is framing only)
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 6m28s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 2m19s
ab7bc771e3
- messageId unique per authenticated actor and session; dedupe key (actor, id) bound to SHA-256 of
  [operation, schemaId, recordKey, payload]; same id with other content is message_invalid, never the old receipt.
- A late answer after the window is recorded on the write (admitted_late / refused_late); no blind resend.
- A forwarder with no primary answer relays nothing; the client reports unconfirmed.
- RECEIPT_RESULT_WINDOW_MS 5000 (default), LEGACY_RESULT_WINDOW_MS 500 (fallback only), DEDUPE_RETENTION_MS as vector constants.
- The hello capability changes framing only and never authorizes.
- Batches can commit partially; the caller owns retry.
- Vectors: constants, worked content hashes, 7 dedupe cases, late-answer and window scenarios.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
spec: dedupe scope is at least the session; a resend after a reconnect is a new write
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 5m52s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 41s
7a560b1984
Per Heimdall's review. The dedupe key lives for the life of its session, bounded per
session without forgetting an id the server promised to answer. A longer retention
is optional and never to be relied on. After a reconnect callers resend only writes
that are idempotent by record key and read back before resending any other.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
cultnet: add limit_reached to error.v1 code enum, with captured vector
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 4m51s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 26s
eafcdcdf7c
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
cultnet-ts: tests for two tracker mutants (send expires other windows; non-answer frames settle nothing)
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 5m28s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 51s
8dc75c5522
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
libby force-pushed libby/ts-write-receipt-client from 8dc75c5522
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 5m28s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 51s
to 6eb6d2440e
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 12m8s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 42s
2026-11-08 16:40:53 +00:00
Compare
libby force-pushed libby/ts-write-receipt-client from 6eb6d2440e
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 12m8s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 42s
to c89c4ee39a
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 5m58s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 1m18s
2026-11-08 17:07:57 +00:00
Compare
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
cultmesh-ts: sendOnly tests use one fake server per publish (the reused one threw on the second connect and hung the run); spec names send-only and the presence publisher
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
206dbe142b
The hang was the fake server, not the writer: it is bound to one connection id, and two publishes in one test sent a second connect it rejected from inside the socket handler. The unacknowledged-send test also scripted an admit, whose reply piggybacks the put's ack.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
cultnet-ts test: the Odin presence publisher is send-only, so a refusal after the transport ack is not awaited
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
89ff3d2cbd
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
cultnet-ts, cultmesh-ts: Heimdall's five Lows on send-only (spec wording, error.v1 ack-time refusal tests, build errors keep their cause, presence changelog, ack-cut anchors)
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
0fbf2baea6
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
cultmesh-ts: publishRudpDocumentOnce builds the put before connecting, so a put that cannot be built keeps its cause on both paths
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 6m13s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 31s
dc1ae51e92
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
libby merged commit 7665df33ae into main 2026-11-08 19:52:38 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
GameCult/CultLib!62
No description provided.