Commit graph

1,369 commits

Author SHA1 Message Date
Meta Vens
384ee30ff6 Say that a conditional variant commit reads the getters a second time
Judging the merge against the file re-runs Project for the records the commit
lands and for re-resolved variants, so "once per landing record" holds only for
the admission. Handing the plan's projections to Judging would not cover the
re-resolved dependents, so the contract now states the second read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 19:37:03 +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
fee55e89c5 Check the CultMath release gate against the type-definition table
scripts/check-cultmath-types.cs reads the assembly with System.Reflection.Metadata
and reports which named types are not public top-level CultMath types. The old
NUL-delimited string search passed an appended string or a member named like the
type, and failed a real type whose name is tail-shared in the string heap.
Prerelease and range versions now get a clear message instead of a raw
System.Version error.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 18:31:16 +02:00
Meta Vens
5fb3fca2ba Normalise a blank name once, where it is read
The held-ancestor path compared the raw empty string, so a blank variant name
and a blank held base name never met the blank rule; NameRead now returns null
for blank on both paths.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 18:14:24 +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
9b5597e89c Gate the CultLib Unity release on the CultMath package it depends on
The package build now fails when the declared org.gamecult.cultmath version is
ahead of the CultMath package, or when that package's CultMath.dll lacks a type
CultMathResolver formats. It also drops the shipped-plugin guard that could not
fire, since the output root is wiped first.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 17:20:17 +02:00
Meta Vens
9b23b33f8c Let Stryker mutate the variant name rule
The is-not pattern binding made every mutant in RefuseVariantNameSharing a
compile error, so Stryker removed the whole method from its run.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 17:11:47 +02:00
Meta Vens
9dcce987fd Update Mesh docs that still named CultVec2 and CultRect
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:57:31 +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
5687d8c355 Make the CultLib Unity package depend on org.gamecult.cultmath
GameCult.Caching.MessagePack now references CultMath, so the Unity package
declares org.gamecult.cultmath in package.json, references CultMath.dll from the
asmdef, and the package build refuses to ship a second CultMath.dll and checks
the asmdef against the shipped plus external assembly lists.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:52:44 +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
60663f952c Record publication rulings Q-P1..Q-P4
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:41:19 +02:00
Meta Vens
2dc7c122f9 Map CultCache publication: order as data via a journal under the cache gate
Imagination rebuilt the writer-thread scheduler Soul pass 3 proposed: it
deadlocks exactly as bcae483 did (deleted in 4562340). The map keeps per-writer
delivery, validates getters before minting, isolates observers, and moves the
shard log onto a gate-held journal. Q-P1..Q-P4 open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:36:18 +02:00
Meta Vens
1e3a337b81 Record C2a Soul hold, the tripwire and duplicate-id rulings, and the C2b precondition
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:35:33 +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
acdf36c81e Merge Studio grouping Cut 2: tree lowering, create in group, drag onto refs
Soul: merge. The drop gate calls the model's one candidate rule; every ref write
ends in CreateRecordRef; node ids injective (69,905-string brute force, 0
collisions). Operator click-through still owed (steps in the Cut 2 report).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:09:38 +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
857e6e8a54 Studio README: grouping, create in group, drag to reference
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 14:10:39 +02:00
Meta Vens
88a5726017 Studio: lower the grouping tree, create in group, drag source
The record list draws GroupRecords as foldouts (fold state keyed by listed
type and node id), each with Create through CreateInGroup; an ungrouped type
lists RecordCandidates flat under the model's notice. Add, Create and
Duplicate reveal the new record's path. Rows start the record drag.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 14:10:39 +02:00
Meta Vens
af370cd29e Studio: record drag payload, ref drop target and the model's ref label
A record row dragged onto a CultRecordRef value sets it when the ref's picker
would offer that record (IsRecordCandidate), refusing in a disabled scope, a
foreign model, or the key already held. The ref popup's None/Missing label
now comes from RecordRefLabel.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 14:10:38 +02:00
Meta Vens
384c7df02b Make group node id escaping injective
Uri.EscapeDataString maps every unpaired surrogate to %EF%BF%BD, so distinct
values shared one node id. An unpaired surrogate now spells %uXXXX.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 14:03:58 +02:00
Meta Vens
7defd82c20 Pin node-id escaping, case-distinct nodes and the flat ungrouped list
Ids that differ only by %2F versus /, keys that differ only by case, and
unpaired surrogates each get a test; the ungrouped list stays flat.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 14:00:47 +02:00
Meta Vens
65311c9ad7 Merge the snoise seam fix (Asura Q-N1 a): upstream kernel r2=0.5, scale 105, permute +10
Soul: no defect; independent port of stegu 22434e04d7 matches (3D and 2D), goldens
confirmed independently, value jump 2.2e-6 over 20k crossings, gradient FD 9.7e-6,
every hand mutant killed. 2D follows upstream by ruling. Release follow-ups: rebuild
the Unity CultMath.dll, CHANGELOG entry, pin the two HLSL copies equal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 13:55:08 +02:00
Meta Vens
c60af61e73 Merge Studio grouping Cut 1: the model owns declared record grouping
Soul: merge. [CultInspectorGroupBy], GroupingOf/GroupRecords/CreateInGroup,
IsRecordCandidate (one candidate predicate), RecordRefLabel; variants group by
resolved value and follow their base. Follow-ups in Cut 2: pin '%' escaping and
case-distinct keys, distinct ids for lone surrogates, fold state keyed by type+id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 13:55:08 +02:00
Meta Vens
4f7d8821af Pin the create-in-group node check against a value that fits another grouping
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 13:29:09 +02:00
Meta Vens
93fe1b9c8e Merge CultMath bounded least squares (locomotion Cut 2)
Closed after three Soul passes: the double iterate and progress stop hold over
~9000 cases against exact enumeration, zero allocation, deterministic; the stall
rule and fScale are now pinned (all six survivors killed). Ships in the next
CultMath release with Asura. Recorded, outside the documented range: 18/6000
gap misses at cond 1e5-3e5 with A scaled 1e-4..1e4 (solver or reference unknown).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 13:22:54 +02:00
Meta Vens
439efd1550 Drop the inert inherit flag from the global check and its derived-type case
[CultGlobal] is not inherited, so the flag changed nothing and no test can tell.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 13:16:11 +02:00
Meta Vens
30e1f3fb95 Cover ungrouped types, null strings, derived globals and id separators
Stryker survivors on the grouping diff: the no-declaration path, the
null-string identity, the inherited [CultGlobal] check and the id separator.
GroupLevel takes text and tie as optional arguments so the scalar kinds
stop passing constant strings that could be swapped without any effect.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 13:15:03 +02:00
Meta Vens
09507901d0 cultmath: BoundedLeastSquares doc states the cost gap is relative to |b|^2
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 13:14:21 +02:00
Meta Vens
c8227c6347 cultmath: BoundedLeastSquares tests drive stalled passes to the stall rule
Batches of small boxed problems whose passes end with the KKT test failing and
the cost unmoved (dependent free columns, releases the factor drops, weak-direction
noise-floor problems). They must report Converged, and land within the documented
gap of an exact active-set enumeration. Pins the stall comparison and the cost
scale in Objective, which no test reached before.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 13:14:21 +02:00
Meta Vens
069ecc369c Note the operator's future cross-store variant direction under ruling 3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 13:10:36 +02:00
x
84c9a79972 Pin string case ordering and node id spelling in the grouping tests
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 12:52:05 +02:00
x
3d07ba0d20 Give the overriding variant its own name in the grouping test
A variant must override its name.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 12:21:28 +02:00
x
0a5f4bf571 CultMath: regenerate snoise golden values for the upstream kernel
Seven values change: four snoise(float3) in HlslSemanticsTests and three snoise(float2)
in MathTests (the 2D (0,0) golden is 0 either way). Regenerated from the code after the
continuity probe passed. The tests no longer claim to match Unity.Mathematics, whose
snoise keeps the old constants.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 12:09:43 +02:00
x
79e9318698 Add model-owned record grouping: declaration, tree, create-in-group, ref labels
[CultInspectorGroupBy(nameof(A), nameof(B))] on a document class names the
members its record list groups by, outermost first. CultInspectorModel owns
the rest: GroupingOf validates the declaration (a refused one gives a flat
list and a notice), GroupRecords partitions RecordCandidates by value
identity with occupied values only, CreateInGroup builds the record a node
holds, RecordRefLabel owns None and Missing <key>. A variant groups by its
resolved Document.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 12:09:25 +02:00
x
641041822d CultMath: noise gradient tests carry only numbers the harness produces
Drops the unreproducible floors and detection-scale claims, and the seam-fluke
consistency filter (the spikes it hid were the snoise seam, now fixed and pinned by the
continuity probe). Tightens the tolerances to at least 5x the harness maximum (ridged
0.5 -> 0.05), corrects the point count in the bit-equality test, and caps the ridged
compounding loop so a mutant fails loudly instead of hanging.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 12:04:08 +02:00
x
8ad0691bdd Declare the label fixture's key on its base member
The registry requires an override to repeat or omit the base declaration's [Key].

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 12:03:28 +02:00
Meta Vens
a6382475e4 Collapse the ref-candidate predicate and read inherited member attributes
RecordCandidates and the new IsRecordCandidate share one rule, so a
picker's candidates and a drop's acceptance cannot disagree. Member
attributes are read with Attribute.GetCustomAttributes(member, true):
PropertyInfo.GetCustomAttributes ignores inherit, so a base abstract
property's inspector attributes never reached the override.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 11:55:41 +02:00