C#: SubmitDocumentAsync and the shard write forwarder complete on the result frame #58

Merged
libby merged 1 commit from libby/cs-client-ack-finding into main 2026-11-08 13:24:39 +00:00
Member

C#: SubmitDocumentAsync and the shard write forwarder (CultNetSchemaWriteForwarder.ForwardPutAsync/ForwardDeleteAsync) complete on the peer's result frame, not on the send returning. New CultNetWriteCompletion.SendAndAwaitResultAsync registers the refusal handler before the send and waits a result window (500 ms default; CultMeshClientOptions.SubmitResultWindow, CultNetSchemaWriteForwarderOptions.ResultWindow). A cultnet.error.v0 in the window rejects with the new CultNetWriteRefusedException (Code: write_not_authorized, message_invalid, ...) whatever its order against the send or transport ack. Peers send no success frame for an admitted write, so the window is the interim bound (no server code); the error frame carries no message id, so any refusal inside the window is attributed to this write.

Caller exposure: CultNetDatabaseServer.TryForwardPutAsync/DeleteAsync (:698/:718) returned true after a forward whose refusal it never read; a refused forward now throws from the forwarder, the same path as an unreachable primary (server code unchanged).

Doc line 'fire-and-forget: an ack or a return is not admission; read the result frame' on the C# ICultNetSchemaClient.SendCultNet and CultMeshSession.SendCultNet, Python CultNetRawClient.send and the RUDP/tcp transport send, Kotlin sendSchemaMessage/send/sendSchema.

Tests: SubmitDocument and forwarder reject typed for write_not_authorized and message_invalid, immediate and after 150 ms; neither completes before the window. Mutants killed: refusal check removed, window zeroed, handler registered after the send. Mesh.Tests 346 and Networking.Tests 514 pass.

🤖 Generated with Claude Code

C#: `SubmitDocumentAsync` and the shard write forwarder (`CultNetSchemaWriteForwarder.ForwardPutAsync/ForwardDeleteAsync`) complete on the peer's result frame, not on the send returning. New `CultNetWriteCompletion.SendAndAwaitResultAsync` registers the refusal handler before the send and waits a result window (500 ms default; `CultMeshClientOptions.SubmitResultWindow`, `CultNetSchemaWriteForwarderOptions.ResultWindow`). A `cultnet.error.v0` in the window rejects with the new `CultNetWriteRefusedException` (`Code`: `write_not_authorized`, `message_invalid`, ...) whatever its order against the send or transport ack. Peers send no success frame for an admitted write, so the window is the interim bound (no server code); the error frame carries no message id, so any refusal inside the window is attributed to this write. Caller exposure: `CultNetDatabaseServer.TryForwardPutAsync/DeleteAsync` (:698/:718) returned true after a forward whose refusal it never read; a refused forward now throws from the forwarder, the same path as an unreachable primary (server code unchanged). Doc line 'fire-and-forget: an ack or a return is not admission; read the result frame' on the C# `ICultNetSchemaClient.SendCultNet` and `CultMeshSession.SendCultNet`, Python `CultNetRawClient.send` and the RUDP/tcp transport `send`, Kotlin `sendSchemaMessage`/`send`/`sendSchema`. Tests: SubmitDocument and forwarder reject typed for write_not_authorized and message_invalid, immediate and after 150 ms; neither completes before the window. Mutants killed: refusal check removed, window zeroed, handler registered after the send. Mesh.Tests 346 and Networking.Tests 514 pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
C#: SubmitDocumentAsync and the shard write forwarder complete on the result frame
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 6m41s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 32s
09e6a528b8
CultNetWriteCompletion.SendAndAwaitResultAsync registers a refusal handler before
the send, then waits a result window (default 500 ms; CultMeshClientOptions.
SubmitResultWindow, CultNetSchemaWriteForwarderOptions.ResultWindow). A
cultnet.error.v0 inside it rejects with the new CultNetWriteRefusedException
(Code: write_not_authorized, message_invalid, ...) whatever its order against the
send or transport ack; a send returning no longer completes the write. The
forwarder's refusal now throws on the same path as an unreachable primary, so
CultNetDatabaseServer.TryForwardPutAsync/DeleteAsync no longer report a refused
forward as done. Raw send primitives (C# schema client/session, Python, Kotlin)
carry the doc line: fire-and-forget, an ack or a return is not admission, read the
result frame.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
libby merged commit dc5abedffc into main 2026-11-08 13:24:39 +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!58
No description provided.