Commit graph CultLib/tests
Author SHA1 Message Date
Meta Vens
79f144d9ec CultNetDatabase.Dispose publishes what a writer logged and had not yet published
The dispose test showed journal-first alone still lost the change: Dispose won the race against the writer's publication and cleared the stash. Dispose now drains the stash through the publisher after the journal is disposed (so nothing is stashed afterwards) and before the subject completes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 06:16:57 +02:00
Meta Vens
557e70fd03 Cut 4 Soul 4c: committed-unlogged wire writes, database serves only what it owns, typed unowned refusal
Q1: HandlePutAsync/HandleDeleteAsync catch a CultNetShardLogException (or an
AggregateException holding one) before the generic catch and answer nothing: the
write committed and was published, so the peer is not told it was refused. It is
logged at warning level. The wire has no committed-with-degraded-log message.
Q2: GetAsync/GetAll/GetByName/GetByIndex, the shard-less snapshot, the selection
and the subscription snapshot serve only rows a shard owns, so read and watch
agree; the CultMesh collections follow through GetAll, and the Mesh untyped
variant fallback checks ownership. The raw cache still holds everything.
Q3: a replica log apply skips a row its shard does not own, as the snapshot path
does, and still records the entry so a chained replica sees no gap.
API: rowFilter is internal (public CreateSelectionResponse and
CreateRawSnapshotResponse signatures restored, internal overloads added);
exception tags on the write methods; Commit's unwrap rule is XML doc; the
unowned refusal answers on the wire with code unowned_schema (schema enum in both
copies, Rust CultNetErrorCode, CultNetErrorMessage.ForUnownedSchema) and put and
delete log it at warning level.
Dispose keeps journal-first; a test now fails if the observer goes first.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 06:14:49 +02:00
Meta Vens
396cccafd4 Soul probes: commit the pass 4c probes (Q1-Q5) as recovered from 9c30f67f
The Finding-category probes fail on this commit; the fixes that follow are their tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 06:09:14 +02:00
Meta Vens
8d204a9473 Merge remote-tracking branch 'origin/main' into hands/pub-cut4 2026-09-30 06:08:26 +02:00
Meta Vens
dac712b09c CultNetDatabaseServer: a selection skips cached rows no shard owns instead of failing
ResolveShard now throws for an unowned schema, so one such cached row would
have failed the whole selection. The server passes a row filter
(CultNetDatabase.Owns) to CreateSelectionResponse, which gains an optional
rowFilter that SelectPage already took, so those rows are not part of what the
database serves and the rest is answered.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 05:29:35 +02:00
Meta Vens
e79882a8ec CultNetDatabase: no shard owns it, no write, on every path; the fallback shard is deleted
ResolveShardInternal throws CultNetUnownedSchemaException instead of falling
back to the first shard. PutAsync, DeleteAsync, PutPredictedAsync,
ApplyPutAsync and ApplyDeleteAsync refuse an unowned schema before the cache is
touched; a remote put reaches the server's generic catch and is answered as an
application rejection like any other refused remote put. ResolveShard throws
(documented), CanWriteAuthoritatively returns false, and a bare cache write no
shard owns is neither logged nor published. The unused string overload of
EnsureClientAuthority is deleted. No GameCult consumer configures shards
outside vendored CultLib copies; the default shard owns everything.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 04:31:03 +02:00
Meta Vens
e0075217b7 Networking test: the outside-the-shard fixture is written to the cache, since the database refuses it
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 04:21:48 +02:00
Meta Vens
9f6b2d4081 CultNetDatabase: a write no shard owns is refused, not cached and never logged
PutAsync and DeleteAsync carry no door, so the journal cannot place an unowned
schema and now skips it; accepting the write anyway was a silent loss of
replication. They resolve their shard strictly and throw
CultNetUnownedSchemaException (an InvalidOperationException naming the schema)
before the cache is touched. Doors keep the fallback shard they were resolved
to. No GameCult consumer configures shards outside vendored CultLib copies:
AetheriaEve's node uses the default PrimaryAll shard, which owns everything.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 04:08:45 +02:00
Meta Vens
f3076264fc Journal tests: a plain put of an unowned schema is unlogged, a door put keeps the fallback shard
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 02:51:14 +02:00
Meta Vens
a6720b620f Merge Geometry references as CultRecordRef<T>
DomainKey, RequestKey and CutKey were plain strings marked [CultReference];
since e420410f (D11) the cache refuses a reference it cannot walk, and
every cache that registered the geometry catalog threw (7 tests red since
2026-09-22). The wire is unchanged. Geometry gains a reference to
GameCult.Caching.MessagePack for the formatter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:49:38 +02:00
Meta Vens
2eb0e8d6a6 Journal fixes: hole floor on restart, one log exception per call, no shape guard, no stray shard-0 logging
F1: InitializeLogSequencesFromStore raises the in-memory floor to the highest
gap above the store's compaction point, so a restart after a double refusal or
an interrupted compaction answers compacted_history instead of a gapped log.
F2: the journal raises one CultNetShardLogException per call carrying every
burned (shard, sequence); the unwrap rule for a cache-aggregated hold is
documented on the exception and on the cache commit.
F3: TakeDoor no longer refuses a door whose instance is the cached one, so
mutate-then-predict publishes Predicted and is not logged.
F6: a door-less change no shard matches is not logged; doors keep the
fallback shard they were resolved to.
Dispose disposes the journal before the observer. The log store doc says a
slow store blocks cache readers. Soul F4 is ignored as an accepted follow-up,
M1 is explicit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 02:48:49 +02:00
Meta Vens
486244b60f Caching: JSON converter and MessagePack formatter for CultPhasor
The Phacelle merge added the public CultMath value type CultPhasor without
its Caching adapters, failing the every-public-type tests. Register it the
way CultCellular is: {"cos","sin"} objects in JSON (which also gives the
dictionary-key form) and a [cos, sin] array in MessagePack. The adapters are
Caching code and stay MIT; only CultPhasor.cs itself is MPL-2.0.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 02:46:29 +02:00
Meta Vens
49582cf43e Soul probes: commit the pass-3 P-tests and the Cut 4 probes as recovered
SoulPub3Tests.cs is from 1ccc4927 (recovered pass-3 P-tests); SoulP4ProbeTests.cs
is from 8ae8b3dc. Committed as Soul wrote them; the Finding-category probes fail
on this commit and are the tests for the fixes that follow.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 02:38:50 +02:00
Meta Vens
fd34d4573e Geometry tests: import System.Linq for the reference walk test
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 02:30:43 +02:00
Meta Vens
0479304d0b Geometry: reference members are CultRecordRef<T>, not [CultReference] strings
e420410f (D11) refuses a reference member whose CLR shape the cache cannot
walk; many:false needs CultRecordRef<T>. CultGeometryBuildRequest.DomainKey,
CultGeometrySelectedCutManifest.RequestKey and CultGeometryChunkArtifact.CutKey
were strings marked [CultReference], so registering the geometry catalog threw
and 7 geometry tests failed on main. All three are record keys of another
document, so the members become CultRecordRef<T> (the attribute is dropped, the
type declares the reference). The msgpack formatter writes a CultRecordRef as
its key string, so the wire bytes and the fingerprint inputs are unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 01:56:03 +02:00
Meta Vens
e79f3ee370 Journal tests: pin the survivors Stryker found in the changed journal code
Restart over a retained log resumes above its highest sequence and reads its
latest from the durable log; put and delete doors log their own wire messages
and change kinds; a reconciled put is logged as an update; a replica's
watermark follows the primary's sequences; an admission racing disposal logs
nothing.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 00:52:02 +02:00
Meta Vens
af7751e263 Journal tests: the nested shard-log apply must finish, and the store-writes-cache probe fires once
The reentrant apply test now asserts the nested call completes without
throwing: a re-recorded sequence used to be swallowed by the subscriber's
handler and hide a non-replacing in-memory log. The store-writes-cache probe
writes once, so a cache that let the journal re-enter it fails the test instead
of recursing until the host crashes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 00:24:40 +02:00
Meta Vens
3fb2613abf Networking tests: order is data, so pin each change's own publication, not its delivery order
The salvaged S1 and in-place re-upsert tests also asserted the delivery order
of the rejected drainer. Under Q-P1 A delivery order across threads and a
nested write's depth-first delivery are not guaranteed; each change is
published once with its own context, and wire peers drop stale changes by
Sequence (Cut 6). Both assertions now say exactly that. The journal tests'
reentrant-write recorder subscribes before the handler that writes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-29 23:52:14 +02:00
Meta Vens
fe7bca0cb5 CultNetDatabase: log on the cache journal and publish from Watch, no queue
Cut 4b-4d of the publication map. The reorder buffer, drainer, prediction gate
and the logging inside the Watch handler are gone. The database registers the
Watch observer, then one cache journal. The journal runs under the gate in
Sequence order: it takes the door, decides the change kind and prediction
bookkeeping, logs (a primary mints, a replica records the primary's entry) and
stashes the change; the Watch observer publishes the stash entry by Sequence.

A primary that cannot log a committed change burns that sequence, raises its
own compaction floor, tries CompactThrough, and throws CultNetShardLogException
(not an InvalidOperationException) after publication. A replica's refused
append reaches the pull loop and the cursor does not advance.

Fixes four defects the map named: the log is appended to disk before memory
(and memory is a SortedList keyed by sequence); the snapshot reads its log
sequence before its documents; a restart resumes above the compaction point;
GetCompactedMutationLogSequence and GetLatestMutationLogSequence honour the
in-memory floor. The snapshot removal door sets Removal.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-29 23:48:50 +02:00
Meta Vens
7d945b002d Merge the salvaged CultNet publication branch (queue removed in the next commit)
Cut 4a: brings the publication tests and the door table from
hands/cultnet-publish-commits at 28248ebe. The reorder buffer, drainer and
prediction gate die in 4b.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-29 23:36:55 +02:00
Meta Vens
3bf1c0cea5 Merge RUDP stray-packet hardening across all four runtimes
A stray, malformed, foreign-id or refused datagram is dropped and counted,
never fatal; a refused reliable frame ends the peer's session instead of
being acked and lost; flush fails once its session ends; one reliable
Accept per session; the TS operation service expires idle sessions and
survives a throwing handler. Four Soul passes; session-generation and
reconnect semantics move to the ack cut.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:05:30 +02:00
Meta Vens
29f8bf575e Tests: a repeated Connect acknowledges what it carries (TS, Python, C#); fix the TS replaced-peer test
The repeated-Connect answer applies its acknowledgement field in every runtime;
no test failed when a runtime stopped doing so. The TS replaced-peer test now
lets client A receive its Accept before A sends.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:35:44 +02:00
Meta Vens
ca18dfac55 GameCult.Networking: an ended session fails its flush; a repeated Connect owes one Accept
FlushReliable throws for writes an ended session forgot. A server-mode
transport and the listener answer a Connect from the peer they already hold
with AnswerRepeatedConnect: the Accept still owed, or an Ack, queueing
nothing. The listener replaced the peer session on every Connect, reusing
sequences and never reporting PeerDisconnected; it now replaces only on a
different connect payload and reports the old peer, as the Rust hub does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 20:41:23 +02:00
Meta Vens
592a2d49d4 Journal registration counts as disposed only once removal succeeds; a throwing hold body surfaces journal failures
AddJournal's Disposable.Create counted a refused dispose (from inside a journal
or another cache's hold) as done, leaving the journal registered forever. A
private registration now flips only after the removal succeeded. Held's catch
path dropped the hold's journal failures; it now throws an AggregateException
with the body's exception first. The store-composition contract states exactly
when the second getter read runs on a conditional commit. Adds the direct test
that a load is journaled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 20:35:50 +02:00
Meta Vens
36acb4295a Reach the empty admission through a commit that removes nothing
Attaching a store with no file never calls Loaded, so it did not exercise the
rule; a commit removing a key the cache does not hold admits nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 20:04:59 +02:00
Meta Vens
281e1b238c Keep the test frame from holding the subscription it checks the cache released
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 20:03:08 +02:00
Meta Vens
5b3885a1e8 Detect an unsubscribed observer by what the cache still holds, and pin the empty admission
A disposed R3 subscription ignores OnNext, so a no-op removal from the cache's
observer array cannot be seen by what a receiver gets; the test now checks the
cache stops holding the subscriber. An admission that changed nothing (a store
attached with no records) is not journaled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 19:47:38 +02:00
Meta Vens
306412e822 GameCult.Networking.Tests: the malformed-length datagram has the 36-byte fixed header and no channel id
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 19:43:55 +02:00
Meta Vens
b579075dd5 GameCult.Networking: a declared length past int.MaxValue is malformed; server mode is claimed only by a Connect; a refusing session ends
CultNetRudpPacketCodec.Decode did checked((int)length), so a datagram declaring
0x80000000 threw OverflowException, which no receive loop catches; the length
is now compared as a long and takes the ordinary malformed-packet drop.
Server mode claimed its endpoint on the first datagram of any type; only a
Connect claims it now. A session that refuses a packet has already recorded
its reliable sequence, so the socket transport and the listener end it: the
session forgets the peer (so the goodbye does not acknowledge the refused
frame), the peer gets a Disconnect, the listener drops the peer and raises
PeerDisconnected, and a server-mode transport forgets its endpoint.
CultNetRudpSession gains ResetPeerState, and the session and the listener
reject an InitialSequence of uint.MaxValue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 19:41:56 +02:00
Meta Vens
44ad5e8948 Journal admissions under the cache gate, in Sequence order
CultCache.AddJournal registers an ordered admission journal. It is called under
the gate right after Apply, once per admission that changed something, with the
admission's changes (dependents included) in Sequence order, before any
observer. A journal that throws joins the hold's failures: the admission stands,
the other journals run, the change is published and the writer hears of it
afterwards. Any hold entered while a journal runs throws. A hold now carries its
own changes and failures. Order stays data; no delivery thread or scheduler is
added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 19:40:02 +02:00
Meta Vens
be91ea837a Pin that a failed hold publishes what it minted and an unsubscribed observer stops
A hold whose body throws after it admitted changes still publishes them, and
Held now assigns its result up front so it compiles under Stryker Safe Mode
(CS0165 had dropped every mutant in it). Disposing a Watch subscription removes
the observer from the cache.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 19:36:41 +02:00
Meta Vens
2a1b8a8cda Merge CultCache publication Cuts 1-2: project before mint, isolated observers
Soul verdict: merge. Before Cut 4 relies on sequence density: pin the
publish-on-throw guard in Held and observer removal on unsubscribe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 19:30:04 +02:00
Meta Vens
69bd45ff14 Merge canonical CultMath serialization and the Geometry vector collapse (P4)
Every public CultMath value type serializes: MessagePack in the default resolver
chain (byte-identical to Aetheria's and StreamPixels' copies across 653 values
and all 115 float fields of the real Aetheria.cc) and System.Text.Json converters
(STJ-parity number handling, math types as dictionary keys). CultVec2/3 and
CultRect are gone with bytes unchanged. The cultlib Unity package depends on
cultmath; the release gate refuses until CultMath 0.3.0 carries every type.
Three Soul passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 18:34:09 +02:00
Meta Vens
4e5327c61c Bring the CultMath JSON converters to System.Text.Json parity and remove their allocations
Named literals now follow AllowReadingFromString and WriteAsString as
System.Text.Json's float does; quoted numbers refuse whitespace;
UnmappedMemberHandling.Disallow and AllowDuplicateProperties=false are honoured
and a repeated property replaces the whole value; dictionary keys read only the
canonical spelling. Components live in stack spans, property names are
pre-encoded, and there is no per-property closure, so a float3 read allocates
nothing (424 bytes before). Tests pin unknown nested values, de-DE and sv-SE
style cultures, and a distinct negative-zero key.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 18:31:16 +02:00
Meta Vens
b8dbcfe40c GameCult.Networking: RUDP socket transports drop and count strays
A malformed frame, a foreign connection id or a packet the session refuses
threw out of TryReceiveOnce. They are now counted in Stats.PacketsDropped and
the read reports progress. The client-side transport checks the connection
id before it claims the peer endpoint; the server listener drops refused
packets instead of throwing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 17:51:32 +02:00
Meta Vens
0a543c9fb2 Kill the Stryker survivors in the projection and observer cuts
Delete the dead removed-ancestor branch and the duplicated name-read in the
variant name rule (resolution already refuses a missing or removed base and a
variant shares its base type). Add tests for the index rule counting a record
the same commit removes, blank names not colliding, and Dispose rethrowing
escaped completions after every observer completed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 17:46:36 +02:00
Meta Vens
26a4f4240b Pin that a zero or missing Random state decodes to the generator's default seed
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 17:29:02 +02:00
Meta Vens
817c2627b8 Rebuild the CultMath JSON converters on a streaming reader with STJ number semantics
One Scalar plus Node description per type now drives reading, writing and the
dictionary-key spelling, replacing the per-value JsonDocument parse. NaN and the
infinities follow JsonNumberHandling (named literals or JsonException), floats
beyond float.MaxValue are refused instead of becoming infinity, out-of-range
components throw JsonException instead of FormatException, property matching
honours PropertyNameCaseInsensitive, and every type works as a dictionary key
spelled as comma-joined components.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 17:29:02 +02:00
Meta Vens
20c30224fd Add canonical System.Text.Json converters for every CultMath value type
CultMathJson is the JSON twin of CultMathResolver: vectors, quaternion and
Color32 are objects keyed by field name, matrices are arrays of row objects,
rect is {min,max}. Consumers add them with AddCultMathConverters(); CultLib owns
no JSON options. CultCircle and CultSphere serialize and deserialize through
them, with [JsonConstructor] so the struct constructor is used. The Caching
README documents each MessagePack and JSON shape in one table.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:57:31 +02:00
Meta Vens
77602d5c0e Pin every CultMath MessagePack shape and decode a missing Color32 alpha as opaque
Golden bytes now cover double2, double3, int3, int4, bool3, bool4, quaternion,
Color32, Random, float3x3 and CultCellular. A missing Color32 alpha decodes as
255, the constructor default. A test proves a consumer resolver registered for
the assembly wins over CultMathResolver. The redundant nil check is deleted;
ReadArrayHeader already refuses nil.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:57:31 +02:00
Meta Vens
41b964c6f1 Narrow the escaped-observer probe to what this base can show
A database write is published after its cache write returns, so a write whose
observer threw never reaches the database observers on this base. Keep the
probe to the exception reaching the writer and later changes still publishing
and logging; the ordering question belongs to the database cut.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:57:04 +02:00
Meta Vens
b8ceab84ac Drive the escaped-observer probe through a database write
A direct cache write is not a database change on this base, so the database
observer could not show it. PutAsync is, and the observer after the thrower must
see it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:54:40 +02:00
Meta Vens
ecee41e8ff CultCache: own the observer list and isolate every observer
The cache no longer fans changes out through an R3 Subject. It keeps a
copy-on-write observer array and Publish catches per observer: every observer
receives every change, an exception that escapes (a fail-fast R3 handler) joins
the OnUpdate failures rethrown to the writer after delivery, and the observer
stays subscribed. Dispose completes observers, and a disposed cache completes
new ones at once. Deletes the false "OnNext does not throw" comment.

The composition contract now states the observer policy and that a throwing
name or index getter refuses a change set, loads included.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:51:33 +02:00
Meta Vens
6b0cf66f0e Count serializer reads apart in the once-per-landed-record projection test
Resolving a variant serializes its base, and the serializer reads the same
getters; the test measured them together and expected too few.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:50:29 +02:00
Meta Vens
7362257f08 CultCache: read names and indexes once before minting; a throwing getter refuses the whole change set
Resolve now ends in Project, the only place an admission runs a [CultName] or
[CultIndex] getter on a landing record. It runs before land and before any
Sequence is minted, so a throwing getter refuses the admission (loads
included) with nothing written, minted or left in memory. The variant name and
index rules and the indexer read the projection; Apply runs no user code.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:48:19 +02:00
Meta Vens
20ac3b0b6c Collapse CultVec2, CultVec3 and CultRect into CultMath float2, float3 and rect
GameCult.Geometry no longer carries vector or rectangle values. CultCircle and
CultSphere hold float2/float3, the isosurface and surface-nets extractors take
float3 origin, and the per-call conversion to float3 is gone. Their MessagePack
bytes are unchanged (pinned against the pre-collapse encodings), now produced
by CultMathResolver through the default CultCache options.

This is a breaking change to the GameCult.Geometry public API.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:18:09 +02:00
Meta Vens
14621b3893 Reference CultMath from Caching.MessagePack and scope the span helpers
The first commit's resolver needs the CultMath project reference and scoped
span parameters to compile; the golden test file also had two literal slips.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:15:29 +02:00
Meta Vens
139deb0e28 Add the canonical MessagePack encoding for every public CultMath value type
CultMathResolver formats float2/3/4, double2/3, int2/3/4, bool2/3/4,
quaternion, Color32, Random, float2x2, float3x3, rect and CultCellular as
component arrays, and sits in the default CultCache resolver chain so no
consumer registers anything. It lives in GameCult.Caching.MessagePack, which
already owns that chain; CultMath core stays dependency-free.

Vector, rect and Aetheria-formatter byte shapes are pinned by golden tests, a
reflection test fails when a public CultMath value type has no formatter, and
decode skips extra elements and refuses nil.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:13:22 +02:00
Meta Vens
b9cca38dbf Cover valid surrogate pairs and a second unpaired surrogate in node ids
Stryker on the escaping showed the pair-skip branch uncovered and the run
offset unpinned; the kinds now include a valid pair, a replacement character
before a lone low surrogate, a reversed pair, and two unpaired surrogates.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 15:49:51 +02:00
Meta Vens
28248ebede Adopt Soul pass 2 probes and pin log-before-publish and in-place re-upsert
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 14:06:05 +02:00