Rust RUDP server: pin blank schemaId/recordKey refusal, decide sequenced refusal per frame #63

Merged
libby merged 16 commits from libby/rs-receipt-key-tests-per-frame into main 2026-11-09 14:15:50 +00:00

2026-11-09

Libby
Merge remote-tracking branch 'origin/libby/write-receipt-text-blank-rules' into libby/rs-receipt-key-tests-per-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 8m39s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 1m0s
2026-11-09 10:37:49 +00:00
Libby
write-receipt: seven tracker vectors, a tracker that ends with its session, runners that count
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 7m39s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 22s
New scenario vectors: id-less error.v1 with one and with two writes unanswered,
sendFailed, an id-less error after the window, a receipt one ms inside the window
and at the exact boundary (late), a send after sessionEnd. The last exposed a
TS tracker leaving such a write pending forever; it now settles session_ended.
The file declares counts, and the TS replay runner fails on a count it did not
run or an event key scenarios.semantics does not name.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 10:34:49 +00:00
Libby
cultnet-ts: a blank text in a raw frame is Unicode White_Space, not trim()
validateBinaryMessageRoot, requireNonEmptyString and requireOptionalStringArray
used String.prototype.trim(), which takes U+FEFF and misses U+0085, so the TS
decoder and the servers disagreed on what names nothing (write-receipt rule 5).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 10:22:15 +00:00
Libby
write-receipt spec: a repeated or unreceived sequenced packet draws no second answer
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 5m30s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 16s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 09:13:31 +00:00
Libby
Rust RUDP server: answer a sequenced write once, not once per send
A repeat of a packet the session already took, and a packet too far ahead to be
remembered, delivered no frame and so drew the superseded-write refusal again on
every send, breaking write-receipt rule 1. The refusal now applies only to the
first packet the session takes for a sequence; CultNetRudpSession::has_received
exposes that test.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 09:13:18 +00:00
Libby
Rust RUDP server: pin the superseded-write refusal against a releasing packet and the half-space bound
cargo-mutants on the previous commit missed two mutants: `&&` to `||` in the
superseded-packet check (a packet that also releases another write hid it) and
`<` to `<=` at the half-space bound of sequence_at_or_before. A test and two
assertions kill them; the rerun catches 14 of 15 (1 unviable).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 09:13:18 +00:00
Libby
Rust RUDP server: answer a superseded sequenced write; order frame and packet by serial arithmetic
Superseded packet: a reliable-sequenced packet that arrives after a newer one
delivers no frame, yet is acknowledged and never resent, so its write went
unanswered. The test (red first: only "new" was refused, "old" got nothing)
showed the drop happens in the session below frame decoding, but an unfragmented
packet carries its whole frame, so the server can read the id from the packet
payload. Chosen: refuse it from the packet payload. A superseded fragment of a
larger write has no readable id in the packet, so write-receipt.md now says that
write may go unanswered and the client's unconfirmed outcome covers it.

Ordering: frame.sequence <= packet.sequence is replaced by sequence_at_or_before,
serial arithmetic modulo 2^32. Deviation from the brief: cultnet-rs'
at_or_before carries a 4096-sequence receive window made for duplicate detection;
a frame's first fragment may lie further back than that, so reusing it would
leave such a sequenced write unrefused and applied. The new test pins that, and a
hand mutant with the window fails it. A wrapped sequence cannot reach this
compare through the session today (it is judged a duplicate), so the unit test
pins the helper, not an end-to-end wrap.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 09:13:18 +00:00
Libby
Rust RUDP server: decide the sequenced-channel refusal per frame
A sequenced packet's arrival can release held ordered frames in the same delivery; refuse only the packet's own frame.
heimdall-low-refuse-sequenced-per-frame.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 09:13:04 +00:00
Libby
Rust RUDP server: pin the refusal of blank schemaId/recordKey on receipt sessions
heimdall-low-rust-keys-untested.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 09:13:04 +00:00

2026-11-08

Libby
write-receipt spec: name the platforms that disagree accurately
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 5m3s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 26s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 22:27:17 +00:00
Libby
write-receipt vectors: U+001C to U+001F and padded names are not blank
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 22:26:28 +00:00
Libby
2026-11-08 22:02:49 +00:00
Libby
write-receipt vectors and tests: blank is Unicode White_Space, every code point checked
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 22:02:10 +00:00
Libby
C# tests: a nil payload names nothing (mutant survivor)
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 6m30s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 36s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 21:57:38 +00:00
Libby
C# database server: refuse a put that names nothing, one unreadable text
IsUnreadableDocument follows the spec's Required fields rule (blank storedAt, empty payload, blank source ids and tags join blank schemaId/recordKey); ForUnreadableMessage is the single owner of the fixed text. Tests replay the blankFields vectors on receipt and legacy connections.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 21:26:49 +00:00
Libby
write-receipt spec: one unreadable text, one blank-field rule; Rust server tests pin both
The unreadable-frame text is 'message_invalid: the message could not be read' (the servers' wording; the Rust wire never carried decoder text, only its local rejection display). A put that names nothing (blank schemaId/recordKey/storedAt, empty payload, blank present source ids or tags) is refused as unreadable on every connection; the vectors' blankFields section lists the cases and the Rust server tests replay them.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 21:26:49 +00:00