TS write-receipt client against the real Rust and C# receipt servers (interop harness) #67

Merged
libby merged 9 commits from libby/write-receipt-ts-interop into main 2026-11-09 14:16:00 +00:00
Member

Stacked on #64. Runs the merged TypeScript write-receipt client against the two real receipt servers over loopback, as child processes on ephemeral ports, and keeps the harness in the repo.

  • packages/cultmesh-ts/test/interop/write-receipt-interop.test.ts (npm run test:interop in packages/cultmesh-ts): one scenario set, run against each server; outcomes are read from WriteTracker (admitted, refused, unconfirmed) and the server's own stdout facts say what was committed. The blank-field cases are driven by write-receipt-vectors.json blankFields.
  • Rust: packages/cultmesh-rs/examples/receipt_interop_server.rs, the production CultMeshRudpDocumentServer with a recording sink. Reached over RUDP by CultMesh.createRudpPeer; three further tests drive the real one-shot writer publishRudpDocumentOnce (admitted, refused, no-hello).
  • C#: receipt-serve and receipt-relay modes in the existing GameCult.Networking.InteropPeer (no new project). CultNetDatabaseServer speaks LiteNetLib only and TypeScript has no LiteNetLib client, so the relay moves bytes (length-prefixed CultNet frames, which is CultNetPeer's own stream framing) and decodes nothing; the TS side decodes with the real decoder. No TS RUDP client path reaches the C# server.

Results (50 pass, 1 todo, 3 runs, no flakes): every scenario passes against both servers except one.

Finding: the Rust RUDP document server refuses every delete (write_not_authorized: the server does not take deletes, error.v1 carrying the delete's id); the sink port has no delete. The spec has a delete admitted and receipted like a put (Server rules 1 to 3), and the C# server does. The scenario is a todo for the Rust arm, so it stays visible and does not fail the suite. Not fixed here (a server change); follow-up admitted.

Not proven here: that the receipt is sent after the commit (server facts and wire are separate channels, so only "applied exactly once, eventually" is asserted); shard-forwarded writes; the limit_reached bounds; the unreliable-channel refusal.

Build budget: cargo -j1, one example target in cultmesh-rs (linux, built on the host that runs it); one existing dotnet project, no new target. Set RECEIPT_INTEROP_PREBUILT=1 to skip the two builds (MSBuild cannot start under a tight address-space cap).

🤖 Generated with Claude Code

Stacked on #64. Runs the merged TypeScript write-receipt client against the two real receipt servers over loopback, as child processes on ephemeral ports, and keeps the harness in the repo. - `packages/cultmesh-ts/test/interop/write-receipt-interop.test.ts` (`npm run test:interop` in `packages/cultmesh-ts`): one scenario set, run against each server; outcomes are read from `WriteTracker` (admitted, refused, unconfirmed) and the server's own stdout facts say what was committed. The blank-field cases are driven by `write-receipt-vectors.json` `blankFields`. - Rust: `packages/cultmesh-rs/examples/receipt_interop_server.rs`, the production `CultMeshRudpDocumentServer` with a recording sink. Reached over RUDP by `CultMesh.createRudpPeer`; three further tests drive the real one-shot writer `publishRudpDocumentOnce` (admitted, refused, no-hello). - C#: `receipt-serve` and `receipt-relay` modes in the existing `GameCult.Networking.InteropPeer` (no new project). `CultNetDatabaseServer` speaks LiteNetLib only and TypeScript has no LiteNetLib client, so the relay moves bytes (length-prefixed CultNet frames, which is `CultNetPeer`'s own stream framing) and decodes nothing; the TS side decodes with the real decoder. No TS RUDP client path reaches the C# server. Results (50 pass, 1 todo, 3 runs, no flakes): every scenario passes against both servers except one. Finding: the Rust RUDP document server refuses every delete (`write_not_authorized: the server does not take deletes`, error.v1 carrying the delete's id); the sink port has no delete. The spec has a delete admitted and receipted like a put (Server rules 1 to 3), and the C# server does. The scenario is a `todo` for the Rust arm, so it stays visible and does not fail the suite. Not fixed here (a server change); follow-up admitted. Not proven here: that the receipt is sent after the commit (server facts and wire are separate channels, so only "applied exactly once, eventually" is asserted); shard-forwarded writes; the limit_reached bounds; the unreliable-channel refusal. Build budget: cargo `-j1`, one example target in cultmesh-rs (linux, built on the host that runs it); one existing dotnet project, no new target. Set `RECEIPT_INTEROP_PREBUILT=1` to skip the two builds (MSBuild cannot start under a tight address-space cap). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
cultmesh-ts: TS write-receipt client against the real Rust and C# receipt servers (test:interop)
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 5m56s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 31s
140eca5138
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
interop test: read the store under the record key the blank-field vector set
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 3m0s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 46s
04207007d6
A vector that sets recordKey (zero_width_space_record_key_is_a_name) replaces the harness key, so the admitted case waited for
blank:<name> and timed out against the Rust server, and the refused record-key cases counted applications under a key the server
never saw. Use the key the document carried.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Merge remote-tracking branch 'origin/libby/write-receipt-text-blank-rules' into libby/write-receipt-ts-interop
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 10m47s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 45s
819df6a666
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
interop peer: C# store holds the spec's admitted schema-id names (compatible ids)
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 6m32s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 37s
96c5fb1ca4
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
libby changed target branch from libby/write-receipt-text-blank-rules to main 2026-11-09 14:16:00 +00:00
libby merged commit 325da81428 into main 2026-11-09 14:16:00 +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!67
No description provided.