Commit graph CultLib/tests
Author SHA1 Message Date
Meta Vens
b3bd8dd5e5 Merge hands/py-typed-leaves: C# leaf vectors (leaf-vectors-cs) and cultcache-py typed leaves that own each slot's C# type name and checks, held to them
leaf-vectors-cs Soul-held at pass 3 (cultlib-gaps:verdict:cut-leaf-vectors-cs.s3); py-typed-leaves Soul-held at pass 2 (cultlib-gaps:verdict:cut-py-typed-leaves.s2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 02:28:58 +02:00
Meta Vens
4282d507cf Caching tests: the wrong-catalog refusal is raised while the store is added, so both steps sit inside the asserted call
Previous commit 122894f5 failed these four cases (AddBackingStore threw outside Assert.CatchAsync).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 02:06:26 +02:00
Meta Vens
122894f5f8 Caching tests: the reference opens a Python-written typed-leaf store and refuses wrong type names
Vectors py-store/*.cc are written only by cultcache-py (CULTCACHE_WRITE_VECTORS=1).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 02:01:48 +02:00
Meta Vens
100088520e cultcache-py test: the any-row comparison tells bool, int and float apart; README points at the kind-and-value ruling
Ruling any-rewrite-binds-kind-and-value: kind-strict, exact value, recursive, numeric width free.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 02:01:47 +02:00
Meta Vens
7f38134155 Caching tests: regenerate leaves-reads.msgpack from the C# reference (11 leaves x 28 tokens, 308 rows) and the README: timestamp rows, any rewrite binds value
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 00:35:06 +02:00
Meta Vens
2bcbe17253 Caching tests: leaves-reads tokens for the timestamp32/64/96 exts and same-shaped non-timestamp exts (vector tests fail here: vectors stale)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 00:34:09 +02:00
Meta Vens
51631f07d5 Caching tests: regenerate leaves-reads.msgpack from the C# reference (11 leaves x 23 tokens, 253 rows) and the README rows
leaf-record.msgpack is unchanged. The any leaf now has a ext refusal (d40100) and the record leaves read a complete second slot.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 00:19:25 +02:00
Meta Vens
08e1a2cd37 Caching tests: drop the timestamp ext token, which the any leaf accepts (vectors not yet regenerated)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 00:18:46 +02:00
Meta Vens
719cf655b6 Caching tests: leaves-reads tokens for ext values and a complete record, and a list-of-records leaf (vectors not yet regenerated; the vector tests fail at this commit)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 00:17:41 +02:00
Meta Vens
85d8d575cf Caching tests: write slot-nil/reads.msgpack from the C# reference with the two four-byte UTF-8 rows (CULTCACHE_WRITE_VECTORS=1 on Yggdrasil)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 00:09:37 +02:00
Meta Vens
c114820c0c Caching and cultcache-ts tests: slot-nil rows for a four-byte UTF-8 character in a string slot and in a byte[] slot
The C# cases and the TS assertions are here; the vector file is written from the reference in the next commit, so the
slot-nil tests of both runtimes fail at this commit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 00:08:23 +02:00
Meta Vens
067d015122 Caching tests: write leaves-reads.msgpack and leaf-record.msgpack from the C# reference (CULTCACHE_WRITE_VECTORS=1 on Yggdrasil)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 23:58:04 +02:00
Meta Vens
9df776d385 Caching tests: the wide-leaf read and leaf-record vector builders and tests, README rows (vectors not yet written; the two new tests fail until the next commit)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 23:57:05 +02:00
Meta Vens
c770db6e77 Merge hands/union-codec-ts: cultcache-ts slot record and union codecs, and one typed owner of document-payload reads and writes (DocumentPayload)
Soul passes cultlib-gaps:verdict:cut-union-codec-ts.s1-s9. Operator rulings ts-payload-opaque-type and ts-opaque-type-kept. Low pin gaps deferred to follow_up ts-codec-pin-gaps.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 22:40:37 +02:00
Meta Vens
d877d26a05 cultcache-ts test: the slot-nil vector pins a non-ASCII str in a bytes slot as UTF-8 (C#-written)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 22:03:21 +02:00
Meta Vens
ce52d9aa60 Caching tests: slot-nil case for a non-ASCII str in a byte[] slot
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 22:01:42 +02:00
Meta Vens
c85edf90bb cultcache-ts slots: a default fills only a missing slot, a nil is null in a reference slot and refused in a value slot, bytes reads a str
Held to tests/vectors/slot-nil/reads.msgpack, written by the C# reference (SlotNilVectorTests): every accepted row
rewrites to the reference's bytes, nil in an int slot is refused. 94a26431c000c0 round-trips byte-identical.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 21:05:09 +02:00
Meta Vens
6d410f9caf slot-nil vectors: the C# writer for what the reference reads and rewrites for a nil or short record in each slot kind
Does not build the vector yet: reads.msgpack is written in the next commit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 21:01:33 +02:00
Meta Vens
5d2a880ffc numeric-leaves vectors: the 2^24+1 reads row and float32-nan.msgpack, written by the C# reference
Regenerated with CULTCACHE_WRITE_VECTORS=1 on Yggdrasil (dotnet 10 image, 16 vector tests green). Completes the previous commit; both build, and the TS suites are checked once at the end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:31:45 +02:00
Meta Vens
1e0c5a9209 batch 4 code: mesh readers decode through the definition's formatter, float32 sNaN refused, slot keys capped at 65535
cultmesh-ts reads document payloads through resolveDocumentFormatter at its five plain-msgpack sites; WireFloat carries a signalling flag and the float32 leaf refuses it; slots() refuses a key above 65535 at definition. The C# vector writer gains the 2^24+1 reads row and float32-nan.msgpack, whose committed files land in the next commit: this commit does not build its tests (union-parity numeric vectors, row count 160 and float32-nan.msgpack are absent).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:18:18 +02:00
Meta Vens
58712e3992 Payload depth tests: the largest fixmap and a container header cut short at the limit
Stryker survivors of the first scoped run: the fixmap boundary code and the truncated
header return. All commits build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:58:50 +02:00
Meta Vens
26ff9d27e9 numeric-leaves vectors gain two float32 rows; float32 integer rounding drops its redundant guard
An odd kept value just past exact pins the tie rule (the Stryker survivor). The excess <= 0 guard was equivalent to the
general path for the only values that reach it, so it is deleted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:45:48 +02:00
Meta Vens
6640b9d358 NumericLeafVectorTests: an odd float32 value just past exact, the case a wrong tie rule rounds up
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:45:04 +02:00
Meta Vens
0789ec8327 Payload depth walk: tests of every header and scalar width at the rule's own seam
Each case is a two-slot document whose chain puts the payload at the limit (accepted)
or one past (refused), so a scalar or container header read at the wrong width flips
one of the two. Also pins the message, truncated payloads and the first-value rule.
All commits build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:45:00 +02:00
Meta Vens
35386acc51 numeric-leaves vectors: reads, writes and a mixed record, written by the C# reference
Regenerated twice on Yggdrasil under CULTCACHE_WRITE_VECTORS=1 and byte-identical. The cultcache-ts test still
imports the deleted hand table until the next commit, so this commit and its parent do not build the TS tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:34:30 +02:00
Meta Vens
abf624ab04 C# reference: one payload nesting bound (256) on read and write, nil arm slots refused, bounds vectors
CultPayloadDepth.Check walks MessagePack headers iteratively and refuses the first
container past CultMessagePackSecurity.MaximumPayloadDepth, read or skipped, called by
SerializeUntyped (on the bytes it produced) and DeserializeUntyped (before decoding).
UntrustedData's 500 is replaced by the same value as a backstop. CultUnionGuard refuses
[k, nil] arms. New vectors in tests/vectors/union-parity, with bounds-outcomes.msgpack
as their data; the gate now runs every Check-calling test body and fingerprints bytes
and write times. All commits build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:33:15 +02:00
Meta Vens
3eb4cb641f NumericLeafVectorTests: a mixed-record vector, the shape a replicated document has
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:32:18 +02:00
Meta Vens
42f746de20 NumericLeafVectorTests: the coverage floor matches the cases (int32 accepts 8)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:30:48 +02:00
Meta Vens
c38974f3c6 C# numeric-leaf vector writer: reads and writes of int, long, float, double slots, gated by CULTCACHE_WRITE_VECTORS
The vector files follow in the next commit; the new tests fail until they are committed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:30:04 +02:00
Meta Vens
e63f93e4a5 Union golden: union-surface.cc regenerated with the pinned store clock
Written by the C# reference with CULTCACHE_WRITE_VECTORS=1; two regenerations on Yggdrasil were byte-identical.
The 12 payload vectors and outcomes.msgpack are unchanged. Builds and passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:59:51 +02:00
Meta Vens
b4edbb1eeb Union golden: the store's clock is an internal seam, the writer pins it, the gate test runs under any switch
CultCache mints storedAt from an internal Clock (default the wall clock); the vector writer pins it, so
union-surface.cc is regenerated in process and byte-compared on every run. The gate test sets the switch
itself and writes only a probe, so it neither skips nor touches a committed vector.

This commit does not pass: union-surface.cc still holds the old wall-clock stored-at; the next commit
regenerates it. Builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:58:54 +02:00
Meta Vens
e5cfb10674 Union parity vectors: committed bytes written by the C# reference, outcomes as data, README
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:28:20 +02:00
Meta Vens
3c75cae4f0 Union parity vectors: the recursive-union fixture, refusal and extra-slot cases, written only under CULTCACHE_WRITE_VECTORS=1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:26:15 +02:00
Meta Vens
a0e0cceaaa Union guard tests: pin the Int32 bounds and full-width encodings of an arm key
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:07:37 +02:00
Meta Vens
3042757701 Union guard: name an out-of-range or non-integer arm key, pin interface unions, name the schema on a variant refusal, changelog the exception type
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 23:48:49 +02:00
Meta Vens
506ec8c540 Union guard: the store refusal is readable from its outermost message; a consumer formatter for the union is wrapped, not replaced
Manual mutants survived: the record key and schema id were only asserted through the
cause chain, and an inner built from StandardResolver alone passed every test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 22:56:53 +02:00
Meta Vens
62a0e9ac98 Union guard tests: pin the composite's resolver order and that a union owns its keys
Stryker survivors on the Compose line and on the inherit argument.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 22:41:04 +02:00
Meta Vens
28d79b190a Union guard tests: forge a directory-store page the way its manifest commits to it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 21:50:53 +02:00
Meta Vens
29b21a0f33 Union guard tests: the store refusal names the record's schema id
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 21:35:37 +02:00
Meta Vens
afaae23c8a Union guard tests: helper names no longer collide with the arm classes
6254da0c does not build the tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 21:34:56 +02:00
Meta Vens
6254da0c88 CultCache: refuse an unknown union arm on read and an unnamed subtype on write
A guard ahead of MessagePack-CSharp's union formatter decides both; the store
decode site names the record and schema.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 21:17:56 +02:00
Meta Vens
e1bdf92321 C#: an unsendable goodbye names the failure by a fixed code
EndUnsendable put the SocketException's message on the wire, the
platform's wording. SendErrorCode names a permanent failure EMSGSIZE,
EINVAL or EAFNOSUPPORT, anything else UNKNOWN, so every runtime's
unsendable goodbye reads "packet could not be sent: CODE" with the same
codes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:04:40 +02:00
Meta Vens
daedfdd658 Merge CultCache R1: typed read failures, no empty-file stores, no echoed values, typed write outcome
Only "nothing at the path" reads as an empty store; a zero-byte file is Undecodable in every
runtime; a dangling link is an I/O error. Errors name keys and schema ids only, never stored
values, and echo a header only in the cultcache.store.v<digits> shape. Single-file writes
report NotReplaced / ReplacedNotDurable / Rejected; an unlock failure after a successful write
no longer replaces the write's result.

Soul passes 1-3; batch 4 closes pass 3. Merged tree 9d9e76d4 verified on Yggdrasil: Rust
(cultcache, cultnet, cultmesh), cultcache-ts 44 including the four-runtime interop test,
cultnet-ts 198, cultcache-py 47, GameCult.Caching.Tests 346.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 21:13:24 +02:00
Meta Vens
ce63ff88dc C#: a handler's fault ends the session without blaming the peer
The schema server's backstop ended every session with "session refused
a packet", including when the fault was the server's own: for example a
handler's response too large to send, or a refusal the handler did not
type. Decoding and handling are now two catches:
- A message that cannot be decoded is the peer's. The session ends with
  the refusal reason.
- A handler fault ends the session with "server could not handle a
  message".
The transport's EndRefusedPeer becomes EndPeerSession(peer, reason). It
reports whether it ended the session, so the log says when a response
that failed after its first fragment had already ended it over the send.
Before, the log reported that it ended a session that was already gone.

The comment said that ending the session matched cultmesh-py. It does
not: Python silently skips a malformed frame. The honest anchor is the
C# TCP schema server, whose ServePeerAsync ends the one peer whose
message fails to decode or handle. The comment now says so.

Pinned, each by a test that kills its mutant:
- a handler fault's goodbye carries the server's reason, not the refusal
  (mutant: the refusal reason);
- the post-fragment-0 path logs that the session had already ended
  (mutant: a constant outcome);
- EndPeerSession says no goodbye to a replaced peer's endpoint (mutant:
  the Ended check dropped);
- a refused peer's frames still queued are never handled (mutant: the
  queue purge dropped).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 20:19:29 +02:00
Meta Vens
b37f898465 C#: a send failure on an already-ended session says no second goodbye
3b9ffac2 claimed that the generation check subsumed the UnsendableReason
once-guard. It did not. A thread that reads the generation only after
the session has ended carries the ended session's own generation, and the
check lets it through. For example, the polling thread answers a Ping on a
session that a caller's send has just ended but that has not yet been
retired. When that Pong fails permanently, the thread says a second
goodbye and overwrites the first failure's reason (Soul pass 4, PR4).
EndUnsendableSession now also returns when the session has already ended.

Two tests:
- The polling thread answers a Ping on a session already ended, and the
  Pong can never be sent. Exactly one goodbye goes out, and the first
  failure's reason stands. The hook admits the Ping after the session
  ended and before the peer is queued for retirement. The test kills the
  mutant that drops the Ended check.
- A failed send's goodbye is sent under the gate. A polling thread
  admitting a new Connect from the endpoint waits on the gate, so the old
  generation's goodbye never follows the new session's Accept. The test
  kills the mutant that sends the goodbye outside the gate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 20:19:19 +02:00
Meta Vens
c996ae7892 Caching: a single-file refusal echoes a header only in its known shape
RequireSingleFileFormat echoed any header string. It now names one only in
the shape cultcache.store.v<digits> and otherwise gives its byte length.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 18:35:20 +02:00
Meta Vens
a44e189e0c C#: a peer's undecodable message ends that peer's session, never the poll
RudpCultNetSchemaServer decoded each schema frame outside its per-message
backstop, so a malformed payload (0xc1) or a well-formed message with an
unknown schemaVersion threw MessagePackSerializationException out of
PollAvailableAsync and PollOnceAsync. The drain aborted: a good peer's
request in the same drain went unserved, a consumer loop that did not
catch died, and the bad frame was already acknowledged while its peer
stayed connected.

Decoding now runs inside the backstop. A peer whose message cannot be
decoded or handled has its session ended: the transport's new
EndRefusedPeer sends the refusal goodbye under the gate, counts the drop
in PacketsDropped, drops that peer's frames still queued, forgets the
peer and raises PeerDisconnected. A session that already ended (replaced
by a new Connect, or ended by a send failure) gets no goodbye, since the
endpoint may belong to a new session. Other peers in the drain are still
served. Ending the session matches cultmesh-py's server, where one
peer's bad message ends that peer; runtime parity is the reason.

The log names the fault's type only and never its message, because the
decoder's message quotes the peer's input (the unknown schemaVersion).
The dispatch-backstop test now asserts that rule instead of the handler
message it used to require.

Tests, each failing on the pre-fix code: a malformed payload and an
unknown schemaVersion each leave the good peer served without Poll
throwing (also through PollOnceAsync); the bad peer's session ends,
counted and told; the log carries the type and not the canary value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 17:23:40 +02:00
Meta Vens
3b9ffac2fe C#: a send failure's goodbye belongs to the generation that sent
Send ended an unsendable session after releasing SessionGate, and the
goodbye was built under the gate but sent outside it. If the polling
thread admitted a new Connect from the same endpoint in that window, the
ended generation's goodbye reached the new client: it saw Data, Accept,
Disconnect and believed itself disconnected while the listener held it
connected.

Every path that finds a permanent send failure now reads the session's
generation under the gate at the send, and EndUnsendableSession builds
and sends the goodbye under the gate only while that generation is
unchanged. The generation check replaces the UnsendableReason once-guard:
a second failure in the same generation finds it already ended.

The test orders the new Connect inside the send, before the fragment
that can never be sent, and asserts the new client hears no Disconnect
and stays connected on both sides. It fails on the pre-fix code
(Data, Accept, Disconnect) and kills the mutant that drops the check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 17:23:30 +02:00
Meta Vens
2d7a3c78eb Caching tests: an empty store file is refused; a missing file or [0x90] is empty
Pins the C# side of the cross-runtime rule the Rust, Python and TS runtimes
now share. C# already refused a zero-byte file (the snapshot reader runs out
of bytes at the array header); this test keeps it that way. Its exception is
still EndOfStreamException, an IOException: that overlap belongs to R3's C#
work.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 17:05:15 +02:00
Meta Vens
2d76b8d1b6 Pin the reset before a refusal's goodbye (cultmesh-ts, cultmesh-py) and C#'s once-guard
The document servers' refusal tests sent an unreliable fragment, whose
sequence the session never records, so dropping the reset before the goodbye
survived. They now refuse a reliable fragment and check the goodbye does not
acknowledge it.

C#: a BeforeSend seam orders a caller's failing send between the polling
thread's ack and its send, so both threads end the same session; the peer
hears one goodbye.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 16:02:27 +02:00