CultNetWriteNotSentException names the pre-send boundary (connect, hello, no endpoint,
or a send port that proves nothing was written). Every other forwarding failure keeps
the session claim. ForUnownedSchema and the routing refusal no longer carry exception text.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Opt-in per connection by the first hello (or first write); the server answers a
capable hello with its own. A put or delete commits, then gets write_admitted under
its id; every refusal is error.v1 with the id (an unreadable frame carries the id
when it still holds one). (actor, messageId) dedupe is bound to the content hash and
asked only after the write authority grants; same id other content is message_invalid.
The shard write forwarder says hello, waits for the primary's receipt, and the server
relays only what the primary answered under the original id.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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>
CultNetDatabaseServerOptions.RemoteWriteAuthority is asked once per received
write, after the schema resolves and before the shard does; none configured
refuses every remote write; an authority that throws refuses and is logged.
A refusal applies, publishes, logs and forwards nothing. The host's own
CultNetDatabase.ApplyPutAsync/ApplyDeleteAsync ask no remote authority.
Existing server tests whose subject is not the grant pass a test-local
granting authority.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>